Zend Framework 2使用Doctrine作为Hydrator的表单问题

时间:2015-03-29 22:50:02

标签: php forms doctrine-orm zend-framework2

我遇到的问题比我列出的更多问题,试图找出& @#$ *&使用用于填充数据的表单使Zetr 2中的Doctrine工作。 (可用的文档叮咬!!!)

我只是尝试从特定表/实体中的记录中填充简单的选择列表。实体只有两个属性。 ID和名称。我希望值为ID,选项innerHTML文本为名称。没问题。

我正在尝试编写表单的主要对象称为'列表'并有3个属性。 ListId,TypeId和ListName。在Doctrine中,Type和Types对象的多对一关系是我想要用于选择器的关系。 (属性:TypeId和TypeName)

我创建了一个基本表单,并设置了一个控制器操作,以便使用FormElementManager通过服务管理器检索它。然后我将它绑定到实体的实例。最后,如果提供了ListId,我将在绑定之前检索该记录,但是现在,我只是创建一个新的(空)Lists对象。

问题1:

首先,我尝试使用ZF2文档中几乎逐行的字段集。当我使用服务定位器识别代码创建我的字段集时,它获取getServiceLocator()方法,根据我看到的许多引用,它返回表单上下文中的FormElementManager。因此建议在FormElementManager上再次调用getServiceLocator()以获取Zend中的实际服务定位器。该方法存在,但返回' null'来自我的Fieldset。我在form_elements:

下的modules.config.php中定义了form和fieldset
'form_elements' => array(
    'invokables' => array(
        'listForm' => 'Application\Form\ListForm',
        'typeFieldset' => 'Application\Form\Fieldset\TypeFieldset'
    )
)

我从表单(在init()函数中)引用fieldset,如下所示:

    $this->add(
        array(
            'name' => 'Type',
            'type' => 'typeFieldset',
            'options' => array(
                'label' => 'List Type',
            ),
            'attributes' => array(
                'required' => 'required'
            )
        )
    );

如果我无法访问完整的服务管理员,我就无法使用Doctrine正确填充字段集。

问题2:

我找到了另一个例子,建议将服务定位器感知代码移到表单然后使用Doctrine作为加氢器。我有一个工作,并按照我的意愿填充字段,并使用回调函数正确填写标签。

    $this->add(
        array(
            'name' => 'TypeId',
            'type' => 'DoctrineORMModule\Form\Element\DoctrineEntity',
            'options' => array(
                'label'          => 'Type',
                'object_manager' => $entityManager,
                'target_class'   => 'Application\Entity\Types',
                'property'       => 'TypeId',
                'label_generator' => function($targetEntity) {
                    return $targetEntity->getTypeId() . ' - ' . $targetEntity->getTypeName();
                },
                'display_empty_item' => true,
                'empty_item_label'   => '---',
                'find_method' => array(
                    'name'   => 'findBy',
                    'params' => array(
                        'criteria' => array(),
                        'orderBy'  => array('TypeId' => 'ASC'),
                    ),
                ),
            ),
        )
    );

这导致我开始使用Id的输入来预填充表单。问题是Id字段是有条件的,如果Id为空,则会导致问题。我假设Id的隐藏字段需要设置为条件,或者我需要在水合器尝试存储结果之前有条件地解析它。我似乎无法找到有关如何执行此操作的任何文档。 目前,我通过添加“addId”来修复了一个问题。如果ListId是一个参数并且是对应于现有记录的有效Integer,我可以从控制器调用的形式的方法。

