Actualización

This commit is contained in:
Xes
2025-04-10 12:24:57 +02:00
parent 8969cc929d
commit 45420b6f0d
39760 changed files with 4303286 additions and 0 deletions

View File

@@ -0,0 +1,322 @@
FOSUserBundle Invitation
========================
Require an invitation to create a new user is a pattern mostly used for
early stage of a project. User enter their invitation code in order to
register.
Invitation model
----------------
First we need to add the invitation entity. An invitation is represented
by a unique code/identifier generated in the constructor::
<?php
// src/AppBundle/Entity/Invitation.php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/** @ORM\Entity */
class Invitation
{
/** @ORM\Id @ORM\Column(type="string", length=6) */
protected $code;
/** @ORM\Column(type="string", length=256) */
protected $email;
/**
* When sending invitation be sure to set this value to `true`
*
* It can prevent invitations from being sent twice
*
* @ORM\Column(type="boolean")
*/
protected $sent = false;
public function __construct()
{
// generate identifier only once, here a 6 characters length code
$this->code = substr(md5(uniqid(rand(), true)), 0, 6);
}
public function getCode()
{
return $this->code;
}
public function getEmail()
{
return $this->email;
}
public function setEmail($email)
{
$this->email = $email;
}
public function isSent()
{
return $this->sent;
}
public function send()
{
$this->sent = true;
}
}
Next we map our ``Invitation`` entity to our ``User`` with a one-to-one association::
<?php
// src/AppBundel/Entity/User.php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/** @ORM\Entity */
class User extends \FOS\UserBundle\Model\User
{
/** @ORM\Id @ORM\Column(type="integer") @ORM\GeneratedValue(strategy="AUTO") */
protected $id;
/**
* @ORM\OneToOne(targetEntity="Invitation")
* @ORM\JoinColumn(referencedColumnName="code")
* @Assert\NotNull(message="Your invitation is wrong", groups={"Registration"})
*/
protected $invitation;
public function setInvitation(Invitation $invitation)
{
$this->invitation = $invitation;
}
public function getInvitation()
{
return $this->invitation;
}
}
Add invitation to RegistrationFormType
--------------------------------------
Override the default registration form with your own::
<?php
// src/AppBundle/Form/RegistrationFormType.php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
class RegistrationFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('invitation', 'AppBundle\Form\InvitationFormType');
}
public function getParent()
{
return 'FOS\UserBundle\Form\Type\RegistrationFormType';
}
public function getBlockPrefix()
{
return 'app_user_registration';
}
// Not necessary on Symfony 3+
public function getName()
{
return 'app_user_registration';
}
}
Create the invitation field::
<?php
// src/AppBundle/Form/InvitationFormType.php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Doctrine\ORM\EntityRepository;
use AppBundle\Form\DataTransformer\InvitationToCodeTransformer;
class InvitationFormType extends AbstractType
{
private $invitationTransformer;
public function __construct(InvitationToCodeTransformer $invitationTransformer)
{
$this->invitationTransformer = $invitationTransformer;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addModelTransformer($this->invitationTransformer);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'class' => 'AppBundle\Entity\Invitation',
'required' => true,
));
}
public function getParent()
{
return 'Symfony\Component\Form\Extension\Core\Type\TextType';
}
public function getBlockPrefix()
{
return 'app_invitation_type';
}
// Not necessary on Symfony 3+
public function getName()
{
return 'app_invitation_type';
}
}
Create the custom data transformer::
<?php
// src/AppBundle/Form/DataTransformer/InvitationToCodeTransformer.php
namespace AppBundle\Form\DataTransformer;
use AppBundle\Entity\Invitation;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
/**
* Transforms an Invitation to an invitation code.
*/
class InvitationToCodeTransformer implements DataTransformerInterface
{
private $entityManager;
public function __construct(EntityManager $entityManager)
{
$this->entityManager = $entityManager;
}
public function transform($value)
{
if (null === $value) {
return null;
}
if (!$value instanceof Invitation) {
throw new UnexpectedTypeException($value, 'AppBundle\Entity\Invitation');
}
return $value->getCode();
}
public function reverseTransform($value)
{
if (null === $value || '' === $value) {
return null;
}
if (!is_string($value)) {
throw new UnexpectedTypeException($value, 'string');
}
$dql = <<<DQL
SELECT i
FROM AppBundle:Invitation i
WHERE i.code = :code
AND NOT EXISTS(SELECT 1 FROM AppBundle:User u WHERE u.invitation = i)
DQL;
return $this->entityManager
->createQuery($dql)
->setParameter('code', $value)
->setMaxResults(1)
->getOneOrNullResult();
}
}
Register your custom form type in the container:
.. configuration-block::
.. code-block:: yaml
# app/config/services.yml
services:
app.form.registration:
class: AppBundle\Form\RegistrationFormType
tags:
- { name: "form.type", alias: "app_user_registration" }
app.form.invitation:
class: AppBundle\Form\InvitationFormType
arguments: ['@app.form.data_transformer.invitation']
tags:
- { name: "form.type", alias: "app_invitation_type" }
app.form.data_transformer.invitation:
class: AppBundle\Form\DataTransformer\InvitationToCodeTransformer
arguments: ['@doctrine.orm.entity_manager']
public: false
.. code-block:: xml
<!-- app/config/services.xml -->
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="app.form.registration" class="AppBundle\Form\RegistrationFormType">
<tag name="form.type" alias="app_user_registration" />
</service>
<service id="app.form.invitation" class="AppBundle\Form\InvitationFormType">
<argument type="service" id="app.form.data_transformer.invitation"/>
<tag name="form.type" alias="app_invitation_type" />
</service>
<service id="app.form.data_transformer.invitation"
class="AppBundle\Form\DataTransformer\InvitationToCodeTransformer"
public="false
>
<argument type="service" id="doctrine.orm.entity_manager"/>
</service>
</services>
</container>
Next overwrite the default ``RegistrationFormType`` with the one just created :
.. code-block:: yaml
# app/config/config.yml
fos_user:
registration:
form:
type: AppBundle\Form\RegistrationFormType
You are done, go to your registration form to see the result.

View File

@@ -0,0 +1,47 @@
FOSUserBundle Canonicalization
==============================
FOSUserBundle stores canonicalized versions of the username and the email
which are used when querying and checking for uniqueness.
The default implementation simply makes them case-insensitive to avoid having
users whose username only differs because of the case. It uses :phpfunction:`mb_convert_case`
to achieve this result.
.. caution::
If you do not have the mbstring extension installed you will need to
define your own canonicalizer.
Replacing the canonicalizers
----------------------------
If you want to change the way the canonical fields are populated, simply
create a class implementing ``FOS\UserBundle\Util\CanonicalizerInterface``
and register it as a service:
.. code-block:: yaml
# app/config/services.yml
services:
app.my_canonicalizer:
class: AppBundle\Util\CustomCanonicalizer
public: false
You can now configure FOSUserBundle to use your own implementation:
.. code-block:: yaml
# app/config/config.yml
fos_user:
# ...
service:
email_canonicalizer: app.my_canonicalizer
username_canonicalizer: app.my_canonicalizer
You can of course use different services for each field if you don't want
to use the same logic.
.. note::
The default implementation has the id ``fos_user.util.canonicalizer.default``.

