@@ -197,24 +197,32 @@ For more details on each of these, see :class:`Symfony\\Component\\Security\\Cor
197
197
because the :method: `Symfony\\ Bridge\\ Doctrine\\ Security\\ User\\ EntityUserProvider::refreshUser `
198
198
method reloads the user on each request by using the ``id ``.
199
199
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 `.
202
209
203
210
.. code-block :: bash
204
211
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 rows in 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
218
226
thanks to the Doctrine entity user provider and a couple of lines of
219
227
configuration.
220
228
@@ -329,9 +337,8 @@ entity user provider to load User entity objects from the database by using
329
337
the ` ` username` ` unique field. In other words, this tells Symfony how to
330
338
fetch the user from the database before checking the password validity.
331
339
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 application for ** active** users.
341
+ The next section explains how to forbid non active users.
335
342
336
343
Forbid non Active Users
337
344
-----------------------
@@ -361,10 +368,10 @@ For this example, the first three methods will return ``true`` whereas the
361
368
// src/Acme/UserBundle/Entity/User.php
362
369
namespace Acme\UserBundle\Entity;
363
370
364
- // ...
371
+ use Doctrine\ORM\Mapping as ORM;
365
372
use Symfony\Component\Security\Core\User\AdvancedUserInterface;
366
373
367
- class User implements AdvancedUserInterface
374
+ class User implements AdvancedUserInterface, \Serializable
368
375
{
369
376
// ...
370
377
@@ -389,10 +396,8 @@ For this example, the first three methods will return ``true`` whereas the
389
396
}
390
397
}
391
398
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.
396
401
397
402
Authenticating Someone with a Custom Entity Provider
398
403
----------------------------------------------------
@@ -434,8 +439,7 @@ The code below shows the implementation of the
434
439
->where(' u.username = :username OR u.email = :email' )
435
440
->setParameter(' username' , $username)
436
441
->setParameter(' email' , $username)
437
- ->getQuery()
438
- ;
442
+ ->getQuery();
439
443
440
444
try {
441
445
// The Query::getSingleResult() method throws an exception
@@ -543,10 +547,11 @@ about in this section.
543
547
authenticated at all.
544
548
545
549
In 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::
550
555
551
556
// src/Acme/UserBundle/Entity/User.php
552
557
namespace Acme\U serBundle\E ntity;
@@ -556,63 +561,46 @@ returns the list of related groups::
556
561
557
562
class User implements AdvancedUserInterface, \S erializable
558
563
{
564
+ //...
565
+
559
566
/**
560
- * @ORM\M anyToMany(targetEntity=" Group " , inversedBy=" users" )
567
+ * @ORM\M anyToMany(targetEntity=" Role " , inversedBy=" users" )
561
568
*
562
569
* /
563
- private $groups ;
570
+ private $roles ;
564
571
565
572
public function __construct()
566
573
{
567
- $this -> groups = new ArrayCollection ();
574
+ $this -> roles = new ArrayCollection ();
568
575
}
569
576
570
- // ...
571
-
572
577
public function getRoles()
573
578
{
574
- return $this->groups->toArray ();
575
- }
576
-
577
- /**
578
- * @see \S erializable::serialize()
579
- * /
580
- public function serialize()
581
- {
582
- return serialize(array(
583
- $this -> id,
584
- ));
579
+ return $this->roles->toArray ();
585
580
}
581
+
582
+ // ...
586
583
587
- /**
588
- * @see \S erializable::unserialize()
589
- * /
590
- public function unserialize($serialized)
591
- {
592
- list (
593
- $this -> id,
594
- ) = unserialize($serialized );
595
- }
596
584
}
597
585
598
- The ` ` AcmeUserBundle:Group ` ` entity class defines three table fields (` ` id` ` ,
586
+ The ` ` AcmeUserBundle:Role ` ` entity class defines three table fields (` ` id` ` ,
599
587
` ` name` ` and ` ` role` ` ). The unique ` ` role` ` field contains the role name used by
600
588
the 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
602
590
extends the :class:` Symfony\\ Component\\ Security\\ Core\\ Role\\ Role` ::
603
591
604
- // src/Acme/Bundle/UserBundle/Entity/Group .php
592
+ // src/Acme/Bundle/UserBundle/Entity/Role .php
605
593
namespace Acme\U serBundle\E ntity;
606
594
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 ;
608
596
use Doctrine\C ommon\C ollections\A rrayCollection;
609
597
use Doctrine\O RM\M apping as ORM;
610
598
611
599
/**
612
- * @ORM\T able(name=" acme_groups " )
600
+ * @ORM\T able(name=" acme_roles " )
613
601
* @ORM\E ntity()
614
602
* /
615
- class Group extends Role
603
+ class Role implements RoleInterface
616
604
{
617
605
/**
618
606
* @ORM\C olumn(name=" id" , type=" integer" )
@@ -632,7 +620,7 @@ extends the :class:`Symfony\\Component\\Security\\Core\\Role\\Role`::
632
620
private $role ;
633
621
634
622
/**
635
- * @ORM\M anyToMany(targetEntity=" User" , mappedBy=" groups " )
623
+ * @ORM\M anyToMany(targetEntity=" User" , mappedBy=" roles " )
636
624
* /
637
625
private $users ;
638
626
@@ -641,21 +629,27 @@ extends the :class:`Symfony\\Component\\Security\\Core\\Role\\Role`::
641
629
$this -> users = new ArrayCollection ();
642
630
}
643
631
644
- // ... getters and setters for each property
645
-
646
632
/**
647
633
* @see RoleInterface
648
634
* /
649
635
public function getRole()
650
636
{
651
637
return $this -> role;
652
638
}
639
+
640
+ // ... getters and setters for each property
653
641
}
654
642
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 getters for 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
657
651
relationship 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::
659
653
660
654
// src/Acme/UserBundle/Entity/UserRepository.php
661
655
namespace Acme\UserBundle\Entity;
@@ -668,8 +662,8 @@ fetch the user and his associated roles / groups with a single query::
668
662
{
669
663
$q = $this
670
664
->createQueryBuilder(' u' )
671
- -> select(' u, g ' )
672
- -> leftJoin(' u.groups ' , ' g ' )
665
+ ->select(' u, r ' )
666
+ ->leftJoin(' u.roles ' , ' r ' )
673
667
->where(' u.username = :username OR u.email = :email' )
674
668
->setParameter(' username' , $username)
675
669
->setParameter(' email' , $username)
@@ -681,6 +675,29 @@ fetch the user and his associated roles / groups with a single query::
681
675
// ...
682
676
}
683
677
684
- The ``QueryBuilder::leftJoin ()` ` method joins and fetches related groups from
678
+ The ``QueryBuilder::leftJoin()`` method joins and fetches related roles from
685
679
the ``AcmeUserBundle:User`` model class when a user is retrieved with his email
686
680
address 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 an export 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
+ +---------+---------+
0 commit comments