@@ -197,24 +197,32 @@ For more details on each of these, see :class:`Symfony\\Component\\Security\\Cor
197197 because the:method: `Symfony\\ Bridge\\ Doctrine\\ Security\\ User\\ EntityUserProvider::refreshUser `
198198 method reloads the user on each request by using the ``id ``.
199199
200- Below is an export of my ``User `` table from MySQL. For details on how to
201- create user records and encode their password, see:ref: `book-security-encoding-user-password `.
200+ ..tip ::
201+
202+ To generate missing setters and getters for your ``User `` entity, you
203+ can use ``php app/console doctrine:generate:entities Acme/UserBundle/Entity/User ``.
204+ For more details, see Doctrine's:ref: `book-doctrine-generating-getters-and-setters `.
205+
206+ Below is an export of my ``User `` table from MySQL with user `admin `
207+ and password `admin `. For details on how to create user records and
208+ encode their password, see:ref: `book-security-encoding-user-password `.
202209
203210..code-block ::bash
204211
205- $ mysql> select * from user;
206- +----+----------+----------------------------------+------------------------------------------+--------------------+-----------+
207- | id| username| salt| password| email| is_active|
208- +----+----------+----------------------------------+------------------------------------------+--------------------+-----------+
209- | 1| hhamon| 7308e59b97f6957fb42d66f894793079| 09610f61637408828a35d7debee5b38a8350eebe| hhamon@example.com| 1|
210- | 2| jsmith| ce617a6cca9126bf4036ca0c02e82dee| 8390105917f3a3d533815250ed7c64b4594d7ebf| jsmith@example.com| 1|
211- | 3| maxime| cd01749bb995dc658fa56ed45458d807| 9764731e5f7fb944de5fd8efad4949b995b72a3c| maxime@example.com| 0|
212- | 4| donald| 6683c2bfd90c0426088402930cadd0f8| 5c3bcec385f59edcc04490d1db95fdb8673bf612| donald@example.com| 1|
213- +----+----------+----------------------------------+------------------------------------------+--------------------+-----------+
214- 4 rowsin set (0.00 sec)
215-
216- The database now contains four users with different usernames, emails and
217- statuses. The next part will focus on how to authenticate one of these users
212+ $ mysql> select * from acme_users;
213+ +----+----------+------+------------------------------------------+--------------------+-----------+
214+ | id| username| salt| password| email| is_active|
215+ +----+----------+------+------------------------------------------+--------------------+-----------+
216+ | 1| admin| | d033e22ae348aeb5660fc2140aec35850c4da997| admin@example.com| 1|
217+ +----+----------+------+------------------------------------------+--------------------+-----------+
218+
219+ .. tip::
220+
221+ To generate database table from your` ` User` ` entity, you can run
222+ ` ` php app/console doctrine:schema:update --force` ` .
223+ For mor details, see Doctrine' s :ref:`book-doctrine-creating-the-database-tables-schema`.
224+
225+ The next part will focus on how to authenticate one of these users
218226thanks to the Doctrine entity user provider and a couple of lines of
219227configuration.
220228
@@ -329,9 +337,8 @@ entity user provider to load User entity objects from the database by using
329337the` ` username` ` unique field. In other words, this tells Symfony how to
330338fetch the user from the database before checking the password validity.
331339
332- This code and configuration works but it' s not enough to secure the application
333- for ** active** users. As of now, you can still authenticate with` ` maxime` ` . The
334- next section explains how to forbid non active users.
340+ This code is not enough to secure the applicationfor ** active** users.
341+ The next section explains how to forbid non active users.
335342
336343Forbid non Active Users
337344-----------------------
@@ -361,10 +368,10 @@ For this example, the first three methods will return ``true`` whereas the
361368 // src/Acme/UserBundle/Entity/User.php
362369 namespace Acme\UserBundle\Entity;
363370
364- // ...
371+ use Doctrine\ORM\Mapping as ORM;
365372 use Symfony\Component\Security\Core\User\AdvancedUserInterface;
366373
367- class User implements AdvancedUserInterface
374+ class User implements AdvancedUserInterface, \Serializable
368375 {
369376 // ...
370377
@@ -389,10 +396,8 @@ For this example, the first three methods will return ``true`` whereas the
389396 }
390397 }
391398
392- If you try to authenticate as ``maxime``, the access is now forbidden as this
393- user does not have an enabled account. The next session will focus on how
394- to write a custom entity provider to authenticate a user with his username
395- or his email address.
399+ The next session will focus on how to write a custom entity provider
400+ to authenticate a user with his username or his email address.
396401
397402Authenticating Someone with a Custom Entity Provider
398403----------------------------------------------------
@@ -434,8 +439,7 @@ The code below shows the implementation of the
434439 ->where(' u.username = :username OR u.email = :email' )
435440 ->setParameter(' username' , $username)
436441 ->setParameter(' email' , $username)
437- ->getQuery()
438- ;
442+ ->getQuery();
439443
440444 try {
441445 // The Query::getSingleResult() method throws an exception
@@ -543,10 +547,11 @@ about in this section.
543547 authenticated at all.
544548
545549In this example, the` ` AcmeUserBundle:User` ` entity class defines a
546- many-to-many relationship with a` ` AcmeUserBundle:Group` ` entity class. A user
547- can be related to several groups and a group can be composed of one or
548- more users. As a group is also a role, the previous``getRoles ()` ` method now
549- returns the list of related groups::
550+ many-to-many relationship with a` ` AcmeUserBundle:Role` ` entity class.
551+ A user can be related to several roles and a role can be composed of
552+ one or more users. The previous``getRoles ()` ` method now returns
553+ the list of related roles.
554+ Notice that methods``__construcotor ()` ` and``getRoles ()` ` had changed::
550555
551556 // src/Acme/UserBundle/Entity/User.php
552557 namespace Acme\U serBundle\E ntity;
@@ -556,63 +561,46 @@ returns the list of related groups::
556561
557562 class User implements AdvancedUserInterface,\S erializable
558563 {
564+ //...
565+
559566 /**
560- * @ORM\M anyToMany(targetEntity=" Group " , inversedBy=" users" )
567+ * @ORM\M anyToMany(targetEntity=" Role " , inversedBy=" users" )
561568*
562569* /
563- private$groups ;
570+ private$roles ;
564571
565572 publicfunction __construct()
566573 {
567- $this -> groups = newArrayCollection ();
574+ $this -> roles = newArrayCollection ();
568575 }
569576
570- // ...
571-
572577 publicfunction getRoles()
573578 {
574- return $this->groups->toArray ();
575- }
576-
577- /**
578- * @see\S erializable::serialize()
579- * /
580- publicfunction serialize()
581- {
582- return serialize(array(
583- $this -> id,
584- ));
579+ return $this->roles->toArray ();
585580 }
581+
582+ // ...
586583
587- /**
588- * @see\S erializable::unserialize()
589- * /
590- publicfunction unserialize($serialized)
591- {
592- list (
593- $this -> id,
594- ) = unserialize($serialized );
595- }
596584 }
597585
598- The` ` AcmeUserBundle:Group ` ` entity class defines three table fields (` ` id` ` ,
586+ The` ` AcmeUserBundle:Role ` ` entity class defines three table fields (` ` id` ` ,
599587` ` name` ` and` ` role` ` ). The unique` ` role` ` field contains the role name used by
600588the Symfony security layer to secure parts of the application. The most
601- important thing to notice is that the` ` AcmeUserBundle:Group ` ` entity class
589+ important thing to notice is that the` ` AcmeUserBundle:Role ` ` entity class
602590extends the :class:` Symfony\\ Component\\ Security\\ Core\\ Role\\ Role` ::
603591
604- // src/Acme/Bundle/UserBundle/Entity/Group .php
592+ // src/Acme/Bundle/UserBundle/Entity/Role .php
605593 namespace Acme\U serBundle\E ntity;
606594
607- use Symfony\C omponent\S ecurity\C ore\R ole\R ole ;
595+ use Symfony\C omponent\S ecurity\C ore\R ole\R oleInterface ;
608596 use Doctrine\C ommon\C ollections\A rrayCollection;
609597 use Doctrine\O RM\M apping as ORM;
610598
611599 /**
612- * @ORM\T able(name=" acme_groups " )
600+ * @ORM\T able(name=" acme_roles " )
613601* @ORM\E ntity()
614602* /
615- classGroup extends Role
603+ classRole implements RoleInterface
616604 {
617605 /**
618606* @ORM\C olumn(name=" id" , type=" integer" )
@@ -632,7 +620,7 @@ extends the :class:`Symfony\\Component\\Security\\Core\\Role\\Role`::
632620 private$role ;
633621
634622 /**
635- * @ORM\M anyToMany(targetEntity=" User" , mappedBy=" groups " )
623+ * @ORM\M anyToMany(targetEntity=" User" , mappedBy=" roles " )
636624* /
637625 private$users ;
638626
@@ -641,21 +629,27 @@ extends the :class:`Symfony\\Component\\Security\\Core\\Role\\Role`::
641629$this -> users = newArrayCollection ();
642630 }
643631
644- // ... getters and settersfor each property
645-
646632 /**
647633* @see RoleInterface
648634* /
649635 publicfunction getRole()
650636 {
651637return $this -> role;
652638 }
639+
640+ // ... getters and settersfor each property
653641 }
654642
655- To improve performances and avoid lazy loading of groups when retrieving a user
656- from the custom entity provider, the best solution is to join the groups
643+ .. tip::
644+
645+ To generate missing setters and gettersfor your` ` Role` ` entity, you
646+ can use` ` php app/console doctrine:generate:entities Acme/UserBundle/Entity/User` ` .
647+ For more details, see Doctrine' s :ref:`book-doctrine-generating-getters-and-setters`.
648+
649+ To improve performances and avoid lazy loading of roles when retrieving a user
650+ from the custom entity provider, the best solution is to join the roles
657651relationship in the ``UserRepository::loadUserByUsername()`` method. This will
658- fetch the user and his associated roles/ groups with a single query::
652+ fetch the user and his associated roles with a single query::
659653
660654 // src/Acme/UserBundle/Entity/UserRepository.php
661655 namespace Acme\UserBundle\Entity;
@@ -668,8 +662,8 @@ fetch the user and his associated roles / groups with a single query::
668662 {
669663 $q = $this
670664 ->createQueryBuilder(' u' )
671- -> select(' u,g ' )
672- -> leftJoin(' u.groups ' ,' g ' )
665+ ->select(' u,r ' )
666+ ->leftJoin(' u.roles ' ,' r ' )
673667 ->where(' u.username = :username OR u.email = :email' )
674668 ->setParameter(' username' , $username)
675669 ->setParameter(' email' , $username)
@@ -681,6 +675,29 @@ fetch the user and his associated roles / groups with a single query::
681675 // ...
682676 }
683677
684- The``QueryBuilder::leftJoin ()` ` method joins and fetches relatedgroups from
678+ The ``QueryBuilder::leftJoin()`` method joins and fetches relatedroles from
685679the ``AcmeUserBundle:User`` model class when a user is retrieved with his email
686680address or username.
681+
682+ To re-generate all database tables, you can run ``php app/console doctrine:schema:update --force``.
683+ This will also create additional table ``user_role`` what holds
684+ relations between users and roles.
685+ For mor details, see Doctrine' s :ref:` book-doctrine-creating-the-database-tables-schema` .
686+
687+ Below is anexport of my` ` Roles` ` and` ` user_role` ` tables from MySQL:
688+
689+ .. code-block:: bash
690+
691+ $ mysql> select * from acme_users;
692+ +----+-------+------------+
693+ | id| name| role|
694+ +----+-------+------------+
695+ | 1| admin| ROLE_ADMIN|
696+ +----+-------+------------+
697+
698+ mysql> select * from user_role;
699+ +---------+---------+
700+ | user_id| role_id|
701+ +---------+---------+
702+ | 1| 1|
703+ +---------+---------+