如何在ZF2中的fieldset工厂中使用集合

jcr*_*opp 12 php forms factory doctrine-orm zend-framework2

我正在用ZF2和Doctrine开发一个项目.我试图在表单创建中使用Doctrine Hydrator,如本教程所示.在此方法中,将在控制器中创建ObjectManager对象,并在实例化时将其传递给新表单.当我想使用ZF2的FormElementManager时,将ObjectManager对象从控制器传递到表单会产生问题,因为ZF2要求我通过Zend\Form\FormElementManager获取表单类的实例,而不是直接实例化它.为了解决这个问题,我已经基于如何通过ZF2 FormElementManager将Doctrine ObjectManager传递给表单的问题的答案创建了表单和字段集工厂..该问题的答案中提供的方法适用于典型的fieldset元素,但我需要确定如何包含集合元素.本教程使用父字段集中的collection元素中的ObjectManager对象,我需要弄清楚如何使用工厂添加集合.

我试图模仿的教程中的TagFieldset:

namespace Application\Form;

use Application\Entity\Tag;
use Doctrine\Common\Persistence\ObjectManager;
use DoctrineModule\Stdlib\Hydrator\DoctrineObject as DoctrineHydrator;
use Zend\Form\Fieldset;
use Zend\InputFilter\InputFilterProviderInterface;

class TagFieldset extends Fieldset implements InputFilterProviderInterface
{
    public function __construct(ObjectManager $objectManager)
    {
        parent::__construct('tag');

        $this->setHydrator(new DoctrineHydrator($objectManager))
             ->setObject(new Tag());

        $this->add(array(
            'type' => 'Zend\Form\Element\Hidden',
            'name' => 'id'
        ));

        $this->add(array(
            'type'    => 'Zend\Form\Element\Text',
            'name'    => 'name',
            'options' => array(
                'label' => 'Tag'
            )
        ));
    }

    public function getInputFilterSpecification()
    {
        return array(
            'id' => array(
                'required' => false
            ),

            'name' => array(
                'required' => true
            )
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

新的TagFieldsetFactory:

namespace Application\Form;

use Zend\Form\Fieldset;
use Application\Entity\Tag;

class TagFieldsetFactory
{
    public function __invoke($formElementManager, $name, $requestedName)
    {
        $serviceManager = $formElementManager->getServiceLocator();
        $hydrator = $serviceManager->get('HydratorManager')->get('DoctrineEntityHydrator');

        $fieldset = new Fieldset('tags');
        $fieldset->setHydrator($hydrator);
        $fieldset->setObject(new Tag);

        //... add fieldset elements.
        $fieldset->add(['...']);
        //...

        return $fieldset;
    }
}
Run Code Online (Sandbox Code Playgroud)

我试图模仿的教程中的BlogPostFieldset:

namespace Application\Form;

use Application\Entity\BlogPost;
use Doctrine\Common\Persistence\ObjectManager;
use DoctrineModule\Stdlib\Hydrator\DoctrineObject as DoctrineHydrator;
use Zend\Form\Fieldset;
use Zend\InputFilter\InputFilterProviderInterface;

class BlogPostFieldset extends Fieldset implements InputFilterProviderInterface
{
    public function __construct(ObjectManager $objectManager)
    {
        parent::__construct('blog-post');

        $this->setHydrator(new DoctrineHydrator($objectManager))
             ->setObject(new BlogPost());

        $this->add(array(
            'type' => 'Zend\Form\Element\Text',
            'name' => 'title'
        ));

        $tagFieldset = new TagFieldset($objectManager);
        $this->add(array(
            'type'    => 'Zend\Form\Element\Collection',
            'name'    => 'tags',
            'options' => array(
                'count'           => 2,
                'target_element' => $tagFieldset
            )
        ));
    }

    public function getInputFilterSpecification()
    {
        return array(
            'title' => array(
                'required' => true
            ),
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

新的BlogPostFieldsetFactory:

namespace Application\Form;

use Zend\Form\Fieldset;
use Application\Entity\BlogPost;

class BlogPostFieldsetFactory
{
    public function __invoke($formElementManager, $name, $requestedName)
    {
        $serviceManager = $formElementManager->getServiceLocator();
        $hydrator = $serviceManager->get('HydratorManager')->get('DoctrineEntityHydrator');

        $fieldset = new Fieldset('blog_post');
        $fieldset->setHydrator($hydrator);
        $fieldset->setObject(new BlogPost);

        //... add fieldset elements.
        $fieldset->add(['...']);
        //...

        return $fieldset;
    }
}
Run Code Online (Sandbox Code Playgroud)

在module.config.php中:

'form_elements' => [
    'factories' => [
        'UpdateBlogPostForm' => 'Application\Form\UpdateBlogPostFormFactory',
        'BlogPostFieldset' => 'Application\Form\BlogPostFieldsetFactory',
        'TagFieldset' => 'Application\Form\TagFieldsetFactory',
    ],
],
Run Code Online (Sandbox Code Playgroud)

当我添加fieldset元素在我的新BlogPostFieldsetFactory中,我从原始字段集中替换此代码:

$this->add(array(
        'type' => 'Zend\Form\Element\Text',
        'name' => 'title'
));
Run Code Online (Sandbox Code Playgroud)

有了这个:

$fieldset->add(array(
        'type' => 'Zend\Form\Element\Text',
        'name' => 'title'
));
Run Code Online (Sandbox Code Playgroud)

如何从原始字段集中替换集合元素:

$tagFieldset = new TagFieldset($objectManager);
$this->add(array(
        'type'    => 'Zend\Form\Element\Collection',
        'name'    => 'tags',
        'options' => array(
                'count'           => 2,
                'target_element' => $tagFieldset
        )
));
Run Code Online (Sandbox Code Playgroud)

小智 4

也许我弄错了你的问题......但如果你更换了这个

$this->add(array(
        'type' => 'Zend\Form\Element\Text',
        'name' => 'title'
));
Run Code Online (Sandbox Code Playgroud)

与此:

$fieldset->add(array(
        'type' => 'Zend\Form\Element\Text',
        'name' => 'title'
));
Run Code Online (Sandbox Code Playgroud)

那么你可能可以替换它:

$tagFieldset = new TagFieldset($objectManager);
$this->add(array(
        'type'    => 'Zend\Form\Element\Collection',
        'name'    => 'tags',
        'options' => array(
                'count'           => 2,
                'target_element' => $tagFieldset
        )
));
Run Code Online (Sandbox Code Playgroud)

有了这个:

$tagFieldset = new TagFieldset($objectManager);
$fieldset->add(array(
        'type'    => 'Zend\Form\Element\Collection',
        'name'    => 'tags',
        'options' => array(
                'count'           => 2,
                'target_element' => $tagFieldset
        )
));
Run Code Online (Sandbox Code Playgroud)

现在,如果你无法将 $objectManger 传递到表单...那么,如果你查看代码,你会发现这个东西可用 $serviceManager,那个东西看起来像一个 DI 容器,我确信你可以从那里获取 $objectManager 实例,如果不可用,您可以将其实例放入其中。

所以最终代码可能的结局如下:

$objectManager =  $serviceManager->get('DoctrineObjectManager') //or something like this
$tagFieldset = new TagFieldset($objectManager);
$fieldset->add(array(
        'type'    => 'Zend\Form\Element\Collection',
        'name'    => 'tags',
        'options' => array(
                'count'           => 2,
                'target_element' => $tagFieldset
        )
));
Run Code Online (Sandbox Code Playgroud)