changing ZF2 form behavior when retrieving form

196 Views Asked by At

I'm wondering if there is a way to either pass additional parameters to the constructor (preferred) or retrieve the Request object to check the headers from within the Form constructor so that when I do a getForm in a controller, the form will be customized depending on how it is called?

I'm working on integrating AngularJs bindings and model tags into my form elements but I will need to modify how the submit button works whenever a form is called from Ajax vs being pulled into a Zend template via the framework.

Thus I would like to throw conditional parameters around where the submit button is added to the form, but I need to know if the rendered form is being viewed in zend or is being sent via an ajax call. I can detect the ajax call in the controller by looking at the request headers with isXmlHttpRequest(), but I'm not sure how to let the form know what the controller saw when it's retrieving the form with $this->getForm()

2

There are 2 best solutions below

3
On

You can inject any options you like using a factory class.

use MyModule\Form\MyForm;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\ServiceManager\FactoryInterface;

class MyFormFactory implements FactoryInterface
{
    public function createService(ServiceLocatorInterface $formElementManager)
    {
        $serviceManager = $formElementManager->getServiceLocator();
        $request = $serviceManager->get('Request');

        // I would recommend assigning the data
        // from the request to the options array
        $options = [
            'is_ajax' => $request->isXmlHttpRequest(),
        ];

        // Although you could also pass in the request instance into the form
        return new MyForm('my_form', $options, $request);
    }
}

If you inject the request you will need modify MyForm::__construct.

namespace MyModule\Form;

use Zend\Form\Form;
use Zend\Http\Request as HttpRequest;

class MyForm extends Form
{
    protected $request;

    public function __construct($name, $options, HttpRequest $request)
    {
        $this->request = $request;

        parent::__construct($name, $options);
    }
}

Update your module.config.php to use the factory

return [
    'form_elements' => [
        'factories' => [
            'MyModule\Form\MyForm' => 'MyModule\Form\MyFormFactory'
        ]
    ]
]

Then ensure you request the form from the service manager (in a controller factory)

$myForm = $serviceManager->get('FormElementManager')->get('MyModule\Form\MyForm');
1
On

My AbstractForm with helper functions (I just added the getRequest() to the bottom). Of course in a wider scale application I'd probably add error checking to make sure these were not called from the constructor (when the service manager would not yet be available)

namespace Application\Form;

use Zend\Form\Form as ZendForm;
use Zend\Http\Request as HttpRequest;
use Zend\Stdlib\RequestInterface as Request;
use Zend\Form\FormElementManager as ZendFormElementManager;
use Zend\ServiceManager\ServiceLocatorAwareInterface as ZendServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface      as ZendServiceLocatorInterface;
use Doctrine\ORM\EntityManager as DoctrineEntityManager

class AbstractForm extends ZendForm implements ZendServiceLocatorAwareInterface {

    /**
     * @var Request
     */
    protected $request;

    /**
     * in form context this turns out to be Zend\Form\FormElementManager
     *
     * @var ZendFormElementManager $service_manager
     */
    protected static $service_manager;

    /**
     * @var DoctrineEntityManager $entity_manager
     */
    protected $entity_manager;

    /**
     * @var ZendServiceLocatorInterface $service_locator_interface
     */
    protected $service_locator_interface;

    public function __construct($name = null)
    {
        parent::__construct($name);
    }

    /**
     * in form context this turns out to be Zend\Form\FormElementManager
     *
     * @param ZendFormElementManager $serviceLocator
     */
    public function setServiceLocator(FormElementManager $serviceLocator)
    {
        self::$service_manager = $serviceLocator;
    }

    /**
     * in form context this turns out to be Zend\Form\FormElementManager
     *
     * @return ZendFormElementManager
     */
    public function getServiceLocator()
    {
        return self::$service_manager;
    }

    /**
     * wrapper for getServiceLocator
     * @return ZendFormElementManager
     */
    protected function getFormElementManager() {
        return $this->getServiceLocator();
    }

    /**
     * this returns an actual service aware interface
     *
     * @return ZendServiceLocatorInterface
     */
    protected function getServiceManager() {
        if(!($this->service_locator_interface instanceof ZendServiceLocatorInterface)) {
            $this->service_locator_interface = $this->getFormElementManager()->getServiceLocator();
        }
        return $this->service_locator_interface;
    }

    /**
     * @return DoctrineEntityManager
     */
    protected function getEntityManager() {
        if(!($this->entity_manager instanceof \DoctrineEntityManager)) {
            $this->entity_manager = $this->getServiceLocator()->getServiceLocator()->get('Doctrine\ORM\EntityManager');
        }
        return $this->entity_manager;
    }

    /**
     * Get request object
     *
     * @return Request
     */
    public function getRequest()
    {
        if (!$this->request) {
            $this->request = $this->getServiceManager()->get('Request');
        }

        return $this->request;
    }
}