View File

@@ -0,0 +1,168 @@
FOSUserBundle Command Line Tools
================================
The FOSUserBundle provides a number of command line utilities to help manage your
application's users. Commands are available for the following tasks:
1. Create a User
2. Activate a User
3. Deactivate a User
4. Promote a User
5. Demote a User
6. Change a User's Password
.. note::
You must have correctly installed and configured the FOSUserBundle before
using these commands.
.. note::
This documentation references the console as ``bin/console``, which is
the Symfony 3 location. If you use Symfony 2.x, use ``app/console`` instead.
Create a User
-------------
You can use the ``fos:user:create`` command to create a new user for your application.
The command takes three arguments, the ``username``, ``email``, and ``password`` for
the user you are creating.
For example if you wanted to create a user with username ``testuser``, with email
``test@example.com`` and password ``p@ssword``, you would run the command as follows.
.. code-block:: bash
$ php bin/console fos:user:create testuser test@example.com p@ssword
If any of the required arguments are not passed to the command, an interactive prompt
will ask you to enter them. For example, if you ran the command as follows, then
you would be prompted to enter the ``email`` and ``password`` for the user
you want to create.
.. code-block:: bash
$ php bin/console fos:user:create testuser
There are two options that you can pass to the command as well. They are
``--super-admin`` and ``--inactive``.
Specifying the ``--super-admin`` option will flag the user as a super admin when
the user is created. A super admin has access to any part of your application.
An example is provided below:
.. code-block:: bash
$ php bin/console fos:user:create adminuser --super-admin
If you specify the ``--inactive`` option, then the user that you create will no be
able to log in until he is activated.
.. code-block:: bash
$ php bin/console fos:user:create testuser --inactive
Activate a User
---------------
The ``fos:user:activate`` command activates an inactive user. The only argument
that the command requires is the ``username`` of the user who should be activated.
If no ``username`` is specified then an interactive prompt will ask you
to enter one. An example of using this command is listed below.
.. code-block:: bash
$ php bin/console fos:user:activate testuser
Deactivate a User
-----------------
The ``fos:user:deactivate`` command deactivates a user. Just like the activate
command, the only required argument is the ``username`` of the user who should be
activated. If no ``username`` is specified then an interactive prompt will ask you
to enter one. Below is an example of using this command.
.. code-block:: bash
$ php bin/console fos:user:deactivate testuser
Promote a User
--------------
The ``fos:user:promote`` command enables you to add a role to a user or make the
user a super administrator.
If you would like to add a role to a user you simply pass the ``username`` of the
user as the first argument to the command and the ``role`` to add to the user as
the second.
.. code-block:: bash
$ php bin/console fos:user:promote testuser ROLE_ADMIN
You can promote a user to a super administrator by passing the ``--super`` option
after specifying the ``username``.
.. code-block:: bash
$ php bin/console fos:user:promote testuser --super
If any of the arguments to the command are not specified then an interactive
prompt will ask you to enter them.
.. note::
You may not specify the ``role`` argument and the ``--super`` option simultaneously.
.. caution::
Changes will not be applied until the user logs out and back in again.
Demote a User
-------------
The ``fos:user:demote`` command is similar to the promote command except that
instead of adding a role to the user it removes it. You can also revoke a user's
super administrator status with this command.
If you would like to remove a role from a user you simply pass the ``username`` of
the user as the first argument to the command and the ``role`` to remove as the
second.
.. code-block:: bash
$ php bin/console fos:user:demote testuser ROLE_ADMIN
To revoke the super administrator status of a user, simply pass the ``username`` as
an argument to the command as well as the ``--super`` option.
.. code-block:: bash
$ php bin/console fos:user:demote testuser --super
If any of the arguments to the command are not specified then an interactive
prompt will ask you to enter them.
.. note::
You may not specify the ``role`` argument and the ``--super`` option simultaneously.
.. caution::
Changes will not be applied until the user logs out and back in again. This has
implications for the way in which you configure sessions in your application since
you want to ensure that users are demoted as quickly as possible.
Change a User's Password
------------------------
The ``fos:user:change-password`` command provides an easy way to change a user's
password. The command takes two arguments, the ``username`` of the user whose
password you would like to change and the new ``password``.
.. code-block:: bash
$ php bin/console fos:user:change-password testuser newp@ssword
If you do not specify the ``password`` argument then an interactive prompt will
ask you to enter one.

View File

@@ -0,0 +1,65 @@
FOSUserBundle Configuration Reference
=====================================
All available configuration options are listed below with their default values.
.. code-block:: yaml
fos_user:
db_driver: ~ # Required
firewall_name: ~ # Required
user_class: ~ # Required
use_listener: true
use_flash_notifications: true
use_authentication_listener: true
use_username_form_type: true
model_manager_name: null # change it to the name of your entity/document manager if you don't want to use the default one.
from_email:
address: webmaster@example.com
sender_name: webmaster
profile:
form:
type: FOS\UserBundle\Form\Type\ProfileFormType
name: fos_user_profile_form
validation_groups: [Profile, Default]openssl_get_cipher_methods will be used. See http://php.net/manual/function.openssl-get-cipher-methods.php
change_password:
form:
type: FOS\UserBundle\Form\Type\ChangePasswordFormType
name: fos_user_change_password_form
validation_groups: [ChangePassword, Default]
registration:
confirmation:
from_email: # Use this node only if you don't want the global email address for the confirmation email
address: ...
sender_name: ...
enabled: false # change to true for required email confirmation
template: '@FOSUser/Registration/email.txt.twig'
form:
type: FOS\UserBundle\Form\Type\RegistrationFormType
name: fos_user_registration_form
validation_groups: [Registration, Default]
resetting:
retry_ttl: 7200 # Value in seconds, logic will use as hours
token_ttl: 86400
email:
from_email: # Use this node only if you don't want the global email address for the resetting email
address: ...
sender_name: ...
template: '@FOSUser/Resetting/email.txt.twig'
form:
type: FOS\UserBundle\Form\Type\ResettingFormType
name: fos_user_resetting_form
validation_groups: [ResetPassword, Default]
service:
mailer: fos_user.mailer.default
email_canonicalizer: fos_user.util.canonicalizer.default
username_canonicalizer: fos_user.util.canonicalizer.default
token_generator: fos_user.util.token_generator.default
user_manager: fos_user.user_manager.default
group:
group_class: ~ # Required when using groups
group_manager: fos_user.group_manager.default
form:
type: FOS\UserBundle\Form\Type\GroupFormType
name: fos_user_group_form
validation_groups: [Registration, Default]

View File

