Skip to content

Commit 1d00f06

Browse files
gondoweaverryan
authored andcommitted
Fixing Security Entity Provider tutorial
for more info see symfony#2756
1 parent 0849175 commit 1d00f06

File tree

2 files changed

+91
-70
lines changed

2 files changed

+91
-70
lines changed

book/doctrine.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,8 @@ see the :ref:`book-doctrine-field-types` section.
364364
class Product
365365
// ...
366366

367+
.. _book-doctrine-generating-getters-and-setters:
368+
367369
Generating Getters and Setters
368370
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
369371

@@ -426,6 +428,8 @@ mapping information) of a bundle or an entire namespace:
426428
The getters and setters are generated here only because you'll need them
427429
to interact with your PHP object.
428430

431+
.. _book-doctrine-creating-the-database-tables-schema:
432+
429433
Creating the Database Tables/Schema
430434
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
431435

cookbook/security/entity_provider.rst

Lines changed: 87 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -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 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
218226
thanks to the Doctrine entity user provider and a couple of lines of
219227
configuration.
220228
@@ -329,9 +337,8 @@ entity user provider to load User entity objects from the database by using
329337
the ``username`` unique field. In other words, this tells Symfony how to
330338
fetch 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 application for **active** users.
341+
The next section explains how to forbid non active users.
335342
336343
Forbid 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
397402
Authenticating 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
545549
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::
550555
551556
// src/Acme/UserBundle/Entity/User.php
552557
namespace Acme\UserBundle\Entity;
@@ -556,63 +561,46 @@ returns the list of related groups::
556561
557562
class User implements AdvancedUserInterface, \Serializable
558563
{
564+
//...
565+
559566
/**
560-
* @ORM\ManyToMany(targetEntity="Group", inversedBy="users")
567+
* @ORM\ManyToMany(targetEntity="Role", inversedBy="users")
561568
*
562569
*/
563-
private $groups;
570+
private $roles;
564571
565572
public function __construct()
566573
{
567-
$this->groups = new ArrayCollection();
574+
$this->roles = new ArrayCollection();
568575
}
569576
570-
// ...
571-
572577
public function getRoles()
573578
{
574-
return $this->groups->toArray();
575-
}
576-
577-
/**
578-
* @see \Serializable::serialize()
579-
*/
580-
public function serialize()
581-
{
582-
return serialize(array(
583-
$this->id,
584-
));
579+
return $this->roles->toArray();
585580
}
581+
582+
// ...
586583
587-
/**
588-
* @see \Serializable::unserialize()
589-
*/
590-
public function 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
600588
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
602590
extends 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\UserBundle\Entity;
606594
607-
use Symfony\Component\Security\Core\Role\Role;
595+
use Symfony\Component\Security\Core\Role\RoleInterface;
608596
use Doctrine\Common\Collections\ArrayCollection;
609597
use Doctrine\ORM\Mapping as ORM;
610598
611599
/**
612-
* @ORM\Table(name="acme_groups")
600+
* @ORM\Table(name="acme_roles")
613601
* @ORM\Entity()
614602
*/
615-
class Group extends Role
603+
class Role implements RoleInterface
616604
{
617605
/**
618606
* @ORM\Column(name="id", type="integer")
@@ -632,7 +620,7 @@ extends the :class:`Symfony\\Component\\Security\\Core\\Role\\Role`::
632620
private $role;
633621
634622
/**
635-
* @ORM\ManyToMany(targetEntity="User", mappedBy="groups")
623+
* @ORM\ManyToMany(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 = new ArrayCollection();
642630
}
643631
644-
// ... getters and setters for each property
645-
646632
/**
647633
* @see RoleInterface
648634
*/
649635
public function getRole()
650636
{
651637
return $this->role;
652638
}
639+
640+
// ... getters and setters for 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 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
657651
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::
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 related groups from
678+
The ``QueryBuilder::leftJoin()`` method joins and fetches related roles from
685679
the ``AcmeUserBundle:User`` model class when a user is retrieved with his email
686680
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

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy