【发布时间】:2014-04-24 23:36:07
【问题描述】:
我正在使用 Doctrine 的类表继承映射策略开发一个项目,该策略涉及根据父表中鉴别器列中的值将父表与多个子表之一连接起来。我有一个工作原型,其中唯一的综合字段集每个都包含来自父实体的公共元素的所有代码的重复副本。为了确保一致性并避免过多代码,我想更改字段集,以便我有一个与父实体相关的单个字段集,所有其他字段集只是父实体的扩展(详细说明包含在 How to Extend a Fieldset in ZF2 )。当我分离字段集然后尝试让它们相互协作时遇到了问题。
How to Extend a Fieldset in ZF2 问题的第一个答案清楚地解释了单个字段集如何在 ZF2 中扩展另一个字段集。但是,答案使用init() 来组合字段集,而对于 Doctrine 策略,我们需要使用__construct。我开发字段集的第一个步骤是构建DoctrineModule/docs 中规定的一些代码,这将我们带到了这一点:
class FieldsetParent extends Zend\Form\Fieldset
{
public function __construct(ObjectManager $objectManager) {
parent::__construct('parent-fieldset');
$this->setHydrator(new DoctrineHydrator($objectManager, 'MyModule\Entity\Parent'))
->setObject(new Parent());
$this->add(array('name' => 'fieldA'));
$this->add(array('name' => 'fieldB'));
$this->add(array('name' => 'fieldC'));
}
}
还有这个:
class FieldsetFoo extends FieldsetParent
{
public function __construct(ObjectManager $objectManager) {
parent::__construct('foo-fieldset');
$this->setHydrator(new DoctrineHydrator($objectManager, 'MyModule\Entity\Foo'))
->setObject(new Foo());
$this->add(array('name' => 'fieldD'));
$this->add(array('name' => 'fieldE'));
$this->add(array('name' => 'fieldF'));
$this->add(array('name' => 'fieldG'));
}
}
这不起作用,因为它尝试从字符串添加字段集,并给出错误消息:
Catchable fatal error: Argument 1 passed to MyModuule\Form\ParentFieldset::__construct()
must implement interface Doctrine\Common\Persistence\ObjectManager, string given ...
zend2 doctrine 2 form intgergration OneToOne 问题的第一个答案解释了在 OneToOne 策略的情况下如何避免从字符串中添加字段集。但是,我正在使用不同的 ORM 策略,并且在解决相同问题时遇到了困难。
编辑
根据要求,这里有一些更详细的信息:
class FooController extends AbstractActionController
{
/**
* @var Doctrine\ORM\EntityManager
*/
protected $em;
public function setEntityManager(EntityManager $em)
{
$this->em = $em;
return $this;
}
public function getEntityManager()
{
if (null === $this->em) {
$this->em = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
}
return $this->em;
}
// ... //
public function editAction()
{
$fooID = (int)$this->getEvent()->getRouteMatch()->getParam('fooID');
if (!$fooID) {
return $this->redirect()->toRoute('foo', array('action'=>'add'));
}
$foo = $this->getEntityManager()->find('MyModule\Entity\Foo', $fooID);
// Get your ObjectManager from the ServiceManager
$objectManager = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
// Create the form and inject the ObjectManager
$form = new EditFooForm($objectManager);
$form->setBindOnValidate(false);
$form->bind($foo);
$form->get('submit')->setAttribute('label', 'Update');
$request = $this->getRequest();
if ($request->isPost()) {
$form->setData($request->getPost());
if ($form->isValid()) {
$form->bindValues();
$this->getEntityManager()->flush();
return $this->redirect()->toRoute('foo');
}
}
return array(
'foo' => $foo,
'form' => $form,
);
}
}
和
class EditFooForm extends Form
{
public function __construct(ObjectManager $objectManager)
{
parent::__construct('edit_foo_form');
$this->setHydrator(new DoctrineHydrator($objectManager, 'MyModule\Entity\Foo'));
$fooFieldset = new FooFieldset($objectManager);
$fooFieldset->setUseAsBaseFieldset(true);
$this->add($fooFieldset);
// submit elements
}
}
此字段集有效:
class FooFieldset extends Fieldset implements InputFilterProviderInterface
{
public function __construct(ObjectManager $objectManager)
{
parent::__construct('foo-fieldset');
$this->setHydrator(new DoctrineHydrator($objectManager, 'MyModule\Entity\Foo'))
->setObject(new Foo());
$this->add(array('name' => 'fieldA'));
$this->add(array('name' => 'fieldB'));
$this->add(array('name' => 'fieldC'));
$this->add(array('name' => 'fieldD'));
$this->add(array('name' => 'fieldE'));
$this->add(array('name' => 'fieldF'));
$this->add(array('name' => 'fieldG'));
}
public function getInputFilterSpecification()
{
return array('fieldA' => array('required' => false),);
return array('fieldB' => array('required' => false),);
return array('fieldC' => array('required' => false),);
return array('fieldD' => array('required' => false),);
return array('fieldE' => array('required' => false),);
return array('fieldF' => array('required' => false),);
return array('fieldG' => array('required' => false),);
}
}
这些字段集给出错误消息:
class FoobarFieldset extends Fieldset implements InputFilterProviderInterface
{
public function __construct(ObjectManager $objectManager)
{
parent::__construct('foobar-fieldset');
$this->setHydrator(new DoctrineHydrator($objectManager, 'MyModule\Entity\Foobar'))
->setObject(new Foobar());
$this->add(array('name' => 'fieldA'));
$this->add(array('name' => 'fieldB'));
$this->add(array('name' => 'fieldC'));
}
public function getInputFilterSpecification()
{
return array('fieldA' => array('required' => false),);
return array('fieldB' => array('required' => false),);
return array('fieldC' => array('required' => false),);
}
}
和
use MyModule\Form\FoobarFieldset;
class FooFieldset extends FoobarFieldset implements InputFilterProviderInterface
{
public function __construct(ObjectManager $objectManager)
{
parent::__construct('foo-fieldset');
$this->setHydrator(new DoctrineHydrator($objectManager, 'MyModule\Entity\Foo'))
->setObject(new Foo());
$this->add(array('name' => 'fieldD'));
$this->add(array('name' => 'fieldE'));
$this->add(array('name' => 'fieldF'));
$this->add(array('name' => 'fieldG'));
}
public function getInputFilterSpecification()
{
return array('fieldD' => array('required' => false),);
return array('fieldE' => array('required' => false),);
return array('fieldF' => array('required' => false),);
return array('fieldG' => array('required' => false),);
}
}
产生的错误信息是:
Catchable fatal error: Argument 1 passed to MyModule\Form\FoobarFieldset::__construct()
must implement interface Doctrine\Common\Persistence\ObjectManager, string given, called
in C:\xampp\htdocs\GetOut\module\MyModule\src\MyModule\Form\FooFieldset.php on line 17
and defined in C:\xampp\htdocs\GetOut\module\MyModule\src\MyModule\Form\FoobarFieldset.php
on line 14
我试图通过进行这些更改来避免从字符串中添加字段集:
use MyModule\Form\FoobarFieldset;
class FooFieldset extends Fieldset implements InputFilterProviderInterface
{
public function __construct(ObjectManager $objectManager)
{
parent::__construct('foo-fieldset');
$this->setHydrator(new DoctrineHydrator($objectManager, 'MyModule\Entity\Foo'))
->setObject(new Foo());
$this->add(array('name' => 'fieldD'));
$this->add(array('name' => 'fieldE'));
$this->add(array('name' => 'fieldF'));
$this->add(array('name' => 'fieldG'));
$fieldset = new FoobarFieldset($objectManager);
$this->add($fieldset);
}
但这会给出带有消息No element by the name of [fieldA] found in form 的Zend\Form\Exception\InvalidElementException,表明未添加文件集。
另一种选择
说到底,我真正想做的就是将所有常用语句保存在一个地方,并将它们绘制到需要包含它们的各种独特字段集中。我可以在没有 ZF2 的情况下使用 include 语句解决这个问题,如下所示:
// FoobarFieldset_fields.php
$this->add(array('name' => 'fieldA'));
$this->add(array('name' => 'fieldB'));
$this->add(array('name' => 'fieldC'));
和
// FoobarFieldset_filters.php
return array('fieldA' => array('required' => false),);
return array('fieldB' => array('required' => false),);
return array('fieldC' => array('required' => false),);
和
class FooFieldset extends Fieldset implements InputFilterProviderInterface
{
public function __construct(ObjectManager $objectManager)
{
parent::__construct('foo-fieldset');
$this->setHydrator(new DoctrineHydrator($objectManager, 'MyModule\Entity\Foo'))
->setObject(new Foo());
include 'FoobarFieldset_fields.php';
$this->add(array('name' => 'fieldD'));
$this->add(array('name' => 'fieldE'));
$this->add(array('name' => 'fieldF'));
$this->add(array('name' => 'fieldG'));
}
public function getInputFilterSpecification()
{
include 'FoobarFieldset_filters.php';
return array('fieldD' => array('required' => false),);
return array('fieldE' => array('required' => false),);
return array('fieldF' => array('required' => false),);
return array('fieldG' => array('required' => false),);
}
}
【问题讨论】:
-
您是否在
getFormElementConfig中为Fieldsets添加了工厂?在我看来,服务管理器将其创建为invokable(如果您在将字段集添加到表单并且没有注册工厂时使用 FQCN,这将自动发生)。请使用工厂类/闭包以及添加字段集的表单更新您的问题。 -
我能够让类表继承映射策略与一个实体一起扩展另一个实体,然后通过单个字段集将数据传递给表单。对于那个模型,我不需要使用
getFormElementConfig。只有当我将字段集分成两个(一个扩展另一个)时,我才会遇到问题。我假设问题在于我如何进行参考。我已编辑问题以包含更多信息。
标签: doctrine-orm doctrine zend-framework2