1

我在多对一关系上使用 Doctrine 的 ObjectSelect 时遇到了一些麻烦。

我在下面使用 ManyToMany 的关系可以 100% 添加和编辑。我的编辑表单填充了当前选择,没有任何问题。

问题出现在 ManyToOne 关系中,似乎表单没有填充当前选择。

在将任务实体绑定到表单之前,我尝试转储它,它看起来 100% 正确,我的所有关系都填充在实体中。

但是,在绑定它之后,显示的表单没有选择当前值。

任务实体:

/**
 * @ORM\Entity
 * @ORM\Table(name="tasks")
 */
class Task
{

        /**
         * @ORM\Id
         * @ORM\Column(type="integer");
         * @ORM\GeneratedValue(strategy="AUTO")
         */
        protected $id;
    ...
        /**
         * @ORM\ManyToOne(targetEntity="Category")
         * @ORM\JoinColumn(name="category_id", referencedColumnName="id")
         */
        protected $category;
    ...    
        /**
         * @ORM\ManyToMany(targetEntity="ZDUser\Entity\User")
         * @ORM\JoinTable(name="tasks_assigned_user_linker",
         *        joinColumns={@ORM\JoinColumn(name="task_id", referencedColumnName="id")},
         *        inverseJoinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")}
         * )
         */
        protected $assignedUsers;

        /**
         * Initialize
         */
        public function __construct()
        {
                $this->assignedUsers = new ArrayCollection();
        }

        /**
         * We need a few getters and setters
         */
        public function getId()
        {
                return $this->id;
        }
        public function setId($id)
        {
                $this->id = $id;
        }

        public function getCategory() {
                return $this->category;
        }
        public function setCategory(Category $category) {
                $this->category = $category;
        }

        public function getAssignedUsers() {
                return $this->assignedUsers;
        }
        public function addAssignedUsers(Collection $users) {
                foreach ($users as $user) {
                        $this->assignedUsers->add($user);
                }
        }
        public function removeAssignedUsers(Collection $users) {
                foreach ($users as $user) {
                        $this->assignedUsers->removeElement($user);
                }
        }
}

我在我的大多数实体中都使用 ManyToOne,我发现这种方式更容易和可扩展。我可以添加其他实体并将它们链接到其他实体,而无需在双方都建立关系。

类别实体

/**
 * @ORM\Entity
 * @ORM\Table(name="task_categories")
 * @property int $id
 * @property string $name
 */
class Category
{
        /**
         * @ORM\Id
         * @ORM\Column(type="integer");
         * @ORM\GeneratedValue(strategy="AUTO")
         */
        protected $id;

        /**
         * @ORM\Column(type="string", nullable=false)
         */
        protected $name;
  ...
        /**
         * Setters and getters we need
         */
        public function getId()
        {
                return $this->id;
        }
        public function setId($id)
        {
        $this->id = (int) $id;
        }

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

}

用户实体:

/**
 * @ORM\Entity
 * @ORM\Table(name="users")
 */
class User implements UserInterface, ProviderInterface
{
        /**
         * @ORM\Id
         * @ORM\Column(type="integer")
         * @ORM\GeneratedValue(strategy="AUTO")
         */
        protected $id;
    ...
        /**
         * @ORM\ManyToMany(targetEntity="ZDUser\Entity\Group")
         * @ORM\JoinTable(name="users_groups_linker",
         *        joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")},
         *        inverseJoinColumns={@ORM\JoinColumn(name="group_id", referencedColumnName="id")}
         * )
         */
        protected $groups;

        /**
         * Initialies the object
         */
        public function __construct()
        {
                $this->groups = new ArrayCollection();
        }

        /* Getters and setters, we must define these for the implementation to work */
        public function getId()
        {
                return $this->id;
        }
        public function setId($id)
        {
                $this->id = (int) $id;
        }

        /* Get and add groups */
        public function getGroups()
        {
            return $this->groups;
        }
        public function addGroup(Group $group)
        {
            $this->groups->add($group);
        }

表格代码:

class TaskForm extends Form implements ObjectManagerAwareInterface
{
        protected $objectmanager;

