【问题标题】:Zend Framework 2 - Hydrator strategy for Doctrine relationship not workingZend Framework 2 - Doctrine 关系的 Hydrator 策略不起作用
【发布时间】:2013-01-03 16:00:26
【问题描述】:

正如here 所提到的,我正在构建一个自定义水合策略来处理表单中选择框中的相关对象。

我的表单如下所示:

$builder = new AnnotationBuilder($entityManager);
$form    = $builder->createForm(new MyEntity());
$form->add(new MyFieldSet());

$hydrator = new ClassMethodsHydrator();
$hydrator->addStrategy('my_attribute', new MyHydrationStrategy());
$form->setHydrator($hydrator);

$form->get('my_attribute')->setValueOptions(
      $entityManager->getRepository('SecEntity\Entity\SecEntity')->fetchAllAsArray()
);

当我通过 addAction 添加新的 MyEntity 时,一切正常。

我写了fetchAllAsArray() 来填充我的选择框。它位于我的 SecEntityRepository 中:

public function fetchAllAsArray() {

    $objects = $this->createQueryBuilder('s')
        ->add('select', 's.id, s.name')
        ->add('orderBy', 's.name ASC')
        ->getQuery()
        ->getResult();

    $list = array();
    foreach($objects as $obj) {
        $list[$obj['id']] = $obj['name'];
    }

    return $list;
}

但在编辑情况下,extract() 函数不起作用。我现在还没有看到hydrate() 的内容,所以我暂时将其排除在外。

我的补水策略如下所示:

class MyHydrationStrategy extends DefaultStrategy
{
    public function extract($value) {        
        print_r($value);
        $result = array();
        foreach ($value as $instance) {
            print_r($instance);
            $result[] = $instance->getId();
        }
        return $result;
    }

    public function hydrate($value) {
        ...
    }

问题如下:

致命错误:在非对象上调用成员函数 getId()

print_r($value) 返回大量以

开头的内容

DoctrineORMModule\Proxy__CG__\SecEntity\Entity\SecEntity 对象

接下来是关于 BasicEntityPersister 的一些内容,而混乱中的某处是我引用的实体。

print_r($instance) 不打印任何内容。它只是空的。因此我猜错误消息是合法的......但为什么我不能遍历这些对象?

有什么想法吗?

编辑:

关于@Sam:

我在实体中的属性:

    /**
 * @ORM\ManyToOne(targetEntity="Path/To/Entity", inversedBy="whatever")
 * @ORM\JoinColumn(name="attribute_id", referencedColumnName="id")
 * @Form\Attributes({"type":"hidden"})
 *
 */
protected $attribute;

我的新选择框:

$form->add(array(
        'name'       => 'attribute',
        'type'       => 'DoctrineModule\Form\Element\ObjectSelect',
        'attributes' => array(
            'required' => true
        ),
        'options'    => array(
            'label'           => 'MyLabel',
            'object_manager'  => $entityManager,
            'target_class'    => 'Path/To/Entity',
            'property'        => 'name'
        )
    ));

我最后的希望是我在控制器中做错了什么。我的选择框既没有被预选,也没有保存值...

...

$obj= $this->getEntityManager()->find('Path/To/Entity', $id);

    $builder = new \MyEnity\MyFormBuilder();
    $form = $builder->newForm($this->getEntityManager());

    $form->setBindOnValidate(false);
    $form->bind($obj);
    $form->setData($obj->getArrayCopy());

    $request = $this->getRequest();
    if ($request->isPost()) {
        $form->setData($request->getPost());

        if ($form->isValid()) {
            $form->bindValues();
            $this->getEntityManager()->flush();

            return $this->redirect()->toRoute('entity');
        }
    }

【问题讨论】:

  • 问题:为什么不使用 Doctrine Form Elements?
  • 好一个 :) 我不知道他们的存在我不得不承认......你知道他们的好教程吗?如果他们工作,这是我会说这个问题的合法答案;)

标签: php doctrine-orm zend-form zend-framework2 foreign-key-relationship


【解决方案1】:

我还没有来写教程:S

我不知道这是否适用于注解构建器!因为DoctrineModule\Form\Element\ObjectSelect 需要EntityManager 才能工作。 ObjectSelect 的选项如下:

   $this->add(array(
        'name'       => 'formElementName',
        'type'       => 'DoctrineModule\Form\Element\ObjectSelect',
        'attributes' => array(
            'required' => true
        ),
        'options'    => array(
            'label'           => 'formElementLabel',
            'empty_option'    => '--- choose formElementName ---',
            'object_manager'  => $this->getEntityManager(),
            'target_class'    => 'Mynamespace\Entity\Entityname',
            'property'        => 'nameOfEntityPropertyAsSelect'
        )
    ));