@@ -0,0 +1,104 @@
Hooking into the controllers
============================
The controllers packaged with the FOSUserBundle provide a lot of
functionality that is sufficient for general use cases. But, you might find
that you need to extend that functionality and add some logic that suits the
specific needs of your application.
For this purpose, the controllers are dispatching events in many places in
their logic. All events can be found in the constants of the
``FOS\UserBundle\FOSUserEvents`` class.
All controllers follow the same convention: they dispatch a ``SUCCESS`` event
when the form is valid before saving the user, and a ``COMPLETED`` event when
it is done. Thus, all ``SUCCESS`` events allow you to set a response if you
don't want the default redirection. And all ``COMPLETED`` events give you access
to the response before it is returned.
Controllers with a form also dispatch an ``INITIALIZE`` event after the entity is
fetched, but before the form is created.
For instance, this listener will change the redirection after the password
resetting to go to the homepage instead of the profile::
// src/Acme/UserBundle/EventListener/PasswordResettingListener.php
namespace Acme\UserBundle\EventListener;
use FOS\UserBundle\FOSUserEvents;
use FOS\UserBundle\Event\FormEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
/**
* Listener responsible to change the redirection at the end of the password resetting
*/
class PasswordResettingListener implements EventSubscriberInterface
{
private $router;
public function __construct(UrlGeneratorInterface $router)
{
$this->router = $router;
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents()
{
return array(
FOSUserEvents::RESETTING_RESET_SUCCESS => 'onPasswordResettingSuccess',
);
}
public function onPasswordResettingSuccess(FormEvent $event)
{
$url = $this->router->generate('homepage');
$event->setResponse(new RedirectResponse($url));
}
}
You can then register this listener:
.. configuration-block::
.. code-block:: yaml
# src/Acme/UserBundle/Resources/config/services.yml
services:
acme_user.password_resetting:
class: Acme\UserBundle\EventListener\PasswordResettingListener
arguments: ['@router']
tags:
- { name: kernel.event_subscriber }
.. code-block:: xml
<!-- src/Acme/UserBundle/Resources/config/services.xml -->
<service id="acme_user.password_resetting" class="Acme\UserBundle\EventListener\PasswordResettingListener">
<tag name="kernel.event_subscriber"/>
<argument type="service" id="router"/>
</service>
Registration success listener with enabled confirmation at the same time
------------------------------------------------------------------------
When you have registration confirmation and you want to hook up to
``FOSUserEvents::REGISTRATION_SUCCESS`` event you will have to prioritize this listener to be called
before ``FOS\UserBundle\EventListener\EmailConfirmationListener::onRegistrationSuccess``::
public static function getSubscribedEvents()
{
return [
FOSUserEvents::REGISTRATION_SUCCESS => [
['onRegistrationSuccess', -10],
],
];
}
If you don't do it, ``EmailConfirmationListener`` will be called earlier and you will be redirected to
``fos_user_registration_check_email`` route.

View File

@@ -0,0 +1,54 @@
Using a custom storage layer
============================
FOSUserBundle has been designed to allow you to easily change the storage
layer used by your application and keep all of the functionality
provided by the bundle.
Implementing a new storage layer requires providing two classes: the user
implementation and the corresponding user manager (you will of course need
two other classes if you want to use the groups).
The user implementation must implement ``FOS\UserBundle\Model\UserInterface``
and the user manager must implement ``FOS\UserBundle\Model\UserManagerInterface``.
The ``FOS\UserBundle\Model`` namespace provides base classes to make it easier to
implement these interfaces.
.. note::
You need to take care to always call ``updateCanonicalFields`` and ``updatePassword``
before saving a user. This is done when calling ``updateUser`` so you will
be safe if you always use the user manager to save the users.
If your storage layer gives you a hook in its saving process, you can use
it to make your implementation more flexible (this is done for Doctrine
using listeners for instance)
Configuring FOSUserBundle to use your implementation
----------------------------------------------------
To use your own implementation, create a service for your user manager. The
following example will assume that its id is ``app.custom_user_manager``.
.. code-block:: yaml
# app/config/config.yml
fos_user:
db_driver: custom # custom means that none of the built-in implementation is used
user_class: AppBundle\Model\CustomUser
service:
user_manager: app.custom_user_manager
firewall_name: main
.. note::
Your own service can be a private one. FOSUserBundle will create an alias
to make it available through ``fos_user.user_manager``.
.. caution::
The validation of the uniqueness of the username and email fields is done
using the constraints provided by DoctrineBundle. You will
need to take care of this validation when using a custom storage layer,
using a `custom constraint`_
.. _custom constraint: https://symfony.com/doc/current/cookbook/validation/custom_constraint.html

View File

@@ -0,0 +1,46 @@
More about Doctrine implementations
===================================
FOSUserBundle was first written for Doctrine-based storage layers. This chapter
describes some things specific to these implementations.
Using a different object manager than the default one
-----------------------------------------------------
Using the default configuration , FOSUserBundle will use the default doctrine
object manager. If you are using multiple ones and want to handle your users
with a non-default one, you can change the object manager used in the configuration
by giving its name to FOSUserBundle.
.. code-block:: yaml
# app/config/config.yml
fos_user:
db_driver: orm
model_manager_name: non_default # the name of your entity manager
.. note::
Using the default object manager is done by setting the configuration
option to ``null`` which is the default value.
Replacing the mapping of the bundle
-----------------------------------
None of the Doctrine projects currently allow overwriting part of the mapping
of a mapped superclass in the child entity.
If you need to change the mapping (for instance to adapt the field names
to a legacy database), one solution could be to write the whole mapping again
without inheriting the mapping from the mapped superclass. In such case,
your entity should extend directly from ``FOS\UserBundle\Model\User`` (and
``FOS\UserBundle\Model\Group`` for the group). Another solution can be through
`doctrine attribute and relations overrides`_.
.. caution::
It is highly recommended to map all fields used by the bundle (see the
mapping files of the bundle in ``Resources/config/doctrine/``). Omitting
them can lead to unexpected behaviors and should be done carefully.
.. _doctrine attribute and relations overrides: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/inheritance-mapping.html#overrides

View File

@@ -0,0 +1,226 @@
FOSUserBundle Emails
====================
The FOSUserBundle has built-in support for sending emails in two different
instances.
Registration Confirmation
-------------------------
The first is when a new user registers and the bundle is configured
to require email confirmation before the user registration is complete.
The email that is sent to the new user contains a link that, when visited,
will verify the registration and enable the user account.
Requiring email confirmation for a new account is turned off by default.
To enable it, update your configuration as follows:
.. code-block:: yaml
# app/config/config.yml
fos_user:
# ...
registration:
confirmation:
enabled: true
Password Reset
--------------
An email is also sent when a user has requested a password reset. The
FOSUserBundle provides password reset functionality in a two-step process.
First the user must request a password reset. After the request has been
made, an email is sent containing a link to visit. Upon visiting the link,
the user will be identified by the token contained in the url. When the user
visits the link and the token is confirmed, the user will be presented with
a form to enter in a new password.
Default Mailer Implementations
------------------------------
The bundle comes with three mailer implementations. They are listed below
by service id:
- ``fos_user.mailer.default`` is the default implementation, and uses Swiftmailer to send emails.
- ``fos_user.mailer.twig_swift`` uses Swiftmailer to send emails and Twig blocks to render the message.
- ``fos_user.mailer.noop`` is a mailer implementation which performs no operation, so no emails are sent.
.. note::
The ``fos_user.mailer.noop`` mailer service should be used in the case
where you do not want the bundle to send emails and you do not want to
include the SwiftmailerBundle in your app. If you leave the default implementation
configured as the mailer and do not have the SwiftmailerBundle registered,
you will receive an exception because of a missing dependency.
Configuring the Sender Email Address
------------------------------------
The FOSUserBundle default mailer allows you to configure the sender email address
of the emails sent out by the bundle. You can configure the address globally or on
a per email basis.
To configure the sender email address for all emails sent out by the bundle, simply
update your ``fos_user`` config as follows:
.. code-block:: yaml
# app/config/config.yml
fos_user:
#...
from_email:
address: noreply@example.com
sender_name: Demo App
The bundle also provides the flexibility of allowing you to configure the sender
email address for the emails individually.
To configure the sender email address for the user registration confirmation
email update your ``fos_user`` config as follows:
.. code-block:: yaml
# app/config/config.yml
fos_user:
#...
registration:
confirmation:
from_email:
address: registration@example.com
sender_name: Demo Registration
You can similarly update the ``fos_user`` config to change the sender email address for
the password reset request email:
.. code-block:: yaml
# app/config/config.yml
fos_user:
#...
resetting:
email:
from_email:
address: resetting@example.com
sender_name: Demo Resetting
Sending HTML mails
------------------
The default mailer only supports sending plain text messages. If you want
to send multipart messages, the easiest solution is to use the TwigSwiftMailer
implementation instead. It expects your twig template to define 3 blocks:
- ``subject`` containing the email subject
- ``body_text`` rendering the plain text version of the message
- ``body_html`` rendering the html mail
Here is how you can use it, you can use either of the two methods
of referencing the email template below.
.. code-block:: yaml
# app/config/config.yml
fos_user:
# ...
service:
mailer: fos_user.mailer.twig_swift
resetting:
email:
template: email/password_resetting.email.twig
registration:
confirmation:
template: '@FOSUser/Registration/email.txt.twig'
.. code-block:: html+jinja
{# app/Resources/views/email/password_resetting.email.twig #}
{% block subject %}Resetting your password{% endblock %}
{% block body_text %}
{% autoescape false %}
Hello {{ user.username }} !
You can reset your password by accessing {{ confirmationUrl }}
Greetings,
the App team
{% endautoescape %}
{% endblock %}
{% block body_html %}
{#
You can of course render the html directly here.
Including a template as done here allows keeping things DRY by using
the template inheritance in it
#}
{% include 'email/password_resetting.html.twig' %}
{% endblock %}
.. note::
The HTML part is set in the message only when the ``body_html`` block is
not empty.
You can view the default email templates at
`@FOSUser/Registration/email.txt.twig` and
`@FOSUser/Resetting/email.txt.twig`
Using A Custom Mailer
---------------------
The default mailer service used by FOSUserBundle relies on the Swiftmailer
library to send mail. If you would like to use a different library to send
emails, want to send HTML emails or simply change the content of the email you
may do so by defining your own service.
First you must create a new class which implements ``FOS\UserBundle\Mailer\MailerInterface``
which is listed below.
.. code-block:: php
<?php
namespace FOS\UserBundle\Mailer;
use FOS\UserBundle\Model\UserInterface;
/**
* @author Thibault Duplessis <thibault.duplessis@gmail.com>
*/
interface MailerInterface
{
/**
* Send an email to a user to confirm the account creation
*
* @param UserInterface $user
*/
function sendConfirmationEmailMessage(UserInterface $user);
/**
* Send an email to a user to confirm the password reset
*
* @param UserInterface $user
*/
function sendResettingEmailMessage(UserInterface $user);
}
After you have implemented your custom mailer class and defined it as a service,
you must update your bundle configuration so that FOSUserBundle will use it.
Simply set the ``mailer`` configuration parameter under the ``service`` section.
An example is listed below.
.. code-block:: yaml
# app/config/config.yml
fos_user:
# ...
service:
mailer: app.custom_fos_user_mailer
To see an example of a working implementation of the ``MailerInterface``
see the `ZetaMailer`_ class of the `ZetaWebmailBundle`_. This implementation
uses the Zeta Components Mail to send emails instead of Swiftmailer.
.. _ZetaMailer: https://github.com/simplethings/ZetaWebmailBundle/blob/master/UserBundle/ZetaMailer.php
.. _ZetaWebmailBundle: https://github.com/simplethings/ZetaWebmailBundle

View File

@@ -0,0 +1,25 @@
The username Form Type
======================
FOSUserBundle provides a convenient username form type, named ``fos_user_username``.
It appears as a text input, accepts usernames and convert them to a User
instance::
class MessageFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('recipient', 'FOS\UserBundle\Form\Type\UsernameFormType');
}
}
.. note::
If you don't use this form type in your app, you can disable it to remove
the service from the container:
.. code-block:: yaml
# app/config/config.yml
fos_user:
use_username_form_type: false

View File

@@ -0,0 +1,305 @@
Using Groups With FOSUserBundle
===============================
FOSUserBundle allows you to associate groups to your users. Groups are a
way to group a collection of roles. The roles of a group will be granted
to all users belonging to it.
.. note::
Symfony supports role inheritance so inheriting roles from groups is
not always needed. If the role inheritance is enough for your use case,
it is better to use it instead of groups as it is more efficient (loading
the groups triggers the database).
To use the groups, you need to explicitly enable this functionality in your
configuration. The only mandatory configuration is the fully qualified class
name (FQCN) of your ``Group`` class which must implement ``FOS\UserBundle\Model\GroupInterface``.
Below is an example configuration for enabling groups support.
.. configuration-block::
.. code-block:: yaml
# app/config/config.yml
fos_user:
db_driver: orm
firewall_name: main
user_class: AppBundle\Entity\User
group:
group_class: AppBundle\Entity\Group
.. code-block:: xml
<!-- app/config/config.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:fos-user="http://friendsofsymfony.github.io/schema/dic/user"
>
<fos_user:config
db-driver="orm"
firewall-name="main"
user-class="AppBundle\Entity\User"
>
<fos_user:group group-class="AppBundle\Entity\Group" />
</fos_user:config>
</container>
The Group class
---------------
The simplest way to create a Group class is to extend the mapped superclass
provided by the bundle.
a) ORM Group class implementation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. configuration-block::
.. code-block:: php-annotations
<?php
// src/AppBundle/Entity/Group.php
namespace AppBundle\Entity;
use FOS\UserBundle\Model\Group as BaseGroup;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table(name="fos_group")
*/
class Group extends BaseGroup
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
}
.. code-block:: yaml
# src/AppBundle/Resources/config/doctrine/Group.orm.yml
AppBundle\Entity\Group:
type: entity
table: fos_group
id:
id:
type: integer
generator:
strategy: AUTO
.. note::
``Group`` is a reserved keyword in SQL so it cannot be used as the table name.
b) MongoDB Group class implementation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: php
<?php
// src/AppBundle/Document/Group.php
namespace AppBundle\Document;
use FOS\UserBundle\Model\Group as BaseGroup;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
/**
* @MongoDB\Document
*/
class Group extends BaseGroup
{
/**
* @MongoDB\Id(strategy="auto")
*/
protected $id;
}
c) CouchDB Group class implementation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: php
<?php
// src/AppBundle/CouchDocument/Group.php
namespace AppBundle\CouchDocument;
use FOS\UserBundle\Model\Group as BaseGroup;
use Doctrine\ODM\CouchDB\Mapping\Annotations as CouchDB;
/**
* @CouchDB\Document
*/
class Group extends BaseGroup
{
/**
* @CouchDB\Id
*/
protected $id;
}
Defining the User-Group relation
--------------------------------
The next step is to map the relation in your ``User`` class.
a) ORM User-Group mapping
~~~~~~~~~~~~~~~~~~~~~~~~~
.. configuration-block::
.. code-block:: php-annotations
<?php
// src/AppBundle/Entity/User.php
namespace AppBundle\Entity;
use FOS\UserBundle\Model\User as BaseUser;
/**
* @ORM\Entity
* @ORM\Table(name="fos_user")
*/
class User extends BaseUser
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORM\ManyToMany(targetEntity="AppBundle\Entity\Group")
* @ORM\JoinTable(name="fos_user_user_group",
* joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={@ORM\JoinColumn(name="group_id", referencedColumnName="id")}
* )
*/
protected $groups;
}
.. code-block:: yaml
# src/AppBundle/Resources/config/doctrine/User.orm.yml
AppBundle\Entity\User:
type: entity
table: fos_user
id:
id:
type: integer
generator:
strategy: AUTO
manyToMany:
groups:
targetEntity: Group
joinTable:
name: fos_user_group
joinColumns:
user_id:
referencedColumnName: id
inverseJoinColumns:
group_id:
referencedColumnName: id
.. code-block:: xml
<?xml version="1.0" encoding="UTF-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="AppBundle\Entity\User" table="fos_user">
<id name="id" column="id" type="integer">
<generator strategy="AUTO" />
</id>
<many-to-many field="groups" target-entity="Group">
<join-table name="fos_user_group">
<join-columns>
<join-column name="user_id" referenced-column-name="id"/>
</join-columns>
<inverse-join-columns>
<join-column name="group_id" referenced-column-name="id" />
</inverse-join-columns>
</join-table>
</many-to-many>
</entity>
</doctrine-mapping>
b) MongoDB User-Group mapping
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: php
<?php
// src/AppBundle/Document/User.php
namespace AppBundle\Document;
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
/**
* @MongoDB\Document
*/
class User extends BaseUser
{
/** @MongoDB\Id(strategy="auto") */
protected $id;
/**
* @MongoDB\ReferenceMany(targetDocument="AppBundle\Document\Group")
*/
protected $groups;
}
c) CouchDB User-Group mapping
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: php
<?php
// src/AppBundle/CouchDocument/User.php
namespace AppBundle\CouchDocument;
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ODM\CouchDB\Mapping\Annotations as CouchDB;
/**
* @CouchDB\Document
*/
class User extends BaseUser
{
/**
* @CouchDB\Id
*/
protected $id;
/**
* @CouchDB\ReferenceMany(targetDocument="AppBundle\CouchDocument\Group")
*/
protected $groups;
}
Enabling the routing for the GroupController
--------------------------------------------
You can import the routing file ``group.xml`` to use the built-in controller to
manipulate groups.
.. code-block:: yaml
# app/config/routing.yml
fos_user_group:
resource: "@FOSUserBundle/Resources/config/routing/group.xml"
prefix: /group