public function editlistAction() {
    $listId = $this->params()->fromRoute('id', '');

    $form = $this->getForm('listForm');

    $list = null;
    if(!empty($listId) && (intval($listId) > 0)) {
        $list = $this->getMapper()->findRecordById($listId);
        $form->addId($listId); // function that adds hidden element
    } else {
        $list = new \Application\Entity\Lists();
    }

    $form->bind($list);

    if ($this->request->isPost()) {
        // do something with the result
    }

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

如果$ form->有(' ListId')返回true,我只会尝试在视图中添加隐藏元素。有更好的方法吗?

问题3:

在视图中,如果我只是回显$ this-> formCollection($ form);它会显示所有正确的字段,但是没有格式化和丑陋。所以我试图找出如何逐场进行,以便我可以围绕它们进行格式化。

当我尝试使用echo $ this-> formCollection($ form-> get(' ListId'))(或任何其他字段名称)时,我一直收到错误' undefined方法'对于类型:: getIterator()(例如未定义的方法Zend .... \ Hidden :: getIterator())。 所以我尝试直接调用各种装饰器,例如:$ this-> formText($ form-> get(' ListName'));但这会丢弃标签字段。互联网上是否有一个很好的例子,说明如何正确格式化Zend Framework 2表格,而这种表格在希腊语中不像猪拉丁语那样读取?

问题4:

所以我使用了丑陋的表单,看看我是否可以使后端功能正常工作。我添加到控制器操作的唯一事情是检查$ form-> isValid()(目前我还没有设置任何验证器),如果为true,则转储绑定对象。 当我这样做时,它再次呕吐 - 去看看。似乎有一个问题,即表单中的一个绑定参数被称为' submit'。我是否真的必须在某个地方进行水合之前手动从标准表单元素中删除参数和/或更改基本建议的“exchangeArray()'实体中的方法忽略它们?说真的!?!?!如果有办法删除它们,在哪里? (我甚至不能100%确定实际发生的水合作用)如果没有,我该如何避免这种情况影响Zend / Doctrine水合作用?

我已经在这里工作了6个多小时,我的浏览器上打开了大约30个标签(不包括我已关闭的120左右)并且今天做了更多谷歌搜索而不是我记得。看起来每个人每个步骤都略有不同,并且没有一个明确的来源可以找到一个好的,基本的,如何。 (我坐在那里,茫然地看着一个Zend Framework文档页面,该页面继续为80%的页面设置一个非常蹩脚的对象集,用于描述如何将它绑定到装饰器,只是在实现它之前关于ZF1 呻吟

非常感谢任何帮助。我有大约二十多个白发,我的血压上升了大约30分,我的声音因为对显示器大喊大叫而声音嘶哑。

1 个答案:

答案 0 :(得分:2)

好的,首先,在与ORM实体合作时,不要将您的关联视为关系数据库级别(即此实体具有另一个实体的ID),但将它们视为域对象关系

这意味着在$typeId实体中拥有List属性是错误的。您应该拥有$type类型的Type属性,因为List有一个Type,而不是typeId

其次,实施ServiceLocatorAwareInterface 强烈建议不要。除非您进行原型设计并且尚未定义依赖关系图,否则您不应使用此界面。
使用构造函数依赖注入,您将拥有更清晰的结构。

现在,根据经验,每个实体应该有一个字段集,但是你的里程可能会有所不同(对于非常简单的实体,你可以使用一个学说形式元素,因为你实际上正在做)。然后,您可以在将字段集添加到表单之前,使用Zend\Form\Fieldset::setUseAsBaseFieldset()将字段集设置为表单的基本字段。

因此,在您的情况下,您将拥有一个ListForm,其中包含ListFieldset基本字段集,该字段集的DoctrineEntity字段的名称设置为type,其值将由水化器映射到List::$type

显然不要忘记相应地设置所有学说水槽:要设置基础场集水化器,你应该在添加基础田野集后在表格上调用setHydrator()

要迭代表单/字段集/集合的元素,您可以使用getIterator()方法,虽然我没有在您的示例中看到任何集合元素,所以它不清楚是什么您正尝试与formCollection视图助手完全一致。 Collection元素旨在用于"许多"}关系的一面,而你所描述的形式是针对"一个"侧。 顺便说一句,您可以在单个元素上使用form视图助手或formRow来对输出进行细粒度控制。

对于隐藏的id字段问题,由于您已经通过route参数检索它,因此您实际上并不需要在表单中使用它。 ;)