在这种情况下,我使用$this->getEntityManager()。我在从 ServiceManager 调用表单时设置了此依赖项。就我个人而言,我总是从 FactoryClasses 执行此操作。我的 FormFactory 看起来像这样:

public function createService(ServiceLocatorInterface $serviceLocator)
{
    $em = $serviceLocator->get('Doctrine\ORM\EntityManager');

    $form = new ErgebnishaushaltProduktForm('ergebnisform', array(
        'entity_manager' => $em
    ));

    $classMethodsHydrator = new ClassMethodsHydrator(false);

    // Wir fügen zwei Strategien, um benutzerdefinierte Logik während Extrakt auszuführen
    $classMethodsHydrator->addStrategy('produktBereich', new Strategy\ProduktbereichStrategy())
                         ->addStrategy('produktGruppe', new Strategy\ProduktgruppeStrategy());

    $hydrator = new DoctrineEntity($em, $classMethodsHydrator);

    $form->setHydrator($hydrator)
         ->setObject(new ErgebnishaushaltProdukt())
         ->setInputFilter(new ErgebnishaushaltProduktFilter())
         ->setAttribute('method', 'post');

    return $form;
}

这就是所有魔法发生的地方。魔术,这也与您在 SO 上的其他线程相关。首先,我抓住EntityManager。然后我创建我的表单,并注入 EntityManager 的依赖项。我使用自己的表单来执行此操作,您可以编写并使用 Setter-Function 来注入 EntityManager

接下来我创建一个ClassMethodsHydrator 并向其中添加两个HydrationStrategies。我个人需要为每个ObjectSelect-Element 应用这些策略。您可能不必自己这样做。先试试看它是否在没有它的情况下工作!

之后,我创建了DoctrineEntity-Hydrator,注入了EntityManager 以及我的自定义ClassMethodsHydrator。这样可以轻松添加策略。

其余的应该是不言自明的(尽管有德语类名:D)

为什么需要策略

Imo,这是目前DoctrineEntity 中缺少的东西,但事情仍处于早期阶段。一旦DoctrineModule-Issue#106 上线,一切都会再次发生变化,可能会让它更舒适。

策略如下所示:

<?php
namespace Haushaltportal\Stdlib\Hydrator\Strategy;

use Zend\Stdlib\Hydrator\Strategy\StrategyInterface;

class ProduktbereichStrategy implements StrategyInterface
{
    public function extract($value)
    {
        if (is_numeric($value) || $value === null) {
            return $value;
        }

        return $value->getId();
    }

    public function hydrate($value)
    {
        return $value;
    }
}

所以每当$value 不是数字或空值时,意味着:它应该是一个对象,我们将调用getId() 函数。就我个人而言,我认为为每个元素提供自己的策略是个好主意,但如果您确定以后不需要更改策略,您可以为多个元素创建一个全局策略,例如 DefaultGetIdStrategy 或其他.

这一切基本上都是Michael Gallego aka Bakura的好作品!万一你路过IRC,就抱他一次;)

编辑一个带有 look into the future 的附加资源 - 更新了 hydrator-docs,很可能很快就会被包含,拉取请求

【讨论】:

  • 即使没有策略也不会发生错误,一切看起来都很好,但在编辑情况下它不会保存/覆盖外键。即使正确的在POST AND 绑定后的表单中!添加您的策略不会改变它...想法?
  • 您在表单中包含 ID 吗?否则,如果没有整个代码,将很难分辨。
  • 有史以来最奇怪的事情!我更改了我的控制器并将 formElement 值手动设置为我的id 并在bindValues() 之后再次手动设置我的对象。有用...!非常难看,但不幸的是,在那之前我不得不坚持这个解决方案。
  • 抱歉我的回复晚了,睡着了 :D bindValues(),你从数据库中获取对象,例如 $ent = $repo-&gt;find(1),然后通过 $form-&gt;bind($ent) 将其绑定到表单。使用这个 all getter 函数将被调用,用相同的元素名称填充表单。
  • 所以我需要更改我的 getter/setter 以便 FK 处理 id vs object?
猜你喜欢
  • 1970-01-01
  • 2011-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多