View File

@@ -0,0 +1,462 @@
Getting Started With FOSUserBundle
==================================
The Symfony Security component provides a flexible security framework that
allows you to load users from configuration, a database, or anywhere else
you can imagine. The FOSUserBundle builds on top of this to make it quick
and easy to store users in a database, as well as functionality for registration,
reset password and a profile page.
So, if you need to persist and fetch the users in your system to and from
a database, then you're in the right place.
For a video tutorial, check out `FOSUserBundle FTW`_ by KnpUniversity.
Prerequisites
-------------
This version of the bundle requires Symfony 2.8+. If you are using an older
Symfony version, please use the 1.3.x releases of the bundle.
Translations
~~~~~~~~~~~~
If you wish to use default texts provided in this bundle, you have to make
sure you have translator enabled in your config.
.. code-block:: yaml
# app/config/config.yml
framework:
translator: ~
For more information about translations, check `Symfony documentation`_.
Installation
------------
Installation is a quick (I promise!) 7 step process:
1. Download FOSUserBundle using composer
2. Enable the Bundle
3. Create your User class
4. Configure your application's security.yml
5. Configure the FOSUserBundle
6. Import FOSUserBundle routing
7. Update your database schema
Step 1: Download FOSUserBundle using composer
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Require the bundle with composer:
.. code-block:: bash
$ composer require friendsofsymfony/user-bundle "~2.0"
Composer will install the bundle to your project's ``vendor/friendsofsymfony/user-bundle`` directory.
If you encounter installation errors pointing at a lack of configuration parameters, such as ``The child node "db_driver" at path "fos_user" must be configured``, you should complete the configuration in Step 5 first and then re-run this step.
Step 2: Enable the bundle
~~~~~~~~~~~~~~~~~~~~~~~~~
Enable the bundle in the kernel::
<?php
// app/AppKernel.php
public function registerBundles()
{
$bundles = array(
// ...
new FOS\UserBundle\FOSUserBundle(),
// ...
);
}
Step 3: Create your User class
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The goal of this bundle is to persist some ``User`` class to a database (MySql,
MongoDB, CouchDB, etc). Your first job, then, is to create the ``User`` class
for your application. This class can look and act however you want: add any
properties or methods you find useful. This is *your* ``User`` class.
The bundle provides base classes which are already mapped for most fields
to make it easier to create your entity. Here is how you use it:
1. Extend the base ``User`` class (from the ``Model`` folder if you are using
any of the doctrine variants)
2. Map the ``id`` field. It must be protected as it is inherited from the parent class.
.. caution::
When you extend from the mapped superclass provided by the bundle, don't
redefine the mapping for the other fields as it is provided by the bundle.
In the following sections, you'll see examples of how your ``User`` class should
look, depending on how you're storing your users (Doctrine ORM, MongoDB ODM,
or CouchDB ODM).
.. note::
The doc uses a bundle named ``AppBundle`` according to the Symfony best
practices. However, you can of course place your user class in the bundle
you want.
.. caution::
If you override the __construct() method in your User class, be sure
to call parent::__construct(), as the base User class depends on
this to initialize some fields.
a) Doctrine ORM User class
..........................
If you're persisting your users via the Doctrine ORM, then your ``User`` class
should live in the ``Entity`` namespace of your bundle and look like this to
start:
.. configuration-block::
.. code-block:: php-annotations
<?php
// src/AppBundle/Entity/User.php
namespace AppBundle\Entity;
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table(name="fos_user")
*/
class User extends BaseUser
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
public function __construct()
{
parent::__construct();
// your own logic
}
}
.. code-block:: yaml
# src/AppBundle/Resources/config/doctrine/User.orm.yml
AppBundle\Entity\User:
type: entity
table: fos_user
id:
id:
type: integer
generator:
strategy: AUTO
.. code-block:: xml
<?xml version="1.0" encoding="utf-8"?>
<!-- src/AppBundle/Resources/config/doctrine/User.orm.xml -->
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="AppBundle\Entity\User" table="fos_user">
<id name="id" type="integer" column="id">
<generator strategy="AUTO"/>
</id>
</entity>
</doctrine-mapping>
.. caution::
``user`` is a reserved keyword in the SQL standard. If you need to use reserved words, surround them with backticks, *e.g.* ``@ORM\Table(name="`user`")``
b) MongoDB User class
.....................
If you're persisting your users via the Doctrine MongoDB ODM, then your ``User``
class should live in the ``Document`` namespace of your bundle and look like
this to start::
<?php
// src/AppBundle/Document/User.php
namespace AppBundle\Document;
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
/**
* @MongoDB\Document
*/
class User extends BaseUser
{
/**
* @MongoDB\Id(strategy="auto")
*/
protected $id;
public function __construct()
{
parent::__construct();
// your own logic
}
}
c) CouchDB User class
.....................
If you're persisting your users via the Doctrine CouchDB ODM, then your ``User``
class should live in the ``CouchDocument`` namespace of your bundle and look
like this to start::
<?php
// src/AppBundle/CouchDocument/User.php
namespace AppBundle\CouchDocument;
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ODM\CouchDB\Mapping\Annotations as CouchDB;
/**
* @CouchDB\Document
*/
class User extends BaseUser
{
/**
* @CouchDB\Id
*/
protected $id;
public function __construct()
{
parent::__construct();
// your own logic
}
}
Step 4: Configure your application's security.yml
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In order for Symfony's security component to use the FOSUserBundle, you must
tell it to do so in the ``security.yml`` file. The ``security.yml`` file is where the
basic security configuration for your application is contained.
Below is a minimal example of the configuration necessary to use the FOSUserBundle
in your application:
.. code-block:: yaml
# app/config/security.yml
security:
encoders:
FOS\UserBundle\Model\UserInterface: bcrypt
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: ROLE_ADMIN
providers:
fos_userbundle:
id: fos_user.user_provider.username
firewalls:
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_token_generator: security.csrf.token_manager
logout: true
anonymous: true
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/, role: ROLE_ADMIN }
Under the ``providers`` section, you are making the bundle's packaged user provider
service available via the alias ``fos_userbundle``. The id of the bundle's user
provider service is ``fos_user.user_provider.username``.
Next, take a look at and examine the ``firewalls`` section. Here we have
declared a firewall named ``main``. By specifying ``form_login``, you have
told the Symfony Framework that any time a request is made to this firewall
that leads to the user needing to authenticate himself, the user will be
redirected to a form where he will be able to enter his credentials. It should
come as no surprise then that you have specified the user provider service
we declared earlier as the provider for the firewall to use as part of the
authentication process.
.. note::
Although we have used the form login mechanism in this example, the FOSUserBundle
user provider service is compatible with many other authentication methods
as well. Please read the Symfony Security component documentation for
more information on the other types of authentication methods.
The ``access_control`` section is where you specify the credentials necessary for
users trying to access specific parts of your application. The bundle requires
that the login form and all the routes used to create a user and reset the password
be available to unauthenticated users but use the same firewall as
the pages you want to secure with the bundle. This is why you have specified that
any request matching the ``/login`` pattern or starting with ``/register`` or
``/resetting`` have been made available to anonymous users. You have also specified
that any request beginning with ``/admin`` will require a user to have the
``ROLE_ADMIN`` role.
For more information on configuring the ``security.yml`` file please read the Symfony
`security component documentation`_.
.. note::
Pay close attention to the name, ``main``, that we have given to the
firewall which the FOSUserBundle is configured in. You will use this
in the next step when you configure the FOSUserBundle.
Step 5: Configure the FOSUserBundle
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Now that you have properly configured your application's ``security.yml`` to work
with the FOSUserBundle, the next step is to configure the bundle to work with
the specific needs of your application.
Add the following configuration to your ``config.yml`` file according to which type
of datastore you are using.
.. configuration-block::
.. code-block:: yaml
# app/config/config.yml
fos_user:
db_driver: orm # other valid values are 'mongodb' and 'couchdb'
firewall_name: main
user_class: AppBundle\Entity\User
from_email:
address: "%mailer_user%"
sender_name: "%mailer_user%"
.. code-block:: xml
<!-- app/config/config.xml -->
<!-- other valid 'db-driver' values are 'mongodb' and 'couchdb' -->
<fos_user:config
db-driver="orm"
firewall-name="main"
user-class="AppBundle\Entity\User"
/>
Only four configuration's node are required to use the bundle:
* The type of datastore you are using (``orm``, ``mongodb`` or ``couchdb``).
* The firewall name which you configured in Step 4.
* The fully qualified class name (FQCN) of the ``User`` class which you created in Step 3.
* The default email address to use when the bundle send a registration confirmation to the user.
.. note::
FOSUserBundle uses a compiler pass to register mappings for the base
User and Group model classes with the object manager that you configured
it to use. (Unless specified explicitly, this is the default manager
of your doctrine configuration.)
Step 6: Import FOSUserBundle routing files
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Now that you have activated and configured the bundle, all that is left to do is
import the FOSUserBundle routing files.
By importing the routing files you will have ready made pages for things such as
logging in, creating users, etc.
.. configuration-block::
.. code-block:: yaml
# app/config/routing.yml
fos_user:
resource: "@FOSUserBundle/Resources/config/routing/all.xml"
.. code-block:: xml
<!-- app/config/routing.xml -->
<import resource="@FOSUserBundle/Resources/config/routing/all.xml"/>
.. note::
In order to use the built-in email functionality (confirmation of the account,
resetting of the password), you must activate and configure the SwiftmailerBundle.
Step 7: Update your database schema
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Now that the bundle is configured, the last thing you need to do is update your
database schema because you have added a new entity, the ``User`` class which you
created in Step 4.
For ORM run the following command.
.. code-block:: bash
$ php bin/console doctrine:schema:update --force
For MongoDB users you can run the following command to create the indexes.
.. code-block:: bash
$ php bin/console doctrine:mongodb:schema:create --index
.. note::
If you use the Symfony 2.x structure in your project, use ``app/console``
instead of ``bin/console`` in the commands.
You now can log in at ``http://app.com/app_dev.php/login``!
Next Steps
~~~~~~~~~~
Now that you have completed the basic installation and configuration of the
FOSUserBundle, you are ready to learn about more advanced features and usages
of the bundle.
The following documents are available:
.. toctree::
:maxdepth: 1
overriding_templates
controller_events
overriding_forms
user_manager
command_line_tools
logging_by_username_or_email
form_type
emails
groups
doctrine
overriding_validation
canonicalizer
custom_storage_layer
routing
configuration_reference
adding_invitation_registration
.. _security component documentation: https://symfony.com/doc/current/book/security.html
.. _Symfony documentation: https://symfony.com/doc/current/book/translation.html
.. _TypehintableBehavior: https://github.com/willdurand/TypehintableBehavior
.. _FOSUserBundle FTW: https://knpuniversity.com/screencast/fosuserbundle