        public function __construct(EntityManager $em)
        {
                // we want to ignore the name passed
                parent::__construct('task');


                $this->setHydrator(new DoctrineHydrator($em,'TaskList\Entity\Task'));

                $this->setAttribute('method', 'post');
                $this->add(array(
                        'name' => 'id',
                        'attributes' => array(
                                'type'  => 'hidden',
                        ),
                ));

                $this->add(array(
                        'name' => 'subject',
                        'type'  => 'Text',
                        'options' => array(
                                'label' => 'Subject',
                        ),
                ));

                $this->add(array(
                        'name' => 'category',
                        'type' => 'DoctrineModule\Form\Element\ObjectSelect',
                        'options' => array(
                                'label' => "Category",
                                'object_manager' => $em,
                                'target_class' => 'TaskList\Entity\Category',
                                'property' => 'name',
                        ),
                ));


                $this->add(array(
                        'name' => 'assignedUsers',
                        'type' => 'DoctrineModule\Form\Element\ObjectSelect',
                        'attributes' => array(
                                'multiple' => 'multiple',
                        ),
                        'options' => array(
                                'label' => "Assigned To (User)",
                                'object_manager' => $em,
                                'target_class' => 'ZDUser\Entity\User',
                                'property' => 'email',
                        ),
                ));

编辑和添加控制器:

    public function addAction()
    {
            $this->addedit();

            // Grab form
            $form = new TaskForm($this->getEntityManager());

            // Grab any request we may have
            $request = $this->getRequest();

            // If it a post ...
            if ($request->isPost()) {
                    $task = new Task();
                    $form->bind($task);

                    // Populate data
                    $form->setData($request->getPost());

                    // Check if the form is valid
                    if ($form->isValid()) { 
                            // Setup some things we need
                            $task->setCreated(new \DateTime("now"));

                            // Save
                            $this->getEntityManager()->persist($task);
                            $this->getEntityManager()->flush();

                            // Redirect to list of tasks
                            return $this->redirect()->toRoute('tasklist'); 
                    }
            }

            return array(
                    'form' => $form
            );
    }


    public function editAction()
    {
            $this->addedit();

            // Get ID or redirect
            $id = (int)$this->getEvent()->getRouteMatch()->getParam('id');
            if (!$id) {
                    return $this->redirect()->toRoute('tasklist');
            }

            // Create a form
            $form = new TaskForm($this->getEntityManager());

            // Grab entity from doctrine
            $task = $this->getEntityManager()->find('TaskList\Entity\Task', $id);

            // Bind the form to the task 
            $form->bind($task);

            // Check if we have a request and if its POST
            $request = $this->getRequest();

            if ($request->isPost()) {
                    // If it is, set the form data from the request
                    $form->setData($request->getPost());

                    // If the form is valid, bind the values
                    if ($form->isValid()) {
                            // Setup some things we need
                            $task->setLastUpdated(new \DateTime("now"));

                            // Flush the update
                            $this->getEntityManager()->flush();

                            // Redirect to list of tasks
                            return $this->redirect()->toRoute('tasklist');
                    }
            }

            return array(
                    'id' => $id,
                    'form' => $form,
            );
    }

我很确定我错过了一些非常简单的东西。

4

2 回答 2

0

我遇到了类似的问题,有关更多信息,请参阅 DoctrineORMModule GitHub 上的这个问题。

这与 Doctrine 在加载代理实体时未从元数据返回正确的 ID 字段有关。解决方案如下:

  1. 等待 Doctrine 2.4 中的官方修复(您现在可以安装 2.4-beta2!)。
  2. 将 ObjectSelect 子类化以强制使用正确的 ID 字段(前面​​链接的问题中有人这样做)。
  3. 用这个修补 DoctrineModule:

    --- doctrine/doctrine-module/src/DoctrineModule/Form/Element/Proxy.php  2013-03-11 17:49:55.406011600 -0300
    +++ doctrine/doctrine-module/src/DoctrineModule/Form/Element/Proxy.php  2013-03-11 17:51:33.592710900 -0300
    @@ -240,7 +240,10 @@
                     if (count($identifier) > 1) {
                         //$value = $key;
                     } else {
    -                    $value = current($metadata->getIdentifierValues($value));
    +                    // Doctrine has a bug that makes the following not work, 
    +                    // this is a horrible workaround until Doctrine 2.4 is released with a fix.
    +                    //$value = current($metadata->getIdentifierValues($value));
    +                    $value = $value->getId();
                     }
                 }
             }
    

$value->getId()依赖于相应实体中可用的该方法。不建议这样做,但可以快速修复。

于 2013-06-14T07:16:53.857 回答
0

可能不是正确的方法?我将我的想法发布到他们的 ML :) 可能不是正确的方法?我将我的想法发布到他们的 ML :)

diff --git a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php
index cba525a..2f62375 100644
--- a/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php
+++ b/vendor/doctrine/orm/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php
@@ -667,7 +667,17 @@ class ClassMetadataInfo implements ClassMetadata
             return $id;
         }

-        $value = $this->reflFields[$this->identifier[0]]->getValue($entity);
+
+               /**
+                * NK: First try use the getter, in the case of a proxied object, the reflection is not going to work
+                * as the proxied object does not have any properties
+                */
+               $getter = 'get' . ucfirst($this->identifier[0]);
+               if (method_exists($entity, $getter)) {
+                       $value = $entity->$getter();
+               } else {
+               $value = $this->reflFields[$this->identifier[0]]->getValue($entity);
+               }
于 2013-06-14T12:37:07.143 回答