Управление пользователями / ролями / группами в FOSUserBundle

Я разрабатываю простой CRUD для управления пользователями / ролями / группами приложения, в котором я работаю. Для управления пользователями я использую FOSUserBundle. То, что я хочу сделать, может быть достигнуто несколькими способами:

  • назначение ролей группам, а затем назначение пользователей этим группам
  • назначение ролей пользователям напрямую

но я понятия не имею как. Я знал, что FOSUser BaseUser класс уже имеет столбец roles и в документация FOSUser объясняет, как установить ManyToMany отношения между пользователями и группами, но ничего не говорят о ролях. Единственная идея, которая приходит на ум, - создать сущность для управления ролями, а также форму для той же цели, что и то, что вы видите ниже:

Роль Субъекта

use SymfonyComponentSecurityCoreRoleRoleInterface;
use DoctrineCommonCollectionsArrayCollection;
use DoctrineORMMapping as ORM;

/**
 * @ORMTable(name="fos_role")
 * @ORMEntity(repositoryClass="UserBundleEntityRepositoryRoleRepository")
 * 
 * @see User
 * @see UserBundleRoleRoleHierarchy
 * 
 */
class Role implements RoleInterface
{
    /**
     * @ORMColumn(name="id", type="integer")
     * @ORMId()
     * @ORMGeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORMColumn(name="name", type="string", length=80, unique=true)
     */
    private $name;

    /**
     * @ORMManyToOne(targetEntity="Role", inversedBy="children")
     * @ORMJoinColumn(name="parent_id", referencedColumnName="id", nullable=true)
     * @var Role[]
     */
    private $parent;

    /**
     * @ORMOneToMany(targetEntity="Role", mappedBy="parent")
     * @var ArrayCollection|Role[]
     */
    private $children;

    /**
     * @ORMManyToMany(targetEntity="User", mappedBy="roles")
     */
    private $users;

    public function __construct($role = "")
    {
        if (0 !== strlen($role)) {
            $this->name = strtoupper($role);
        }

        $this->users = new ArrayCollection();
        $this->children = new ArrayCollection();
    }

    /**
     * @see RoleInterface
     */
    public function getRole()
    {
        return $this->name;
    }

    public function getId()
    {
        return $this->id;
    }

    public function setId($id)
    {
        $this->id = $id;
    }

    public function getName()
    {
        return $this->name;
    }

    public function setName($name)
    {
        $this->name = $name;
    }

    public function getUsers()
    {
        return $this->users;
    }

    public function addUser($user, $addRoleToUser = true)
    {
        $this->users->add($user);
        $addRoleToUser && $user->addRole($this, false);
    }

    public function removeUser($user)
    {
        $this->users->removeElement($user);
    }

    public function getChildren()
    {
        return $this->children;
    }

    public function addChildren(Role $child, $setParentToChild = true)
    {
        $this->children->add($child);
        $setParentToChild && $child->setParent($this, false);
    }

    public function getDescendant(& $descendants = array())
    {
        foreach ($this->children as $role) {
            $descendants[spl_object_hash($role)] = $role;
            $role->getDescendant($descendants);
        }
        return $descendants;
    }

    public function removeChildren(Role $children)
    {
        $this->children->removeElement($children);
    }

    public function getParent()
    {
        return $this->parent;
    }

    public function setParent(Role $parent, $addChildToParent = true)
    {
        $addChildToParent && $parent->addChildren($this, false);
        $this->parent = $parent;
    }

    public function __toString()
    {
        if ($this->children->count()) {
            $childNameList = array();
            foreach ($this->children as $child) {
                $childNameList[] = $child->getName();
            }
            return sprintf('%s [%s]', $this->name, implode(', ', $childNameList));
        }
        return sprintf('%s', $this->name);
    }
}

Тип Ролевой Формы

use SymfonyComponentFormAbstractType;
use SymfonyComponentFormFormBuilderInterface;
use SymfonyComponentOptionsResolverOptionsResolverInterface;