View File

@@ -0,0 +1,15 @@
Logging by Username or Email
============================
As of the version 1.3.0, the bundle provides a built-in user provider implementation
using both the username and email fields. To use it, simply change the id
of your user provider to use this implementation instead of the base one
using only the username:
.. code-block:: yaml
# app/config/security.yml
security:
providers:
fos_userbundle:
id: fos_user.user_provider.username_email

View File

@@ -0,0 +1,167 @@
Overriding Default FOSUserBundle Forms
======================================
Overriding a Form Type
----------------------
The default forms packaged with the FOSUserBundle provide functionality for
registering new user, updating your profile, changing your password and
much more. These forms work well with the bundle's default classes and controllers.
But, as you start to add more properties to your ``User``
class or you decide you want to add a few options to the registration form you
will find that you need to override the forms in the bundle.
Suppose that you have created an ORM user class with the following class name,
``AppBundle\Entity\User``. In this class, you have added a ``name`` property
because you would like to save the user's name as well as their username and
email address. Now, when a user registers for your site they should enter in their
name as well as their username, email and password. Below is an example ``$name``
property and its validators.
.. code-block:: php
// src/AppBundle/Entity/User.php
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
class User extends BaseUser
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORM\Column(type="string", length=255)
*
* @Assert\NotBlank(message="Please enter your name.", groups={"Registration", "Profile"})
* @Assert\Length(
* min=3,
* max=255,
* minMessage="The name is too short.",
* maxMessage="The name is too long.",
* groups={"Registration", "Profile"}
* )
*/
protected $name;
// ...
}
.. note::
By default, the Registration validation group is used when validating a new
user registration. Unless you have overridden this value in the configuration,
make sure you add the validation group named Registration to your name property.
If you try and register using the default registration form you will find that
your new ``name`` property is not part of the form. You need to create a custom
form type and configure the bundle to use it.
The first step is to create a new form type in your own bundle. The following
class inherits from the base FOSUserBundle ``fos_user_registration`` type using
the form type hierarchy and then adds the custom ``name`` field.
.. code-block:: php
<?php
// src/AppBundle/Form/RegistrationType.php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
class RegistrationType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name');
}
public function getParent()
{
return 'FOS\UserBundle\Form\Type\RegistrationFormType';
}
public function getBlockPrefix()
{
return 'app_user_registration';
}
// For Symfony 2.x
public function getName()
{
return $this->getBlockPrefix();
}
}
.. note::
If you don't want to reuse the fields added in FOSUserBundle by default,
you can omit the ``getParent`` method and configure all fields yourself.
Now that you have created your custom form type, you must declare it as a service
and add a tag to it. The tag must have a ``name`` value of ``form.type`` and an ``alias``
value that is the equal to the string returned from the ``getName`` method of your
form type class. The ``alias`` that you specify is what you will use in the FOSUserBundle
configuration to let the bundle know that you want to use your custom form.
Below is an example of configuring your form type as a service:
.. configuration-block::
.. code-block:: yaml
# app/config/services.yml
services:
app.form.registration:
class: AppBundle\Form\RegistrationType
tags:
- { name: form.type, alias: app_user_registration }
.. code-block:: xml
<!-- app/config/services.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="app.form.registration" class="AppBundle\Form\RegistrationType">
<tag name="form.type" alias="app_user_registration" />
</service>
</services>
</container>
Finally, you must update the configuration of the FOSUserBundle so that it will
use your form type instead of the default one. Below is the configuration for
changing the registration form type in YAML.
.. code-block:: yaml
# app/config/config.yml
fos_user:
# ...
registration:
form:
type: AppBundle\Form\RegistrationType
Note how the ``alias`` value used in your form type's service configuration tag
is used in the bundle configuration to tell the FOSUserBundle to use your custom
form type.
.. note::
If you need to add some logic to the processing of the form, you can
use a listener :doc:`hooking into the controller </controller_events>`.

View File

@@ -0,0 +1,96 @@
Overriding Default FOSUserBundle Templates
==========================================
As you start to incorporate FOSUserBundle into your application, you will probably
find that you need to override the default templates that are provided by
the bundle. Although the template names are not configurable, Symfony
provides a built-in way to `override the templates themselves`_.
Example: Overriding The Default layout.html.twig
------------------------------------------------
It is highly recommended that you override the ``Resources/views/layout.html.twig``
template so that the pages provided by the FOSUserBundle have a similar look and
feel to the rest of your application. An example of overriding this layout template
is demonstrated below using both of the overriding options listed above.
Here is the default ``layout.html.twig`` provided by the FOSUserBundle:
.. code-block:: html+jinja
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
</head>
<body>
<div>
{% if is_granted("IS_AUTHENTICATED_REMEMBERED") %}
{{ 'layout.logged_in_as'|trans({'%username%': app.user.username}, 'FOSUserBundle') }} |
<a href="{{ path('fos_user_security_logout') }}">
{{ 'layout.logout'|trans({}, 'FOSUserBundle') }}
</a>
{% else %}
<a href="{{ path('fos_user_security_login') }}">{{ 'layout.login'|trans({}, 'FOSUserBundle') }}</a>
{% endif %}
</div>
{% if app.request.hasPreviousSession %}
{% for type, messages in app.session.flashBag.all %}
{% for message in messages %}
<div class="{{ type }}">
{{ message|trans({}, 'FOSUserBundle') }}
</div>
{% endfor %}
{% endfor %}
{% endif %}
<div>
{% block fos_user_content %}
{% endblock fos_user_content %}
</div>
</body>
</html>
As you can see its pretty basic and doesn't really have much structure, so you will
want to replace it with a layout file that is appropriate for your application. The
main thing to note in this template is the block named ``fos_user_content``. This is
the block where the content from each of the different bundle's actions will be
displayed, so you must make sure to include this block in the layout file you will
use to override the default one.
The following Twig template file is an example of a layout file that might be used
to override the one provided by the bundle.
.. code-block:: html+jinja
{% block title %}Demo Application{% endblock %}
{% block content %}
{% block fos_user_content %}{% endblock %}
{% endblock %}
This example extends the layout template from the layout of your app. The
``content`` block is where the main content of each page is rendered. This
is why the ``fos_user_content`` block has been placed inside of it. This
will lead to the desired effect of having the output from the FOSUserBundle
actions integrated into our applications layout, preserving the look and
feel of the application.
The easiest way to override a bundle's template is to simply place a new one in
your ``app/Resources`` folder. To override the layout template located at
``Resources/views/layout.html.twig`` in the ``FOSUserBundle`` directory, you would place
your new layout template at ``app/Resources/FOSUserBundle/views/layout.html.twig``.
As you can see the pattern for overriding templates in this way is to
create a folder with the name of the bundle class in the ``app/Resources`` directory.
Then add your new template to this folder, preserving the directory structure from the
original bundle.
After overriding a template, you must clear the cache for the override to
take effect, even in a development environment.
Overriding all of the other templates provided by the FOSUserBundle can be done
in a similar fashion using either of the two methods shown in this document.
.. _`override the templates themselves`: https://symfony.com/doc/current/templating/overriding.html

