Zend框架2 - Hydrator关于Doctrine关系的策略不起作用 [英] Zend Framework 2 - Hydrator strategy for Doctrine relationship not working

查看:93
本文介绍了Zend框架2 - Hydrator关于Doctrine关系的策略不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此处所述,我正在构建一个自定义水合策略,以一种形式的选择框中处理我的相关对象

As mentioned here I'm building a custom hydration strategy to handle my related objects in a select box in a form.

我的表单如下所示:

$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()
);

当我添加一个新的 MyEntity 通过 addAction 一切都很好。

When I add a new MyEntity via the addAction everything works great.

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

I wrote fetchAllAsArray() to populate my selectbox. It lives within my 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(),所以我现在就把它留下来。

But in the edit-case the extract() function doesn't work. I'm not at the point where I see something of hydrate() so I'll leave it out for now.

我的hydrator策略如下所示:

My hydrator strategy looks like this:

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( )

Fatal error: Call to a member function getId() on a non-object

print_r($ value)返回负载以$开头的东西

The print_r($value) returns loads of stuff beginning with


DoctrineORMModule\Proxy__CG__\SecEntity\Entity\SecEntity Object

DoctrineORMModule\Proxy__CG__\SecEntity\Entity\SecEntity Object

以下是关于BasicEntityPersister的某些东西,而在某些地方,我的引用实体是。

following with something about BasicEntityPersister and somewhere in the mess are my referenced entities.

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

The print_r($instance) prints nothing. It's just empty. Therefore I guess is the error message legit... but why can't I iterate over these objects?

任何想法?

编辑:

关于@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'
        )
    ));

我最后的希望是我在控制器内做错了事情。我的选择框都没有被选中,也没有保存这个值...

My final hope is that I'm doing something wrong within the controller. Neither my selectbox is preselected nor the value is saved...

...

$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');
        }
    }


推荐答案

仍然没有到这里写教程:S

I still haven't come around to write the tutorial for that :S

我不知道这是否与注释工具一起使用!由于 DoctrineModule\Form\Element\ObjectSelect 需要 EntityManager 才能正常工作。 ObjectSelect 的选项如下:

I don't know if this is working with the annotationbuilder though! As the DoctrineModule\Form\Element\ObjectSelect needs the EntityManager to work. The options for the ObjectSelect are as follows:

   $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看起来像这样:

In this case i make use of $this->getEntityManager(). I set up this dependency when calling the form from the ServiceManager. Personally i always do this from FactoryClasses. My FormFactory looks like this:

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;
}

这是所有的魔法都在发生的地方。魔术,这也是与你的其他线程在这里相关。首先,我抓住 EntityManager 。然后我创建我的表单,并为 EntityManager 注入依赖项。我使用我自己的表单,你可以写和使用Setter-Function来注入 EntityManager

And this is where all the magic is happening. Magic, that is also relevant to your other Thread here on SO. First, i grab the EntityManager. Then i create my form, and inject the dependency for the EntityManager. I do this using my own Form, you may write and use a Setter-Function to inject the EntityManager.

接下来,我创建一个 ClassMethodsHydrator ,并向其添加两个 HydrationStrategies 。个人我需要为每个 ObjectSelect -Element应用这些策略。您可能不需要在您身边执行此操作。尝试看看它是否工作没有它首先!

Next i create a ClassMethodsHydrator and add two HydrationStrategies to it. Personally i need to apply those strategies for each ObjectSelect-Element. You may not have to do this on your side. Try to see if it is working without it first!

之后,我创建了 DoctrineEntity -Hydrator,注入 EntityManager 以及我的自定义 ClassMethodsHydrator 。这样一来,策略就会很容易地被添加。

After that, i create the DoctrineEntity-Hydrator, inject the EntityManager as well as my custom ClassMethodsHydrator. This way the Strategies will be added easily.

其余的应该是非常不言自明的(尽管有德文类别:D)

The rest should be quite self-explanatory (despite the german classnames :D)

为什么需要策略

Imo,这是从 DoctrineEntity ,但事情还处于早期阶段。一旦 DoctrineModule-Issue#106 将会生活,事情会再次改变,可能会使它更舒适。

Imo, this is something missing from the DoctrineEntity currently, but things are still in an early stage. And once DoctrineModule-Issue#106 will be live, things will change again, probably making it more comfortable.

策略如下所示:

<?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 不是数字或空值,意思是:它应该是一个Object,我们将调用 getId()函数。就个人而言,我认为给每个Element都是自己的策略是一个好主意,但是如果你确定你不需要在以后改变这个策略,你就可以创建一个全局策略,这些元素就像 DefaultGetIdStrategy 或某事。

So whenever the $value is not numeric or null, meaning: it should be an Object, we will call the getId() function. Personally i think it's a good idea to give each Element it's own strategy, but if you are sure you won't be needing to change the strategy at a later point, you could create a global Strategy for several elements like DefaultGetIdStrategy or something.

所有这一切基本上都是 Michael Gallego又名Bakura !如果你放在IRC,只要拥抱他一次;)

All this is basically the good work of Michael Gallego aka Bakura! In case you drop by the IRC, just hug him once ;)

修改另外一个资源,一个查看未来 - 更新的hydrator-docs很可能,很快被包括,拉请求

Edit An additional resource with a look into the future - updated hydrator-docs for a very likely, soon to be included, pull request

这篇关于Zend框架2 - Hydrator关于Doctrine关系的策略不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