10

How can I in ZF2 create custom form element with custom validator? I want to create custom category picker that uses jQuery and content of this element should be rendered from phtml script. In ZF1 it was quite easy but in ZF2 I don't know from where to start.

1 Answer 1

26

A form element must implement a Zend\Form\ElementInterface. A default class is the Zend\Form\Element which you can use as a base form:

<?php
namespace MyModule\Form\Element;

use Zend\Form\Element;

class Foo extends Element
{
}

CUSTOM VALIDATOR

You can let the element directly assign a custom validator. Then you must implement the Zend\InputFilter\InputProviderInterface:

<?php
namespace MyModule\Form\Element;

use Zend\Form\Element;
use Zend\InputFilter\InputProviderInterface;
use MyModule\InputFilter\Bar as BarValidator;

class Foo extends Element implements InputProviderInterface
{
    protected $validator;

    public function getValidator()
    {
        if (null === $this->validator) {
            $this->validator = new BarValidator;
        }
        return $this->validator;
    }

    public function getInputSpecification()
    {
        return array(
            'name'       => $this->getName(),
            'required'   => true,
            'validators' => array(
                $this->getValidator(),
            ),
        );
    }
}

CUSTOM RENDERING

At this moment it is a bit complex how Zend Framework handles the rendering of custom form element types. Usually, it just returns plain <input type="text"> elements.

There is one option, then you have to override the Zend\Form\View\Helper\FormElement helper. It is registered as formelement and you must override this view helper in your custom module:

namespace MyModule;

class Module
{
    public function getViewHelperConfig()
    {
        return array(
            'invokables' => array(
                'formelement' => 'MyModule\Form\View\Helper\FormElement',
                'formfoo'     => 'MyModule\Form\View\Helper\FormFoo',
            ),
        );
    }
}

Furthermore, every form element in Zend Framework 2 is rendered by a view helper. So you create a view helper for your own element, which will render the element's content.

Then you have to create your own form element helper (MyModule\Form\View\Helper\FormElement):

namespace MyModule\Form\View\Helper;

use MyModule\Form\Element;
use Zend\Form\View\Helper\FormElement as BaseFormElement;
use Zend\Form\ElementInterface;

class FormElement extends BaseFormElement
{
    public function render(ElementInterface $element)
    {
        $renderer = $this->getView();
        if (!method_exists($renderer, 'plugin')) {
            // Bail early if renderer is not pluggable
            return '';
        }

        if ($element instanceof Element\Foo) {
            $helper = $renderer->plugin('form_foo');
            return $helper($element);
        }

        return parent::render($element);
    }
}

As a last step, create your view helper to render this specific form element:

namespace MyModule\Form\View\Helper;

use Zend\Form\ElementInterface;
use Zend\Form\View\Helper\AbstractHelper;

class Foo extends AbstractHelper
{
    public function __invoke(ElementInterface $element)
    {
        // Render your element here
    }
}

If you want to render a .phtml file for example for this form element, load it inside this helper:

namespace MyModule\Form\View\Helper;

use Zend\Form\ElementInterface;
use Zend\Form\View\Helper\AbstractHelper;

class Foo extends AbstractHelper
{
    protected $script = 'my-module/form-element/foo';

    public function render(ElementInterface $element)
    {
        return $this->getView()->render($this->script, array(
            'element' => $element
        ));
    }
}

It will render a my-module/form-element/foo.phtml and in this script you will have a variable $element which contains your specific form element.

Sign up to request clarification or add additional context in comments.

9 Comments

I get Catchable fatal error: Argument 1 passed to MyModule\Form\View\Helper\FormElement::render() must be an instance of MyModule\Form\View\Helper\ElementInterface, instance of Zend\Form\Element given
When i'm adding form element it is stil instance of Zend\Form\Element not Element\Foo, i'm adding something like this: $this->add(array( 'name' => 'category', 'attributes' => array( 'type' => 'MyModule\Form\Elemen\Foo', ));
@Maciej you are right, I made two mistakes: in the FormElement view helper you have to import the ElementInterface too, otherwise you get above warning. A second mistake was made in the view helper rendering your custom form element. Check the diff to see the differences, I think this should fix all problems: stackoverflow.com/posts/13776839/revisions
Yes it's better but I still can't render element, probably I'm doing smoething wrong in form class: class MyForm extends Form { public function __construct($name = null) { // we want to ignore the name passed parent::__construct('album'); $this->setAttribute('method', 'post'); $this->add(array( 'name' => 'category', 'attributes' => array( 'type' => 'Element\Foo', ), 'options' => array( 'label' => 'Category', ), )); } }
It used to use the render() method. Now all form view helpers apparently had an overhaul so it doesn't work anymore. I edited the answer as render() should just be renamed to __invoke()
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.