View File

@@ -0,0 +1,6 @@
Overriding Default FOSUserBundle Validation
===========================================
The ``Resources/config/validation.xml`` file contains definitions for custom
validator rules for various classes. The rules defined by FOSUserBundle are
all in validation groups so you can choose not to use them.

View File

@@ -0,0 +1,40 @@
Advanced routing configuration
==============================
By default, the routing file ``@FOSUserBundle/Resources/config/routing/all.xml`` imports
all the routing files (except groups) and enables all the routes.
In the case you want to enable or disable the different available routes, just use the
single routing configuration files.
.. configuration-block::
.. code-block:: yaml
# app/config/routing.yml
fos_user_security:
resource: "@FOSUserBundle/Resources/config/routing/security.xml"
fos_user_profile:
resource: "@FOSUserBundle/Resources/config/routing/profile.xml"
prefix: /profile
fos_user_register:
resource: "@FOSUserBundle/Resources/config/routing/registration.xml"
prefix: /register
fos_user_resetting:
resource: "@FOSUserBundle/Resources/config/routing/resetting.xml"
prefix: /resetting
fos_user_change_password:
resource: "@FOSUserBundle/Resources/config/routing/change_password.xml"
prefix: /profile
.. code-block:: xml
<!-- app/config/routing.xml -->
<import resource="@FOSUserBundle/Resources/config/routing/security.xml"/>
<import resource="@FOSUserBundle/Resources/config/routing/profile.xml" prefix="/profile" />
<import resource="@FOSUserBundle/Resources/config/routing/registration.xml" prefix="/register" />
<import resource="@FOSUserBundle/Resources/config/routing/resetting.xml" prefix="/resetting" />
<import resource="@FOSUserBundle/Resources/config/routing/change_password.xml" prefix="/profile" />