class RoleType extends AbstractType {

    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
                ->add('name')
                ->add('parent');
    }

    /**
     * @param OptionsResolverInterface $resolver
     */
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'TananeUserBundleEntityRole'
        ));
    }

    /**
     * @return string
     */
    public function getName()
    {
        return 'role';
    }    
}

если да то что добавить в мою форму пользователя будет выглядеть такой

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder
            ->add('username', 'text')
            ->add('email', 'email')
            ->add('enabled', null, array(
                'label' => 'Habilitado',
                'required' => false
            ))
            ->add('rolesCollection', 'entity', array(
                'class' => 'UserBundle:Role',
                'multiple' => true,
                'expanded' => true,
                'attr' => array('class' => 'single-line-checks')
            ))
            ->add('groups', 'entity', array(
                'class' => 'UserBundle:Group',
                'multiple' => true,
                'expanded' => true,
    ));
}

но я не знаю, правильно ли это обрабатывать роли, так как в этом случае будет создавать новую таблицу в моей БД под названием fos_roles где были отношения между пользователями / ролями обрабатываются, но отношения между группами / ролями остаются вне этого, тогда вот где я немного потерян и нуждаюсь в помощи от более опытных в этом, скажите мне и предупредите, если я нахожусь на пути, и это заставит их достичь того, что я объясняю в первых двух пунктах. Любые советы или помочь? Как ты с этим справляешься?

2 ответов


Роли В Symfony

способ FOSUserBundle имеет дело с ролями, чтобы сохранить их в roles столбец, который вы видели, в сериализованном формате, как это:a:1:{i:0;s:10:"ROLE_ADMIN";}. Таким образом, нет необходимости в каких-либо других таблицах или сущностях^.

^ это в отличие от групп, которые должны быть явно настроены, представлены отдельной таблицей / сущностью и включают связанных пользователей с группами в БД. Группы позволяют определить произвольные коллекции Роли, которые затем могут быть даны каждому пользователю в виде дискретного пакета.

пользователь может быть членом любого количества ролей. Они идентифицируются строками, начинающимися с "ROLE_", вы можете просто начать использовать новую роль.

то, что роли означают для вашего приложения, полностью зависит от вас, но они довольно высокоуровневый инструмент-пользователь либо в определенной роли, либо нет.

вы ставите людей в роли либо через в Symfony консоль:

php app/console fos:user:promote testuser ROLE_ADMIN

или в PHP:

$user = $this->getUser();
$userManager = $container->get('fos_user.user_manager');
$user->addRole('ROLE_ADMIN');
$userManager->updateUser($user);

и вы можете проверить членство в PHP:

$user = $this->getUser();
if ($user->hasRole('ROLE_ADMIN'))
{
    //do something
}

или через аннотации:

/**
 * @Security("has_role('ROLE_ADMIN')")
 */
 public function adminAction()
 {
     //...

или

/**
 * @Security("has_role('ROLE_ADMIN')")
 */
class AdminController
{
    //...

Я добавил функциональность для добавления группы по умолчанию пользователю во время регистрации, переопределив confirmAction в Registration Controller

Я перекрытая контроллер регистрация в мой пакет проекта путем определения родителю FosUserBUndle .

затем создал функцию confirmedAction и в тело функции добавил этот код

$repository = $em->getRepository('AdminAdminBundle:Group');
        $group = $repository->findOneByName('staff');

        $em = $this->getDoctrine()->getEntityManager();
        $user = $this->getUser();
        $user->addGroup($group);

        $userManager = $this->get('fos_user.user_manager');

        $userManager->updateUser($user);

        if (!is_object($user) || !$user instanceof FOS\UserBundle\Model\UserInterface) {
            throw new AccessDeniedException('This user does not have access to this section.');
        }

        return $this->render('FOSUserBundle:Registration:confirmed.html.twig', array(
            'user' => $user,
        ));

и он отлично сохраняется в БД с групповым назначением. Надеюсь, это поможет кому-то в нужно так же мало информации о реализации в официальном FOSUserBundle doc.