我在ManyToOne关系中使用Doctrine的ObjectSelect时遇到了一些麻烦。
下面我使用ManyToMany工作的关系100%添加和编辑。我的编辑表单填充了当前选择,没有任何问题。
问题出现在ManyToOne关系中,似乎表单没有填充当前选择。
我尝试在将它绑定到表单之前转储Task实体,它看起来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,我发现这种方式更容易和可扩展。我可以添加addtional实体并将它们链接到其他实体,而无需双方都做关系。
类别实体
/**
* @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,
);
}
我很确定我错过了一些非常简单的东西。
答案 0 :(得分:0)
我遇到了类似的问题,请参阅DoctrineORMModule GitHub上的this issue以获取更多信息。
在加载代理实体时,Doctrine没有从元数据返回正确的ID字段。解决方案如下:
修补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()
依赖于相应实体中可用的方法。这不是推荐的,而是快速修复。
答案 1 :(得分: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);
+ }