View File

@@ -0,0 +1,153 @@
About FOSUserBundle User Manager
================================
In order to be storage agnostic, all operations on the user instances are
handled by a user manager implementing ``FOS\UserBundle\Model\UserManagerInterface``.
Using it ensures that your code will continue to work if you change the storage.
The controllers provided by the bundle use the configured user manager instead
of interacting directly with the storage layer.
If you configure the ``db_driver`` option to ``orm``, this service is an instance
of ``FOS\UserBundle\Doctrine\UserManager``.
If you configure the ``db_driver`` option to ``mongodb``, this service is an
instance of ``FOS\UserBundle\Doctrine\UserManager``.
If you configure the ``db_driver`` option to ``couchdb``, this service is an
instance of ``FOS\UserBundle\Doctrine\UserManager``.
Accessing the User Manager service
----------------------------------
The user manager is available in the container as the ``fos_user.user_manager``
service.
.. code-block:: php
$userManager = $container->get('fos_user.user_manager');
Creating a new User
-------------------
A new instance of your User class can be created by the user manager.
.. code-block:: php
$user = $userManager->createUser();
``$user`` is now an instance of your user class.
.. note::
This method will not work if your user class has some mandatory constructor
arguments.
Retrieving the users
--------------------
The user manager has a few methods to find users based on the unique fields
(username, email and confirmation token) and a method to retrieve all existing
users.
- ``findUserByUsername($username)``
- ``findUserByEmail($email)``
- ``findUserByUsernameOrEmail($value)`` (check if the value looks like an email to choose)
- ``findUserByConfirmationToken($token)``
- ``findUserBy(array('id'=>$id))``
- ``findUsers()``
To save a user object, you can use the ``updateUser`` method of the user manager.
This method will update the encoded password and the canonical fields and
then persist the changes.
Updating a User object
----------------------
.. code-block:: php
$user = $userManager->createUser();
$user->setUsername('John');
$user->setEmail('john.doe@example.com');
$userManager->updateUser($user);
.. note::
To make it easier, the bundle comes with a Doctrine listener handling
the update of the password and the canonical fields for you behind the
scenes. If you always save the user through the user manager, you may
want to disable it to improve performance.
.. configuration-block::
.. code-block:: yaml
# app/config/config.yml
fos_user:
# ...
use_listener: false
.. code-block:: xml
<!-- app/config/config.xml -->
<fos_user:config
db-driver="orm"
firewall-name="main"
use-listener="false"
user-class="MyProject\MyBundle\Entity\User"
/>
.. note::
For the Doctrine implementations, the default behavior is to flush the
unit of work when calling the ``updateUser`` method. You can disable the
flush by passing a second argument set to ``false``.
This will then be equivalent to calling ``updateCanonicalFields`` and
``updatePassword``.
An ORM example::
class MainController extends Controller
{
public function updateAction($id)
{
$user = // get a user from the datastore
$user->setEmail($newEmail);
$this->get('fos_user.user_manager')->updateUser($user, false);
// make more modifications to the database
$this->getDoctrine()->getManager()->flush();
}
}
Overriding the User Manager
---------------------------
You can replace the default implementation of the user manager by defining
a service implementing ``FOS\UserBundle\Model\UserManagerInterface`` and
setting its id in the configuration.
The id of the default implementation is ``fos_user.user_manager.default``
.. code-block:: yaml
fos_user:
# ...
service:
user_manager: custom_user_manager_id
Your custom implementation can extend ``FOS\UserBundle\Model\UserManager``
to reuse the common logic.
SecurityBundle integration
--------------------------
The bundle provides several implementation of ``Symfony\Component\Security\Core\UserProviderInterface``
on top of the ``UserManagerInterface``.
Although the built-in user managers also implement
``Symfony\Component\Security\Core\User\UserProviderInterface``, using the
UserManager as user provider is deprecated and will tbe removed in future
versions. Use ``FOS\UserBundle\Security\UserProvider`` instead.