0

私はエンティティとしてのような役割とそのような多対多の関係のためのカスタムハンドラーを持っています:

<?php

namespace Digital\UserBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\Role\RoleInterface;


    /**
     * Role Entity
     *
     * @ORM\Entity
     * @ORM\Table( name="app_roles" )
     */
    class Role implements RoleInterface
    {

        /**
         * @ORM\Id
         * @ORM\Column(type="integer", name="id")
         * @ORM\GeneratedValue(strategy="AUTO")
         */
        private $id;

        /**
         * @ORM\Column(type="string", name="name", unique=true, length=100)
         */
        private $role;

        /**
         * @var Role
         * @ORM\ManyToOne(targetEntity="Role")
         * @ORM\JoinColumn(name="parent_id", referencedColumnName="id")
         **/
        private $parent;


        /**
         * @param $role
         */
        public function __construct($role)
        {
            $this->role = (string)$role;
        }


        /**
         * @return string
         */
        public function __toString()
        {
            return $this->role;
        }


        /**
         * @param $role
         */
        public function setRole($role)
        {
            $this->role = $role;
        }


        /**
         * @return string
         */
        public function getRole()
        {
            return $this->role;
        }


        /**
         * @param Role $parent
         *
         * @return $this
         */
        public function setParent(Role $parent)
        {
            $this->parent = $parent;
            return $this;
        }


        /**
         * @return Role
         */
        public function getParent()
        {
            return $this->parent;
        }


        /**
         * @return bool
         */
        public function hasParent()
        {
            return null !== $this->parent;
        }

    }

次に、ユーザーオブジェクトを次のように構成します。

<?php
// src/Acme/UserBundle/Entity/User.php

namespace Digital\UserBundle\Entity;

use FOS\UserBundle\Entity\User as BaseUserOld;
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\ArrayCollection;
use FOS\MessageBundle\Model\ParticipantInterface;
use Symfony\Component\HttpFoundation\File\File;

use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Constraints\Email;
use Symfony\Component\Validator\Constraints\NotBlank;

/**
 * @ORM\Entity
 * @ORM\Table(name="app_users")
 * @ORM\Entity(repositoryClass="Digital\UserBundle\EntityRepository\UserRepository")
 */
class User extends BaseUser implements ParticipantInterface
{
    // properties...


    /**
     * @ORM\ManyToMany(targetEntity="Role", indexBy="name")
     * @ORM\JoinTable(name="app_users_roles")
     */
    protected $roles;

    /**
     * Construct.
     */
    public function __construct()
    {
        parent::__construct();

        $this->roles       = new ArrayCollection;
    }


    /**
     * @return Role[]
     */
    public function getRoles()
    {
        $roles   = $this->getRolesCollection()->toArray();
        $roles[] = $this->getDefaultRole();
        return $roles;
    }


    /**
     * @param $role
     *
     * @return bool
     */
    public function hasRole($role)
    {
        if ($role instanceof Role) {
            $role = $role->getRole();
        }

        foreach ($this->getRoles() as $roleEntity) {
            if ($roleEntity->getRole() === $role) {
                return true;
            }
        }

        return false;
    }


    /**
     * @param $role
     *
     * @return self
     * @throws \InvalidArgumentException
     */
    public function addRole($role)
    {
        $this->normaliseRole($role);

        if ($this->hasRole($role)) {
            throw new \InvalidArgumentException("Role $role is already applied to this " . get_class($this));
        }

        $this->getRolesCollection()->add($role);

        return $this;
    }


    /**
     * @param Role|string $role
     *
     * @return self
     */
    public function removeRole($role)
    {
        $this->normaliseRole($role);
        $this->getRolesCollection()->removeElement($role);
        return $this;
    }


    /**
     * @param Role[]|string[] $roles
     *
     * @return self
     */
    public function setRoles(array $roles)
    {
        $this->getRolesCollection()->clear();

        foreach ($roles as $role) {
            $this->addRole($role);
        }

        return $this;
    }


    /**
     * {@inheritdoc}
     */
    protected function getRolesCollection()
    {
        return $this->roles;
    }


    /**
     * {@inheritdoc}
     */
    protected function getDefaultRole()
    {
        return new Role(parent::ROLE_DEFAULT);
    }


    /**
     * @param $role
     *
     * @throws \InvalidArgumentException
     */
    protected function normaliseRole(&$role)
    {
        if (is_string($role)) {
            $role = new Role($role);
        }

        if (!$role instanceof Role) {
            throw new \InvalidArgumentException('Role must be either a Role Entity or a string.');
        }
    }
}

今私の質問は、インターフェイスに従ってオブジェクトの配列を受け入れるようにフォームを構成するにはどうすればよいですか?

コレクション/エンティティ/選択を使用しますか?すべてが失敗しているようです...

    $builder->add('roles', 'entity', array(
        'class' => 'Digital\UserBundle\Entity\Role',
        'by_reference' => true,)
    );

キャッチ可能な致命的なエラー:Digital \ UserBundle \ Entity \ User :: setRoles()に渡される引数1は、配列型である必要があり、オブジェクトが指定されています

ヒントをいただければ幸いです...

これも機能しません:

    $builder->add('roles', 'collection', array(
        'type' => new RoleType(),
        'allow_add'    => true,
        'allow_delete' => true,
        'by_reference' => false,
    ));

また:

    $builder->add('roles', 'collection', 
        array( 'options' => array(
            'data_class' => 'Digital\UserBundle\Entity\Role'),
            'allow_add' => true, 
            'allow_delete' => true, 
            'by_reference' => false));

これを機能させることができるクローゼットは次のとおりです。

    public function addRole($role)
    {
        $this->normaliseRole($role);

//        if (!$this->roles->contains($role)) {
        if (!$this->hasRole($role)) {
            $this->getRolesCollection()->add($role);
        }

        return $this;
    }

        $builder->add('roles', 'collection', array( 'options' => array('data_class' => 'Digital\UserBundle\Entity\Role'),
            'allow_add' => true, 'allow_delete' => true, 'by_reference' => false));

このようにして、エラーなしでフォームを送信できますが、カスケード永続化を追加する必要があり、このロールはすでにロールテーブルにあり、Doctrineが再度挿入しようとしているため、変更は失敗します。

4

2 に答える 2

1

これに対する答えは次のとおりです。

    $builder->add('rolesCollection', 'entity', array(
        'multiple'     => true,
        'expanded'     => true,
        'by_reference' => false,
        'label' => 'Roles',
        'class'        => 'Digital\UserBundle\Entity\Role',
    ));

そして、「roles」ではなく「rolesCollection」で遊んでいます。

/**
 * @param Collection $collection
 */
public function setRolesCollection($collection)
{
    $this->setRoles($collection->toArray());

    return $this;
}
于 2013-03-30T11:59:06.163 に答える
0

collectionタイプを使ってみましたか?typeは、 1つの関連オブジェクトをentity意味します。

http://symfony.com/doc/current/cookbook/form/form_collections.html

于 2013-03-25T22:11:25.193 に答える