How can I access Database Adapter in ZF2 Field Set?
Asked Answered
B

2

15

I have followed an example and would like to pass the Database adapter to a fieldset to create a drop down menu.

The code below is how i call the fieldset.
How can i access the database adapter in the BrandFieldset class?

$this->add(array(
    'type' => 'Application\Form\BrandFieldset',
    'name' => 'brand',
    'options' => array(
        'label' => 'Brand of the product',
    ),
));
Bechuana answered 21/1, 2017 at 17:41 Comment(0)
B
1

Based of these docs I was able to find a solution.

https://framework.zend.com/manual/2.1/en/modules/zend.form.advanced-use-of-forms.html

'form_elements' => array(
    'invokables' => array(
        'fieldset' => BrandFieldsetFactory::class
    )
)

I needed to call the form using the service locator in the controller like below.

$sl = $this->getServiceLocator();
$form = $sl->get('FormElementManager')->get('Application\Form\CreateForm');

In addition I changed the __construct to init.

Bechuana answered 2/5, 2017 at 22:6 Comment(0)
B
3

Instantiating a fieldset is responsibility of the FormElementManager. When you try to access a form, form element or fieldset, the FormElementManager knows where to find and how to create it. This behaviour summerized in Default Services section of the framework.

Since the proper way of accessing form elements is retrieving them from FormElementManager, I would write a BrandFieldsetFactory to inject that DB adapter or further dependencies to fieldset on construction to achieve this.

A ZF3 friendly fieldset factory would look like:

<?php
namespace Application\Form\Factory;

use Application\Form\BrandFieldset;
use Interop\Container\ContainerInterface;

class BrandFieldsetFactory
{
    /**
     * @return BrandFieldset
     */
    public function __invoke(ContainerInterface $fem, $name, array $options = null)
    {
        // FormElementManager is child of AbstractPluginManager 
        // which makes it a ContainerInterface instance
        $adapter = $fem->getServiceLocator()->get('Your\Db\Adapter');
        return new BrandFieldset($adapter);
    }
}

At this point, BrandFieldset should extend the Zend\Form\Fieldset\Fieldset and it's constructor may look like following:

private $dbAdapter;

/**
 * {@inheritdoc}
 */
public function __construct(My/Db/Adapter $db, $options = [])
{
    $this->dbAdapter = $db;
    return parent::__construct('brand-fieldset', $options);
}

Finally, in module.config.php file I'd have a configuration to tell FormElementManager about this factory:

<?php

use Application\Form\BrandFieldset;
use Application\Form\Factory\BrandFieldsetFactory;

return [
    // other config

    // Configuration for form element manager
    'form_elements' => [
        'factories' => [
            BrandFieldset::class => BrandFieldsetFactory::class
        ],
    ],
];

HINT: The BrandFieldset::init() method will be called automatically by FormElementManager after construction. You can put any post-initialization logic into this method.

Bibber answered 4/2, 2017 at 23:28 Comment(4)
Can this be used in ZF2? I'm having trouble getting it to work.Bechuana
Sure, after make the factory ZF2 friendly, it should work. Just add a createService() method into the factory just like other zf2 factories and call _invoke from that method.Bibber
I'm not sure what you mean. If I var dump the $db in the fieldset I get the name of the class ("brandfieldset"). It doesn't look like the factory is ever called (if I exit or var dump in the factory nothing happends)Bechuana
The Factory never seems to get called. public function __invoke(ContainerInterface $fem, $name, array $options = null) { echo 'does this work'; exit; // FormElementManager is child of AbstractPluginManager // which makes it a ContainerInterface instance $adapter = $fem->getServiceLocator()->get('Your\Db\Adapter'); return new BrandFieldset($adapter); }Bechuana
B
1

Based of these docs I was able to find a solution.

https://framework.zend.com/manual/2.1/en/modules/zend.form.advanced-use-of-forms.html

'form_elements' => array(
    'invokables' => array(
        'fieldset' => BrandFieldsetFactory::class
    )
)

I needed to call the form using the service locator in the controller like below.

$sl = $this->getServiceLocator();
$form = $sl->get('FormElementManager')->get('Application\Form\CreateForm');

In addition I changed the __construct to init.

Bechuana answered 2/5, 2017 at 22:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.