Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use collections in a fieldset factory in ZF2

I am developing a project with ZF2 and Doctrine. I am attempting to use Doctrine Hydrator in the form creation as shown in this tutorial. In this method, an ObjectManager object is created in the controller and passed to the new form when it is instantiated. Passing the ObjectManager object from the controller to the form creates a problem when I want to use ZF2's FormElementManager because ZF2 requires that I get an instance of the form class through the Zend\Form\FormElementManager instead of directly instantiating it. To work around this requirement, I have created form and fieldset factories based upon the answer to the question How to pass a Doctrine ObjectManager to a form through ZF2 FormElementManager. The method presented in the answer to the question works for typical fieldset elements, but I need to determine how to include a collection element. The tutorial uses the ObjectManager object in the collection element in the parent fieldset, and I need to figure out how to add the collection using a factory.

TagFieldset from the tutorial that I am trying to emulate:

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

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

BlogPostFieldset from the tutorial that I am trying to emulate:

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

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

in module.config.php:

'form_elements' => [
    'factories' => [
        'UpdateBlogPostForm' => 'Application\Form\UpdateBlogPostFormFactory',
        'BlogPostFieldset' => 'Application\Form\BlogPostFieldsetFactory',
        'TagFieldset' => 'Application\Form\TagFieldsetFactory',
    ],
],

When I add the fieldset elements In my new BlogPostFieldsetFactory I replace this code from the original fieldset:

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

with this:

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

How do I replace the collection element from the original fieldset:

$tagFieldset = new TagFieldset($objectManager);
$this->add(array(
        'type'    => 'Zend\Form\Element\Collection',
        'name'    => 'tags',
        'options' => array(
                'count'           => 2,
                'target_element' => $tagFieldset
        )
));
like image 969
jcropp Avatar asked Jan 08 '16 19:01

jcropp


1 Answers

maybe i'm getting your question wrong.... but if you replaced this

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

whith this:

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

then you probably can replace this:

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

with this:

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

now, if you cant pass the $objectManger to the form... well if you look at the code you have this thing available $serviceManager, that thing looks like a DI container, im sure you can get the $objectManager instance from there, and if is not available, you can probably put an instance of it inside.

So de final code probably ending looks like this:

$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
        )
));
like image 169
Javier Neyra Avatar answered Nov 06 '22 05:11

Javier Neyra