diff --git a/.gitignore b/.gitignore index 4cac0a21..673fe323 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,9 @@ .*.sw* .*.un~ nbproject +doc/html/ tmp/ +zf-mkdoc-theme/ clover.xml coveralls-upload.json diff --git a/.travis.yml b/.travis.yml index f0c24082..cf5f4485 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,19 +4,26 @@ language: php branches: except: - - /^release-.*$/ + - /^release-\d+\.\d+\.\d+.*$/ - /^ghgfk-.*$/ cache: directories: - $HOME/.composer/cache - vendor + - $HOME/.local + - zf-mkdoc-theme env: global: - COMPOSER_ARGS="--no-interaction --ignore-platform-reqs" - TESTS_ZEND_FORM_ANNOTATION_SUPPORT=true - TESTS_ZEND_FORM_RECAPTCHA_SUPPORT=true + - SITE_URL: https://zendframework.github.io/zend-form + - GH_USER_NAME: "Matthew Weier O'Phinney" + - GH_USER_EMAIL: matthew@weierophinney.net + - GH_REF: github.com/zendframework/zend-form.git + - secure: "H5t5GcHDEX230xPN0QvXAkKzziCdYb+YQ9EFCsD+hJLm1kdYKmg7NbBibPIr86js01iiVB+q2OZQ+pk6kIigSmNu/zeBR2q2zJYKbOUTGvAGj0pIsje7XpZr/FcSOHUOtm/8yHD8z3KNoood4au3Zsmr8D2bbGvqLe3ZfwFmzIsPTFmB5IvfvHiN4j6NsOP9rGlLzp93Gquv1XSHjuvM2Lr8Jbornf5JVqXaHgIniTRlBzckIcwhaMJKRUjT0jxAnKEZKa9NLkRaj40g+pFDVXxJwq7/5gDj+g7684lbSToZU29ye/akvk1KAkGeXE6f/CYqn/1qi2cfMyFRuwzCaLbKTci7EQBho0iWp39eq/jVT/+XpUKDJikW0xJZYnUMd78uZBseE8iNUdaLojoVUYkOaAevIjr+VaF0j1GWmgcChN2NHyCOj++PNZBLovfL6d2RPUFD82vo6oA6MvtsuZDfEV9F1mWNHcDkb7PgS0Yh6Ag+47iRKptb0nMGgthE2ErieNE7CX1kp0u4tjSQK44XSYP4ObAGCo/Wuxl6xxlgwEYCqGOr+Tu2g2s0R4ocQVsWeRlvKBVdQr5peVxOMcK5Zj15sK9BQ1gjINf6IcpEeh0Tg1Cf9Cy8PwPds/Ym7lc6jv71c0LUCZiLQ/hTkd1euCG3ykzkQ9CEGt+ESLc=" matrix: fast_finish: true @@ -37,6 +44,8 @@ matrix: - php: 5.6 env: - DEPS=locked + - DEPLOY_DOCS="$(if [[ $TRAVIS_BRANCH == 'master' && $TRAVIS_PULL_REQUEST == 'false' ]]; then echo -n 'true' ; else echo -n 'false' ; fi)" + - PATH="$HOME/.local/bin:$PATH" - php: 5.6 env: - DEPS=latest @@ -80,6 +89,10 @@ script: - if [[ $TEST_COVERAGE == 'true' ]]; then composer test-coverage ; fi - if [[ $TEST_COVERAGE != 'true' ]]; then composer test ; fi - if [[ $CS_CHECK == 'true' ]]; then composer cs-check ; fi + - if [[ $DEPLOY_DOCS == "true" && "$TRAVIS_TEST_RESULT" == "0" ]]; then wget -O theme-installer.sh "https://raw.githubusercontent.com/zendframework/zf-mkdoc-theme/master/theme-installer.sh" ; chmod 755 theme-installer.sh ; ./theme-installer.sh ; fi + +after_success: + - if [[ $DEPLOY_DOCS == "true" ]]; then echo "Preparing to build and deploy documentation" ; ./zf-mkdoc-theme/deploy.sh ; echo "Completed deploying documentation" ; fi after_script: - if [[ $TEST_COVERAGE == 'true' ]]; then composer upload-coverage ; fi diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b0cb847..07792e40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,7 +24,8 @@ All notable changes to this project will be documented in this file, in reverse ### Added -- Nothing. +- [#70](https://github.com/zendframework/zend-form/pull/70) adds and publishes + the documentation to https://zendframework.github.io/zend-form/ ### Deprecated diff --git a/book/zend.form.advanced-use-of-forms.md b/book/zend.form.advanced-use-of-forms.md deleted file mode 100644 index 295fd741..00000000 --- a/book/zend.form.advanced-use-of-forms.md +++ /dev/null @@ -1,466 +0,0 @@ -# Advanced use of forms - -Beginning with Zend Framework 2.1, forms elements can be registered using a designated plugin -manager of Zend\\\\ServiceManager <zend.service-manager.intro>. This is similar to how view -helpers, controller plugins, and filters are registered. This new feature has a number of benefits, -especially when you need to handle complex dependencies in forms/fieldsets. This section describes -all the benefits of this new architecture in ZF 2.1. - -## Short names - -The first advantage of pulling form elements from the service manager is that now you can use short -names to create new elements through the factory. Therefore, this code: - -```php -$form->add(array( - 'type' => 'Zend\Form\Element\Email', - 'name' => 'email' -)); -``` - -can now be replaced by: - -```php -$form->add(array( - 'type' => 'Email', - 'name' => 'email' -)); -``` - -Each element provided out-of-the-box by Zend Framework 2 support this natively, so you can now make -your initialization code more compact. - -## Creating custom elements - -`Zend\Form` also supports custom form elements. - -To create a custom form element, make it extend the `Zend\Form\Element` class, or if you need a more -specific one, extend one of the `Zend\Form\Element` classes. - -In the following we will show how to create a custom `Phone` element for entering phone numbers. It -will extend `Zend\Form\Element` class and provide some default input rules. - -Our custom phone element could look something like this: - -```php -namespace Application\Form\Element; - -use Zend\Form\Element; -use Zend\InputFilter\InputProviderInterface; -use Zend\Validator\Regex as RegexValidator; - -class Phone extends Element implements InputProviderInterface -{ - /** - * @var ValidatorInterface - */ - protected $validator; - - /** - * Get a validator if none has been set. - * - * @return ValidatorInterface - */ - public function getValidator() - { - if (null === $this->validator) { - $validator = new RegexValidator('/^\+?\d{11,12}$/'); - $validator->setMessage('Please enter 11 or 12 digits only!', - RegexValidator::NOT_MATCH); - - $this->validator = $validator; - } - - return $this->validator; - } - - /** - * Sets the validator to use for this element - * - * @param ValidatorInterface $validator - * @return Application\Form\Element\Phone - */ - public function setValidator(ValidatorInterface $validator) - { - $this->validator = $validator; - return $this; - } - - /** - * Provide default input rules for this element - * - * Attaches a phone number validator. - * - * @return array - */ - public function getInputSpecification() - { - return array( - 'name' => $this->getName(), - 'required' => true, - 'filters' => array( - array('name' => 'Zend\Filter\StringTrim'), - ), - 'validators' => array( - $this->getValidator(), - ), - ); - } -} -``` - -By implementing the `Zend\InputFilter\InputProviderInterface` interface, we are hinting to our form -object that this element provides some default input rules for filtering and/or validating values. -In this example the default input specification provides a `Zend\Filter\StringTrim` filter and a -`Zend\Validator\Regex` validator that validates that the value optionally has a + sign at the -beginning and is followed by 11 or 12 digits. - -The easiest way of start using your new custom element in your forms is to use the custom element's -FQCN: - -```php -$form = new Zend\Form\Form(); -$form->add(array( - 'name' => 'phone', - 'type' => 'Application\Form\Element\Phone', -)); -``` - -Or, if you are extending `Zend\Form\Form`: - -```php -namespace Application\Form; - -use Zend\Form\Form; - -class MyForm extends Form -{ - public function __construct($name = null) - { - parent::__construct($name); - - $this->add(array( - 'name' => 'phone', - 'type' => 'Application\Form\Element\Phone', - )) - } -} -``` - -If you don't want to use the custom element's FQCN, but rather a short name, as of Zend Framework -2.1 you can do so by adding them to the `Zend\Form\FormElementManager` plugin manager by utilising -the `getFormElementConfig` function. - -> ## Warning -To use custom elements with the FormElementManager needs a bit more work and most likely a change in -how you write and use your forms. - -First, add the custom element to the plugin manager, in your `Module.php` class: - -```php -namespace Application; - -use Application\Form\Element\Phone; -use Zend\Form\ElementFactory; -use Zend\ModuleManager\Feature\FormElementProviderInterface; - -class Module implements FormElementProviderInterface -{ - public function getFormElementConfig() - { - return [ - 'aliases' => [ - 'phone' => Phone::class, - ], - 'factories' => [ - Phone::class => ElementFactory::class, - ], - ]; - } -} -``` - -Or, you can do the same in your `module.config.php` file: - -```php -return [ - 'form_elements' => [ - 'aliases' => [ - 'phone' => Phone::class, - ], - 'factories' => [ - Phone::class => ElementFactory::class, - ], - ], -]; -``` - -`ElementFactory` is the default factory for form elements. Use your own if you need to handle dependencies in your -elements/fieldsets/forms. - -**And now comes the first catch.** - -If you are creating your form class by extending `Zend\Form\Form`, you *must not* add the custom -element in the `__construct`-or (as we have done in the previous example where we used the custom -element's FQCN), but rather in the `init()` method: - -```php -namespace Application\Form; - -use Zend\Form\Form; - -class MyForm extends Form -{ - public function init() - { - $this->add(array( - 'name' => 'phone', - 'type' => 'Phone', - )); - } -} -``` - -**The second catch** is that you *must not* directly instantiate your form class, but rather get an -instance of it through the `Zend\Form\FormElementManager`: - -```php -namespace Application\Controller; - -use Zend\Mvc\Controller\AbstractActionController; - -class IndexController extends AbstractActionController -{ - public function indexAction() - { - $sl = $this->getServiceLocator(); - $form = $sl->get('FormElementManager')->get('\Application\Form\MyForm'); - return array('form' => $form); - } -} -``` - -The biggest gain of this is that you can easily override any built-in Zend Framework form elements -if they do not fit your needs. For instance, if you want to create your own Email element instead of -the standard one, you can simply create your element and add it to the form element config with the -same key as the element you want to replace: - -```php -namespace Application; - -use Application\Form\Element\MyEmail; -use Zend\Form\ElementFactory; -use Zend\ModuleManager\Feature\FormElementProviderInterface; - -class Module implements FormElementProviderInterface -{ - public function getFormElementConfig() - { - return [ - 'aliases' => [ - 'email' => MyEmail::class, - ], - 'factories' => [ - MyEmail::class => ElementFactory::class, - ], - ]; - } -} -``` - -Now, whenever you'll create an element whose `type` is 'email', it will create the custom Email -element instead of the built-in one. - -> ## Note -if you want to be able to use both the built-in one and your own one, you can still provide the FQCN -of the element, i.e. `Zend\Form\Element\Email`. - -As you can see here, we first get the form manager (that we modified in our Module.php class), and -create the form by specifying the fully qualified class name of the form. Please note that you don't -need to add `Application\Form\MyForm` to the invokables array. If it is not specified, the form -manager will just instantiate it directly. - -In short, to create your own form elements (or even reusable fieldsets !) and be able to use them in -your form using the short-name notation, you need to: - -1. Create your element (like you did before). -2. Add it to the form element manager by defining the `getFormElementConfig`, exactly like using -`getServiceConfig()` and `getControllerConfig`. -3. Make sure the custom form element is not added in the form's `__construct`-or, but rather in -it's `init()` method, or after getting an instance of the form. -4. Create your form through the form element manager instead of directly instantiating it. - -## Handling dependencies - -One of the most complex issues in `Zend\Form 2.0` was dependency management. For instance, a very -frequent use case is a form that creates a fieldset, that itself need access to the database to -populate a `Select` element. Previously in such a situation, you would either rely on the Registry -using the Singleton pattern, or either you would "transfer" the dependency from controller to form, -and from form to fieldset (and even from fieldset to another fieldset if you have a complex form). -This was ugly and not easy to use. Hopefully, `Zend\ServiceManager` solves this use case in an -elegant manner. - -For instance, let's say that a form create a fieldset called `AlbumFieldset`: - -```php -namespace Application\Form; - -use Zend\Form\Form; - -class CreateAlbum extends Form -{ - public function init() - { - $this->add(array( - 'name' => 'album', - 'type' => 'AlbumFieldset' - )); - } -} -``` - -Let's now create the `AlbumFieldset` that depends on an `AlbumTable` object that allows you to fetch -albums from the database. - -```php -namespace Application\Form; - -use Album\Model\AlbumTable; -use Zend\Form\Fieldset; - -class AlbumFieldset extends Fieldset -{ - public function __construct(AlbumTable $albumTable) - { - // Add any elements that need to fetch data from database - // using the album table ! - } -} -``` - -For this to work, you need to add a line to the form element manager by adding an element to your -Module.php class: - -```php -namespace Application; - -use Application\Form\AlbumFieldset; -use Zend\ModuleManager\Feature\FormElementProviderInterface; - -class Module implements FormElementProviderInterface -{ - public function getFormElementConfig() - { - return array( - 'factories' => array( - 'AlbumFieldset' => function($sm) { - // I assume here that the Album\Model\AlbumTable - // dependency have been defined too - - $serviceLocator = $sm->getServiceLocator(); - $albumTable = $serviceLocator->get('Album\Model\AlbumTable'); - $fieldset = new AlbumFieldset($albumTable); - return $fieldset; - } - ) - ); - } -} -``` - -Create your form using the form element manager instead of directly instantiating it: - -```php -public function testAction() -{ - $formManager = $this->serviceLocator->get('FormElementManager'); - $form = $formManager->get('Application\Form\CreateAlbum'); -} -``` - -Finally, to use your fieldset in a view you need to use the formCollection function. - -```php -echo $this->form()->openTag($form); -echo $this->formCollection($form->get('album')); -echo $this->form()->closeTag(); -``` - -Et voilĂ ! The dependency will be automatically handled by the form element manager, and you don't -need to create the `AlbumTable` in your controller, transfer it to the form, which itself passes it -over to the fieldset. - -## The specific case of initializers - -In the previous example, we explicitly defined the dependency in the constructor of the -`AlbumFieldset` class. However, in some cases, you may want to use an initializer (like -`Zend\ServiceManager\ServiceLocatorAwareInterface`) to inject a specific object to all your -forms/fieldsets/elements. - -The problem with initializers is that they are injected AFTER the construction of the object, which -means that if you need this dependency when you create elements, it won't be available yet. For -instance, this example **won't work**: - -```php -namespace Application\Form; - -use Album\Model; -use Zend\Form\Fieldset; -use Zend\ServiceManager\ServiceLocatorAwareInterface; -use Zend\ServiceManager\ServiceLocatorInterface; - -class AlbumFieldset extends Fieldset implements ServiceLocatorAwareInterface -{ - protected $serviceLocator; - - public function __construct() - { - // Here, $this->serviceLocator is null because it has not been - // injected yet, as initializers are run after __construct - } - - public function setServiceLocator(ServiceLocatorInterface $sl) - { - $this->serviceLocator = $sl; - } - - public function getServiceLocator() - { - return $this->serviceLocator; - } -} -``` - -Thankfully, there is an easy workaround: every form element now implements the new interface -`Zend\Stdlib\InitializableInterface`, that defines a single `init()` function. In the context of -form elements, this `init()` function is automatically called once all the dependencies (including -all initializers) are resolved. Therefore, the previous example can be rewritten as such: - -```php -namespace Application\Form; - -use Album\Model; -use Zend\Form\Fieldset; -use Zend\ServiceManager\ServiceLocatorAwareInterface; -use Zend\ServiceManager\ServiceLocatorInterface; - -class AlbumFieldset extends Fieldset implements ServiceLocatorAwareInterface -{ - protected $serviceLocator; - - public function init() - { - // Here, we have $this->serviceLocator !! - } - - public function setServiceLocator(ServiceLocatorInterface $sl) - { - $this->serviceLocator = $sl; - } - - public function getServiceLocator() - { - return $this->serviceLocator; - } -} -``` diff --git a/book/zend.form.collections.md b/book/zend.form.collections.md deleted file mode 100644 index 329a8f12..00000000 --- a/book/zend.form.collections.md +++ /dev/null @@ -1,804 +0,0 @@ -# Form Collections - -Often, fieldsets or elements in your forms will correspond to other domain objects. In some cases, -they may correspond to collections of domain objects. In this latter case, in terms of user -interfaces, you may want to add items dynamically in the user interface -- a great example is adding -tasks to a task list. - -This document is intended to demonstrate these features. To do so, we first need to define some -domain objects that we'll be using. - -```php -namespace Application\Entity; - -class Product -{ - /** - * @var string - */ - protected $name; - - /** - * @var int - */ - protected $price; - - /** - * @var Brand - */ - protected $brand; - - /** - * @var array - */ - protected $categories; - - /** - * @param string $name - * @return Product - */ - public function setName($name) - { - $this->name = $name; - return $this; - } - - /** - * @return string - */ - public function getName() - { - return $this->name; - } - - /** - * @param int $price - * @return Product - */ - public function setPrice($price) - { - $this->price = $price; - return $this; - } - - /** - * @return int - */ - public function getPrice() - { - return $this->price; - } - - /** - * @param Brand $brand - * @return Product - */ - public function setBrand(Brand $brand) - { - $this->brand = $brand; - return $this; - } - - /** - * @return Brand - */ - public function getBrand() - { - return $this->brand; - } - - /** - * @param array $categories - * @return Product - */ - public function setCategories(array $categories) - { - $this->categories = $categories; - return $this; - } - - /** - * @return array - */ - public function getCategories() - { - return $this->categories; - } -} - -class Brand -{ - /** - * @var string - */ - protected $name; - - /** - * @var string - */ - protected $url; - - /** - * @param string $name - * @return Brand - */ - public function setName($name) - { - $this->name = $name; - return $this; - } - - /** - * @return string - */ - public function getName() - { - return $this->name; - } - - /** - * @param string $url - * @return Brand - */ - public function setUrl($url) - { - $this->url = $url; - return $this; - } - - /** - * @return string - */ - public function getUrl() - { - return $this->url; - } -} - -class Category -{ - /** - * @var string - */ - protected $name; - - /** - * @param string $name - * @return Category - */ - public function setName($name) - { - $this->name = $name; - return $this; - } - - /** - * @return string - */ - public function getName() - { - return $this->name; - } -} -``` - -As you can see, this is really simple code. A Product has two scalar properties (name and price), a -OneToOne relationship (one product has one brand), and a OneToMany relationship (one product has -many categories). - -## Creating Fieldsets - -The first step is to create three fieldsets. Each fieldset will contain all the fields and -relationships for a specific entity. - -Here is the `Brand` fieldset: - -```php -namespace Application\Form; - -use Application\Entity\Brand; -use Zend\Form\Fieldset; -use Zend\InputFilter\InputFilterProviderInterface; -use Zend\Stdlib\Hydrator\ClassMethods as ClassMethodsHydrator; - -class BrandFieldset extends Fieldset implements InputFilterProviderInterface -{ - public function __construct() - { - parent::__construct('brand'); - - $this - ->setHydrator(new ClassMethodsHydrator(false)) - ->setObject(new Brand()) - ; - - $this->add(array( - 'name' => 'name', - 'options' => array( - 'label' => 'Name of the brand', - ), - 'attributes' => array( - 'required' => 'required', - ), - )); - - $this->add(array( - 'name' => 'url', - 'type' => 'Zend\Form\Element\Url', - 'options' => array( - 'label' => 'Website of the brand', - ), - 'attributes' => array( - 'required' => 'required', - ), - )); - } - - /** - * @return array - */ - public function getInputFilterSpecification() - { - return array( - 'name' => array( - 'required' => true, - ), - ); - } -} -``` - -We can discover some new things here. As you can see, the fieldset calls the method `setHydrator()`, -giving it a `ClassMethods` hydrator, and the `setObject()` method, giving it an empty instance of a -concrete `Brand` object. - -When the data will be validated, the `Form` will automatically iterate through all the field sets it -contains, and automatically populate the sub-objects, in order to return a complete entity. - -Also notice that the `Url` element has a type of `Zend\Form\Element\Url`. This information will be -used to validate the input field. You don't need to manually add filters or validators for this -input as that element provides a reasonable input specification. - -Finally, `getInputFilterSpecification()` gives the specification for the remaining input ("name"), -indicating that this input is required. Note that *required* in the array "attributes" (when -elements are added) is only meant to add the "required" attribute to the form markup (and therefore -has semantic meaning only). - -Here is the `Category` fieldset: - -```php -namespace Application\Form; - -use Application\Entity\Category; -use Zend\Form\Fieldset; -use Zend\InputFilter\InputFilterProviderInterface; -use Zend\Stdlib\Hydrator\ClassMethods as ClassMethodsHydrator; - -class CategoryFieldset extends Fieldset implements InputFilterProviderInterface -{ - public function __construct() - { - parent::__construct('category'); - - $this - ->setHydrator(new ClassMethodsHydrator(false)) - ->setObject(new Category()) - ; - - $this->setLabel('Category'); - - $this->add(array( - 'name' => 'name', - 'options' => array( - 'label' => 'Name of the category', - ), - 'attributes' => array( - 'required' => 'required', - ), - )); - } - - /** - * @return array - */ - public function getInputFilterSpecification() - { - return array( - 'name' => array( - 'required' => true, - ), - ); - } -} -``` - -Nothing new here. - -And finally the `Product` fieldset: - -```php -namespace Application\Form; - -use Application\Entity\Product; -use Zend\Form\Fieldset; -use Zend\InputFilter\InputFilterProviderInterface; -use Zend\Stdlib\Hydrator\ClassMethods as ClassMethodsHydrator; - -class ProductFieldset extends Fieldset implements InputFilterProviderInterface -{ - public function __construct() - { - parent::__construct('product'); - - $this - ->setHydrator(new ClassMethodsHydrator(false)) - ->setObject(new Product()) - ; - - $this->add(array( - 'name' => 'name', - 'options' => array( - 'label' => 'Name of the product', - ), - 'attributes' => array( - 'required' => 'required', - ), - )); - - $this->add(array( - 'name' => 'price', - 'options' => array( - 'label' => 'Price of the product', - ), - 'attributes' => array( - 'required' => 'required', - ), - )); - - $this->add(array( - 'type' => 'Application\Form\BrandFieldset', - 'name' => 'brand', - 'options' => array( - 'label' => 'Brand of the product', - ), - )); - - $this->add(array( - 'type' => 'Zend\Form\Element\Collection', - 'name' => 'categories', - 'options' => array( - 'label' => 'Please choose categories for this product', - 'count' => 2, - 'should_create_template' => true, - 'allow_add' => true, - 'target_element' => array( - 'type' => 'Application\Form\CategoryFieldset', - ), - ), - )); - } - - /** - * Should return an array specification compatible with - * {@link Zend\InputFilter\Factory::createInputFilter()}. - * - * @return array - */ - public function getInputFilterSpecification() - { - return array( - 'name' => array( - 'required' => true, - ), - 'price' => array( - 'required' => true, - 'validators' => array( - array( - 'name' => 'Float', - ), - ), - ), - ); - } -} -``` - -We have a lot of new things here! - -First, notice how the brand element is added: we specify it to be of type -`Application\Form\BrandFieldset`. This is how you handle a OneToOne relationship. When the form is -validated, the `BrandFieldset` will first be populated, and will return a `Brand` entity (as we have -specified a `ClassMethods` hydrator, and bound the fieldset to a `Brand` entity using the -`setObject()` method). This `Brand` entity will then be used to populate the `Product` entity by -calling the `setBrand()` method. - -The next element shows you how to handle OneToMany relationship. The type is -`Zend\Form\Element\Collection`, which is a specialized element to handle such cases. As you can see, -the name of the element ("categories") perfectly matches the name of the property in the `Product` -entity. - -This element has a few interesting options: - -- `count`: this is how many times the element (in this case a category) has to be rendered. We've - set it to two in this examples. -- `should_create_template`: if set to `true`, it will generate a template markup in a `` - element, in order to simplify adding new element on the fly (we will speak about this one later). -- `allow_add`: if set to `true` (which is the default), dynamically added elements will be retrieved - and validated; otherwise, they will be completely ignored. This, of course, depends on what you want - to do. -- `target_element`: this is either an element or, as this is the case in this example, an array that - describes the element or fieldset that will be used in the collection. In this case, the - `target_element` is a `Category` fieldset. - -## The Form Element - -So far, so good. We now have our field sets in place. But those are field sets, not forms. And only -`Form` instances can be validated. So here is the form : - -```php -namespace Application\Form; - -use Zend\Form\Form; -use Zend\InputFilter\InputFilter; -use Zend\Stdlib\Hydrator\ClassMethods as ClassMethodsHydrator; - -class CreateProduct extends Form -{ - public function __construct() - { - parent::__construct('create_product'); - - $this - ->setAttribute('method', 'post') - ->setHydrator(new ClassMethodsHydrator(false)) - ->setInputFilter(new InputFilter()) - ; - - $this->add(array( - 'type' => 'Application\Form\ProductFieldset', - 'options' => array( - 'use_as_base_fieldset' => true, - ), - )); - - $this->add(array( - 'type' => 'Zend\Form\Element\Csrf', - 'name' => 'csrf', - )); - - $this->add(array( - 'name' => 'submit', - 'attributes' => array( - 'type' => 'submit', - 'value' => 'Send', - ), - )); - } -} -``` - -`CreateProduct` is quite simple, as it only defines a `Product` fieldset, as well as some other -useful fields (`CSRF` for security, and a `Submit` button). - -Notice the `use_as_base_fieldset` option. This option is here to say to the form: "hey, the object I -bind to you is, in fact, bound to the fieldset that is the base fieldset." This will be to true most -of the times. - -What's cool with this approach is that each entity can have its own `Fieldset` and can be reused. -You describe the elements, the filters, and validators for each entity only once, and the concrete -`Form` instance will only compose those fieldsets. You no longer have to add the "username" input to -every form that deals with users! - -## The Controller - -Now, let's create the action in the controller: - -```php -/** - * @return array - */ -public function indexAction() -{ - $form = new CreateProduct(); - $product = new Product(); - $form->bind($product); - - $request = $this->getRequest(); - if ($request->isPost()) { - $form->setData($request->getPost()); - - if ($form->isValid()) { - var_dump($product); - } - } - - return array( - 'form' => $form, - ); -} -``` - -This is super easy. Nothing to do in the controllers. All the magic is done behind the scene. - -## The View - -And finally, the view: - -```php -setAttribute('action', $this->url('home')) - ->prepare(); - -echo $this->form()->openTag($form); - -$product = $form->get('product'); - -echo $this->formRow($product->get('name')); -echo $this->formRow($product->get('price')); -echo $this->formCollection($product->get('categories')); - -$brand = $product->get('brand'); - -echo $this->formRow($brand->get('name')); -echo $this->formRow($brand->get('url')); - -echo $this->formHidden($form->get('csrf')); -echo $this->formElement($form->get('submit')); - -echo $this->form()->closeTag(); -``` - -A few new things here : - -- the `prepare()` method. You *must* call it prior to rendering anything in the view (this function - is only meant to be called in views, not in controllers). -- the `FormRow` helper renders a label (if present), the input itself, and errors. -- the `FormCollection` helper will iterate through every element in the collection, and render every - element with the FormRow helper (you may specify an alternate helper if desired, using the - `setElementHelper()` method on that `FormCollection` helper instance). If you need more control - about the way you render your forms, you can iterate through the elements in the collection, and - render them manually one by one. - -Here is the result: - -![image](../images/zend.form.collections.view.png) - -As you can see, collections are wrapped inside a fieldset, and every item in the collection is -itself wrapped in the fieldset. In fact, the `Collection` element uses label for each item in the -collection, while the label of the `Collection` element itself is used as the legend of the -fieldset. You must have a label on every element in order to use this feature. If you don't want the -fieldset created, but just the elements within it, simply add a boolean `false` as the second -parameter of the `FormCollection` view helper. - -If you validate, all elements will show errors (this is normal, as we've marked them as required). -As soon as the form is valid, this is what we get : - -![image](../images/zend.form.collections.view.result.png) - -As you can see, the bound object is completely filled, not with arrays, but with objects! - -But that's not all. - -## Adding New Elements Dynamically - -Remember the `should_create_template`? We are going to use it now. - -Often, forms are not completely static. In our case, let's say that we don't want only two -categories, but we want the user to be able to add other ones at runtime. `Zend\Form` has this -capability. First, let's see what it generates when we ask it to create a template: - -![image](../images/zend.form.collections.dynamic-elements.template.png) - -As you can see, the collection generates two fieldsets (the two categories) *plus* a span with a -`data-template` attribute that contains the full HTML code to copy to create a new element in the -collection. Of course `__index__` (this is the placeholder generated) has to be changed to a valid -value. Currently, we have 2 elements (`categories[0]` and `categories[1]`, so `__index__` has to be -changed to 2. - -If you want, this placeholder (`__index__` is the default) can be changed using the -`template_placeholder` option key: - -```php -$this->add(array( - 'type' => 'Zend\Form\Element\Collection', - 'name' => 'categories', - 'options' => array( - 'label' => 'Please choose categories for this product', - 'count' => 2, - 'should_create_template' => true, - 'template_placeholder' => '__placeholder__', - 'target_element' => array( - 'type' => 'Application\Form\CategoryFieldset', - ), - ), -)); -``` - -First, let's add a small button "Add new category" anywhere in the form: - -```php - -``` - -The `add_category` function is fairly simple: - -1. First, count the number of elements we already have. -2. Get the template from the `span`'s `data-template` attribute. -3. Change the placeholder to a valid index. -4. Add the element to the DOM. - -Here is the code: - -```javascript - -``` - -(Note: the above example assumes `$()` is defined, and equivalent to jQuery's `$()` function, Dojo's -`dojo.query`, etc.) - -One small remark about the `template.replace`: the example uses `currentCount` and not `currentCount -+ 1`, as the indices are zero-based (so, if we have two elements in the collection, the third one -will have the index `2`). - -Now, if we validate the form, it will automatically take into account this new element by validating -it, filtering it and retrieving it: - -![image](../images/zend.form.collections.dynamic-elements.result.png) - -Of course, if you don't want to allow adding elements in a collection, you must set the option -`allow_add` to `false`. This way, even if new elements are added, they won't be validated and hence, -not added to the entity. Also, if we don't want elements to be added, we don't need the data -template, either. Here's how you do it: - -```php -$this->add(array( - 'type' => 'Zend\Form\Element\Collection', - 'name' => 'categories', - 'options' => array( - 'label' => 'Please choose categories for this product', - 'count' => 2, - 'should_create_template' => false, - 'allow_add' => false, - 'target_element' => array( - 'type' => 'Application\Form\CategoryFieldset', - ), - ), -)); -``` - -There are some limitations to this capability: - -- Although you can add new elements and remove them, you *CANNOT* remove more elements in a - collection than the initial count (for instance, if your code specifies `count == 2`, you will be - able to add a third one and remove it, but you won't be able to remove any others. If the initial - count is 2, you *must* have at least two elements. -- Dynamically added elements have to be added at the end of the collection. They can be added - anywhere (these elements will still be validated and inserted into the entity), but if the - validation fails, this newly added element will be automatically be replaced at the end of the - collection. - -## Validation groups for fieldsets and collection - -Validation groups allow you to validate a subset of fields. - -As an example, although the `Brand` entity has a `URL` property, we don't want the user to specify -it in the creation form (but may wish to later in the "Edit Product" form, for instance). Let's -update the view to remove the `URL` input: - -```php -setAttribute('action', $this->url('home')) - ->prepare() -; - -echo $this->form()->openTag($form); - -$product = $form->get('product'); - -echo $this->formRow($product->get('name')); -echo $this->formRow($product->get('price')); -echo $this->formCollection($product->get('categories')); - -$brand = $product->get('brand'); - -echo $this->formRow($brand->get('name')); - -echo $this->formHidden($form->get('csrf')); -echo $this->formElement($form->get('submit')); - -echo $this->form()->closeTag(); -``` - -This is what we get: - -![image](../images/zend.form.collections.validation-groups.png) - -The `URL` input has disappeared, but even if we fill every input, the form won't validate. In fact, -this is normal. We specified in the input filter that the `URL` is a *required* field, so if the -form does not have it, it won't validate, even though we didn't add it to the view! - -Of course, you could create a `BrandFieldsetWithoutURL` fieldset, but of course this is not -recommended, as a lot of code will be duplicated. - -The solution: validation groups. A validation group is specified in a `Form` object (hence, in our -case, in the `CreateProduct` form) by giving an array of all the elements we want to validate. Our -`CreateProduct` now looks like this: - -```php -namespace Application\Form; - -use Zend\Form\Form; -use Zend\InputFilter\InputFilter; -use Zend\Stdlib\Hydrator\ClassMethods as ClassMethodsHydrator; - -class CreateProduct extends Form -{ - public function __construct() - { - parent::__construct('create_product'); - - $this - ->setAttribute('method', 'post') - ->setHydrator(new ClassMethodsHydrator()) - ->setInputFilter(new InputFilter()) - ; - - $this->add(array( - 'type' => 'Application\Form\ProductFieldset', - 'options' => array( - 'use_as_base_fieldset' => true, - ), - )); - - $this->add(array( - 'type' => 'Zend\Form\Element\Csrf', - 'name' => 'csrf', - )); - - $this->add(array( - 'name' => 'submit', - 'attributes' => array( - 'type' => 'submit', - 'value' => 'Send', - ), - )); - - $this->setValidationGroup(array( - 'csrf', - 'product' => array( - 'name', - 'price', - 'brand' => array( - 'name', - ), - 'categories' => array( - 'name', - ), - ), - )); - } -} -``` - -Of course, don't forget to add the `CSRF` element, as we want it to be validated too (but notice -that I didn't write the submit element, as we don't care about it). You can recursively select the -elements you want. - -There is one simple limitation currently: validation groups for collections are set on a -per-collection basis, not per-element in a collection basis. This means you cannot say, "validate -the name input for the first element of the categories collection, but don't validate it for the -second one." But, honestly, this is really an edge-case. - -Now, the form validates (and the `URL` is set to null as we didn't specify it). diff --git a/book/zend.form.elements.md b/book/zend.form.elements.md deleted file mode 100644 index afcf6b45..00000000 --- a/book/zend.form.elements.md +++ /dev/null @@ -1,1432 +0,0 @@ -# Form Elements - -## Introduction - -A set of specialized elements are provided for accomplishing application-centric tasks. These -include several HTML5 input elements with matching server-side validators, the `Csrf` element (to -prevent Cross Site Request Forgery attacks), and the `Captcha` element (to display and validate -\[CAPTCHAs\](zend.captcha)). - -A `Factory` is provided to facilitate creation of elements, fieldsets, forms, and the related input -filter. See the \[Zend\\Form Quick Start\](zend.form.quick-start.factory) for more information. - -## Element Base Class - -`Zend\Form\Element` is a base class for all specialized elements and `Zend\Form\Fieldset`. - -**Basic Usage** - -At the bare minimum, each element or fieldset requires a name. You will also typically provide some -attributes to hint to the view layer how it might render the item. - -```php -use Zend\Form\Element; -use Zend\Form\Form; - -$username = new Element\Text('username'); -$username - ->setLabel('Username') - ->setAttributes(array( - 'class' => 'username', - 'size' => '30', - )); - -$password = new Element\Password('password'); -$password - ->setLabel('Password') - ->setAttributes(array( - 'size' => '30', - )); - -$form = new Form('my-form'); -$form - ->add($username) - ->add($password); -``` - -**Public Methods** - -## Standard Elements - -### Button - -`Zend\Form\Element\Button` represents a button form input. It can be used with the -`Zend\Form\View\Helper\FormButton` view helper. - -`Zend\Form\Element\Button` extends from \[ZendFormElement\](zend.form.element). - -**Basic Usage** - -This element automatically adds a `type` attribute of value `button`. - -```php -use Zend\Form\Element; -use Zend\Form\Form; - -$button = new Element\Button('my-button'); -$button->setLabel('My Button') - ->setValue('foo'); - -$form = new Form('my-form'); -$form->add($button); -``` - -### Captcha - -`Zend\Form\Element\Captcha` can be used with forms where authenticated users are not necessary, but -you want to prevent spam submissions. It is paired with one of the `Zend\Form\View\Helper\Captcha\*` -view helpers that matches the type of *CAPTCHA* adapter in use. - -**Basic Usage** - -A *CAPTCHA* adapter must be attached in order for validation to be included in the element's input -filter specification. See the section on \[Zend CAPTCHA Adapters\](zend.captcha.adapters) for more -information on what adapters are available. - -```php -use Zend\Captcha; -use Zend\Form\Element; -use Zend\Form\Form; - -$captcha = new Element\Captcha('captcha'); -$captcha - ->setCaptcha(new Captcha\Dumb()) - ->setLabel('Please verify you are human'); - -$form = new Form('my-form'); -$form->add($captcha); -``` - -Here is with the array notation: - -```php -use Zend\Captcha; -use Zend\Form\Form; - -$form = new Form('my-form'); -$form->add(array( - 'type' => 'Zend\Form\Element\Captcha', - 'name' => 'captcha', - 'options' => array( - 'label' => 'Please verify you are human', - 'captcha' => new Captcha\Dumb(), - ), -)); -``` - -**Public Methods** - -The following methods are in addition to the inherited methods of Zend\\\\Form\\\\Element -<zend.form.element.methods>. - -### Checkbox - -`Zend\Form\Element\Checkbox` is meant to be paired with the `Zend\Form\View\Helper\FormCheckbox` for -HTML inputs with type checkbox. This element adds an `InArray` validator to its input filter -specification in order to validate on the server if the checkbox contains either the checked value -or the unchecked value. - -**Basic Usage** - -This element automatically adds a `"type"` attribute of value `"checkbox"`. - -```php -use Zend\Form\Element; -use Zend\Form\Form; - -$checkbox = new Element\Checkbox('checkbox'); -$checkbox->setLabel('A checkbox'); -$checkbox->setUseHiddenElement(true); -$checkbox->setCheckedValue("good"); -$checkbox->setUncheckedValue("bad"); - -$form = new Form('my-form'); -$form->add($checkbox); -``` - -Using the array notation: - -```php -use Zend\Form\Form; - -$form = new Form('my-form'); -$form->add(array( - 'type' => 'Zend\Form\Element\Checkbox', - 'name' => 'checkbox', - 'options' => array( - 'label' => 'A checkbox', - 'use_hidden_element' => true, - 'checked_value' => 'good', - 'unchecked_value' => 'bad' - ) -)); -``` - -When creating a checkbox element, setting an attribute of checked will result in the checkbox always -being checked regardless of any data object which might subsequently be bound to the form. The -correct way to set the default value of a checkbox is to set the value attribute as for any other -element. To have a checkbox checked by default make the value equal to the checked\_value eg: - -```php -use Zend\Form\Form; - -$form = new Form('my-form'); -$form->add(array( - 'type' => 'Zend\Form\Element\Checkbox', - 'name' => 'checkbox', - 'options' => array( - 'label' => 'A checkbox', - 'use_hidden_element' => true, - 'checked_value' => 'yes', - 'unchecked_value' => 'no' - ), - 'attributes' => array( - 'value' => 'yes' - ) -)); -``` - -**Public Methods** - -The following methods are in addition to the inherited \[methods of -Zend\\Form\\Element\](zend.form.element.methods) . - -### Collection - -Sometimes, you may want to add input (or a set of inputs) multiple times, either because you don't -want to duplicate code, or because you do not know in advance how many elements you will need (in -the case of elements dynamically added to a form using JavaScript, for instance). For more -information about Collection, please refer to the \[Form Collections -tutorial\](zend.form.collections). - -`Zend\Form\Element\Collection` is meant to be paired with the -`Zend\Form\View\Helper\FormCollection`. - -**Basic Usage** - -```php -use Zend\Form\Element; -use Zend\Form\Form; - -$colors = new Element\Collection('collection'); -$colors->setLabel('Colors'); -$colors->setCount(2); -$colors->setTargetElement(new Element\Color()); -$colors->setShouldCreateTemplate(true); - -$form = new Form('my-form'); -$form->add($colors); -``` - -Using the array notation: - -```php -use Zend\Form\Element; -use Zend\Form\Form; - -$form = new Form('my-form'); -$form->add(array( - 'type' => 'Zend\Form\Element\Collection', - 'options' => array( - 'label' => 'Colors', - 'count' => 2, - 'should_create_template' => true, - 'target_element' => new Element\Color() - ) -)); -``` - -**Public Methods** - -The following methods are in addition to the inherited \[methods of -Zend\\Form\\Element\](zend.form.element.methods) . - -### Csrf - -`Zend\Form\Element\Csrf` pairs with the `Zend\Form\View\Helper\FormHidden` to provide protection -from *CSRF* attacks on forms, ensuring the data is submitted by the user session that generated the -form and not by a rogue script. Protection is achieved by adding a hash element to a form and -verifying it when the form is submitted. - -**Basic Usage** - -This element automatically adds a `"type"` attribute of value `"hidden"`. - -```php -use Zend\Form\Element; -use Zend\Form\Form; - -$csrf = new Element\Csrf('csrf'); - -$form = new Form('my-form'); -$form->add($csrf); -``` - -You can change the options of the CSRF validator using the `setCsrfValidatorOptions` function, or by -using the `"csrf_options"` key. Here is an example using the array notation: - -```php -use Zend\Form\Form; - -$form = new Form('my-form'); -$form->add(array( - 'type' => 'Zend\Form\Element\Csrf', - 'name' => 'csrf', - 'options' => array( - 'csrf_options' => array( - 'timeout' => 600 - ) - ) -)); -``` - -> ## Note -If you are using more than one form on a page, and each contains its own CSRF element, you will need -to make sure that each form uniquely names its element; if you do not, it's possible for the value -of one to override the other within the server-side session storage, leading to the inability to -validate one or more of the forms on your page. We suggest prefixing the element name with the -form's name or function: "login\_csrf", "registration\_csrf", etc. - -**Public Methods** - -The following methods are in addition to the inherited methods of Zend\\\\Form\\\\Element -<zend.form.element.methods>. - -### File - -`Zend\Form\Element\File` represents a form file input and provides a default input specification -with a type of \[FileInput\](zend.input-filter.file-input) (important for handling validators and -filters correctly). It can be used with the `Zend\Form\View\Helper\FormFile` view helper. - -`Zend\Form\Element\File` extends from \[Zend\\Form\\Element\](zend.form.element). - -**Basic Usage** - -This element automatically adds a `"type"` attribute of value `"file"`. It will also set the form's -enctype to `multipart/form-data` during `$form->prepare()`. - -```php -use Zend\Form\Element; -use Zend\Form\Form; - -// Single file upload -$file = new Element\File('file'); -$file->setLabel('Single file input'); - -// HTML5 multiple file upload -$multiFile = new Element\File('multi-file'); -$multiFile->setLabel('Multi file input') - ->setAttribute('multiple', true); - -$form = new Form('my-file'); -$form->add($file) - ->add($multiFile); -``` - -### Hidden - -`Zend\Form\Element\Hidden` represents a hidden form input. It can be used with the -`Zend\Form\View\Helper\FormHidden` view helper. - -`Zend\Form\Element\Hidden` extends from \[Zend\\Form\\Element\](zend.form.element). - -**Basic Usage** - -This element automatically adds a `"type"` attribute of value `"hidden"`. - -```php -use Zend\Form\Element; -use Zend\Form\Form; - -$hidden = new Element\Hidden('my-hidden'); -$hidden->setValue('foo'); - -$form = new Form('my-form'); -$form->add($hidden); -``` - -Here is with the array notation: - -```php -use Zend\Form\Form; - -$form = new Form('my-form'); -$form->add(array( - 'type' => 'Zend\Form\Element\Hidden', - 'name' => 'my-hidden', - 'attributes' => array( - 'value' => 'foo' - ) -)); -``` - -### Image - -`Zend\Form\Element\Image` represents a image button form input. It can be used with the -`Zend\Form\View\Helper\FormImage` view helper. - -`Zend\Form\Element\Image` extends from \[Zend\\Form\\Element\](zend.form.element). - -**Basic Usage** - -This element automatically adds a `"type"` attribute of value `"image"`. - -```php -use Zend\Form\Element; -use Zend\Form\Form; - -$image = new Element\Image('my-image'); -$image->setAttribute('src', 'http://my.image.url'); // Src attribute is required - -$form = new Form('my-form'); -$form->add($image); -``` - -### Month Select - -`Zend\Form\Element\MonthSelect` is meant to be paired with the -`Zend\Form\View\Helper\FormMonthSelect`. This element creates two select elements, where the first -one is populated with months and the second is populated with years. By default, it sets 100 years -in the past for the year element, starting with the current year. - -**Basic Usage** - -```php -use Zend\Form\Element; -use Zend\Form\Form; - -$monthYear = new Element\MonthSelect('monthyear'); -$monthYear->setLabel('Select a month and a year'); -$monthYear->setMinYear(1986); - -$form = new Form('dateselect'); -$form->add($monthYear); -``` - -Using the array notation: - -```php -use Zend\Form\Form; - -$form = new Form('dateselect'); -$form->add(array( - 'type' => 'Zend\Form\Element\MonthSelect', - 'name' => 'monthyear', - 'options' => array( - 'label' => 'Select a month and a year', - 'min_year' => 1986, - ) -)); -``` - -**Public Methods** - -The following methods are in addition to the inherited \[methods of -Zend\\Form\\Element\](zend.form.element.methods). - -### MultiCheckbox - -`Zend\Form\Element\MultiCheckbox` is meant to be paired with the -`Zend\Form\View\Helper\FormMultiCheckbox` for HTML inputs with type checkbox. This element adds an -`InArray` validator to its input filter specification in order to validate on the server if the -checkbox contains values from the multiple checkboxes. - -**Basic Usage** - -This element automatically adds a `"type"` attribute of value `"checkbox"` for every checkboxes. - -```php -use Zend\Form\Element; -use Zend\Form\Form; - -$multiCheckbox = new Element\MultiCheckbox('multi-checkbox'); -$multiCheckbox->setLabel('What do you like ?'); -$multiCheckbox->setValueOptions(array( - '0' => 'Apple', - '1' => 'Orange', - '2' => 'Lemon' -)); - -$form = new Form('my-form'); -$form->add($multiCheckbox); -``` - -Using the array notation: - -```php -use Zend\Form\Form; - -$form = new Form('my-form'); -$form->add(array( - 'type' => 'Zend\Form\Element\MultiCheckbox', - 'name' => 'multi-checkbox', - 'options' => array( - 'label' => 'What do you like ?', - 'value_options' => array( - '0' => 'Apple', - '1' => 'Orange', - '2' => 'Lemon', - ), - ) -)); -``` - -**Advanced Usage** - -In order to set attributes or customize the option elements, an array can be used instead of a -string. The following keys are supported: - -- `"label"` - The string displayed for the option. -- `"value"` - The form value associated with the option. -- `"selected"` - Boolean that sets whether the option is marked as selected. -- `"disabled"` - Boolean that sets whether the option will be disabled -- `"attributes"` - Array of html attributes that will be set on this option. Merged with the - attributes set on the element. -- `"label_attributes"` - Array of html attributes that will be set on the label. Merged with the - attributes set on the element's label. - -```php -$form = new Form('my-form'); -$form->add(array( - 'type' => 'Zend\Form\Element\MultiCheckbox', - 'name' => 'multi-checkbox', - 'options' => array( - 'label' => 'What do you like ?', - 'value_options' => array( - array( - 'value' => '0', - 'label' => 'Apple', - 'selected' => false, - 'disabled' => false, - 'attributes' => array( - 'id' => 'apple_option', - 'data-fruit' => 'apple', - ), - 'label_attributes' => array( - 'id' => 'apple_label', - ), - ), - array( - 'value' => '1', - 'label' => 'Orange', - 'selected' => true, - ), - array( - 'value' => '2', - 'label' => 'Lemon', - ), - ), - ), -)); -``` - -**Public Methods** - -The following methods are in addition to the inherited \[methods of -Zend\\Form\\Element\\Checkbox\](zend.form.element.checkbox.methods) . - -### Password - -`Zend\Form\Element\Password` represents a password form input. It can be used with the -`Zend\Form\View\Helper\FormPassword` view helper. - -`Zend\Form\Element\Password` extends from \[Zend\\Form\\Element\](zend.form.element). - -**Basic Usage** - -This element automatically adds a `"type"` attribute of value `"password"`. - -```php -use Zend\Form\Element; -use Zend\Form\Form; - -$password = new Element\Password('my-password'); -$password->setLabel('Enter your password'); - -$form = new Form('my-form'); -$form->add($password); -``` - -### Radio - -`Zend\Form\Element\Radio` is meant to be paired with the `Zend\Form\View\Helper\FormRadio` for HTML -inputs with type radio. This element adds an `InArray` validator to its input filter specification -in order to validate on the server if the value is contains within the radio value elements. - -**Basic Usage** - -This element automatically adds a `"type"` attribute of value `"radio"` for every radio. - -```php -use Zend\Form\Element; -use Zend\Form\Form; - -$radio = new Element\Radio('gender'); -$radio->setLabel('What is your gender ?'); -$radio->setValueOptions(array( - '0' => 'Female', - '1' => 'Male', -)); - -$form = new Form('my-form'); -$form->add($radio); -``` - -Using the array notation: - -```php -use Zend\Form\Form; - - $form = new Form('my-form'); - $form->add(array( - 'type' => 'Zend\Form\Element\Radio', - 'name' => 'gender', - 'options' => array( - 'label' => 'What is your gender ?', - 'value_options' => array( - '0' => 'Female', - '1' => 'Male', - ), - ), - )); -``` - -**Advanced Usage** - -See MultiCheckbox for examples<zend.form.element.multicheckbox.advanced> of how to apply -attributes and options to each radio button. - -**Public Methods** - -All the methods from the inherited \[methods of -Zend\\Form\\Element\\MultiCheckbox\](zend.form.element.multicheckbox.methods) are also available for -this element. - -### Select - -`Zend\Form\Element\Select` is meant to be paired with the `Zend\Form\View\Helper\FormSelect` for -HTML inputs with type select. This element adds an `InArray` validator to its input filter -specification in order to validate on the server if the selected value belongs to the values. This -element can be used as a multi-select element by adding the "multiple" HTML attribute to the -element. - -**Basic Usage** - -This element automatically adds a `"type"` attribute of value `"select"`. - -```php -use Zend\Form\Element; -use Zend\Form\Form; - -$select = new Element\Select('language'); -$select->setLabel('Which is your mother tongue?'); -$select->setValueOptions(array( - '0' => 'French', - '1' => 'English', - '2' => 'Japanese', - '3' => 'Chinese', -)); - -$form = new Form('language'); -$form->add($select); -``` - -Using the array notation: - -```php -use Zend\Form\Form; - -$form = new Form('my-form'); -$form->add(array( - 'type' => 'Zend\Form\Element\Select', - 'name' => 'language', - 'options' => array( - 'label' => 'Which is your mother tongue?', - 'value_options' => array( - '0' => 'French', - '1' => 'English', - '2' => 'Japanese', - '3' => 'Chinese', - ), - ) -)); -``` - -You can add an empty option (option with no value) using the `"empty_option"` option: - -```php -use Zend\Form\Form; - -$form = new Form('my-form'); -$form->add(array( - 'type' => 'Zend\Form\Element\Select', - 'name' => 'language', - 'options' => array( - 'label' => 'Which is your mother tongue?', - 'empty_option' => 'Please choose your language', - 'value_options' => array( - '0' => 'French', - '1' => 'English', - '2' => 'Japanese', - '3' => 'Chinese', - ), - ) -)); -``` - -Option groups are also supported. You just need to add an 'options' key to the value options. - -```php -use Zend\Form\Element; -use Zend\Form\Form; - -$select = new Element\Select('language'); -$select->setLabel('Which is your mother tongue?'); -$select->setValueOptions(array( - 'european' => array( - 'label' => 'European languages', - 'options' => array( - '0' => 'French', - '1' => 'Italian', - ), - ), - 'asian' => array( - 'label' => 'Asian languages', - 'options' => array( - '2' => 'Japanese', - '3' => 'Chinese', - ), - ), -)); - -$form = new Form('language'); -$form->add($select); -``` - -**Public Methods** - -The following methods are in addition to the inherited \[methods of -Zend\\Form\\Element\](zend.form.element.methods) . - -### Submit - -`Zend\Form\Element\Submit` represents a submit button form input. It can be used with the -`Zend\Form\View\Helper\FormSubmit` view helper. - -`Zend\Form\Element\Submit` extends from \[Zend\\Form\\Element\](zend.form.element). - -**Basic Usage** - -This element automatically adds a `"type"` attribute of value `"submit"`. - -```php -use Zend\Form\Element; -use Zend\Form\Form; - -$submit = new Element\Submit('my-submit'); -$submit->setValue('Submit Form'); - -$form = new Form('my-form'); -$form->add($submit); -``` - -### Text - -`Zend\Form\Element\Text` represents a text form input. It can be used with the -`Zend\Form\View\Helper\FormText` view helper. - -`Zend\Form\Element\Text` extends from \[Zend\\Form\\Element\](zend.form.element). - -**Basic Usage** - -This element automatically adds a `"type"` attribute of value `"text"`. - -```php -use Zend\Form\Element; -use Zend\Form\Form; - -$text = new Element\Text('my-text'); -$text->setLabel('Enter your name'); - -$form = new Form('my-form'); -$form->add($text); -``` - -### Textarea - -`Zend\Form\Element\Textarea` represents a textarea form input. It can be used with the -`Zend\Form\View\Helper\FormTextarea` view helper. - -`Zend\Form\Element\Textarea` extends from \[Zend\\Form\\Element\](zend.form.element). - -**Basic Usage** - -This element automatically adds a `"type"` attribute of value `"textarea"`. - -```php -use Zend\Form\Element; -use Zend\Form\Form; - -$textarea = new Element\Textarea('my-textarea'); -$textarea->setLabel('Enter a description'); - -$form = new Form('my-form'); -$form->add($textarea); -``` - -## HTML5 Elements - -### Color - -`Zend\Form\Element\Color` is meant to be paired with the `Zend\Form\View\Helper\FormColor` for -[HTML5 inputs with type -color](http://www.whatwg.org/specs/web-apps/current-work/multipage/states-of-the-type-attribute.html#color-state-(type=color)). -This element adds filters and a `Regex` validator to it's input filter specification in order to -validate a [HTML5 valid simple -color](http://www.whatwg.org/specs/web-apps/current-work/multipage/common-microsyntaxes.html#valid-simple-color) -value on the server. - -**Basic Usage** - -This element automatically adds a `"type"` attribute of value `"color"`. - -```php -use Zend\Form\Element; -use Zend\Form\Form; - -$color = new Element\Color('color'); -$color->setLabel('Background color'); - -$form = new Form('my-form'); -$form->add($color); -``` - -Here is the same example using the array notation: - -```php -use Zend\Form\Form; - -$form = new Form('my-form'); -$form->add(array( - 'type' => 'Zend\Form\Element\Color', - 'name' => 'color', - 'options' => array( - 'label' => 'Background color' - ) -)); -``` - -**Public Methods** - -The following methods are in addition to the inherited methods of Zend\\\\Form\\\\Element -<zend.form.element.methods>. - -### Date - -`Zend\Form\Element\Date` is meant to be paired with the `Zend\Form\View\Helper\FormDate` for [HTML5 -inputs with type -date](http://www.whatwg.org/specs/web-apps/current-work/multipage/states-of-the-type-attribute.html#date-state-(type=date)). -This element adds filters and validators to it's input filter specification in order to validate -HTML5 date input values on the server. - -**Basic Usage** - -This element automatically adds a `"type"` attribute of value `"date"`. - -```php -use Zend\Form\Element; -use Zend\Form\Form; - -$date = new Element\Date('appointment-date'); -$date - ->setLabel('Appointment Date') - ->setAttributes(array( - 'min' => '2012-01-01', - 'max' => '2020-01-01', - 'step' => '1', // days; default step interval is 1 day - )) - ->setOptions(array( - 'format' => 'Y-m-d' - )); - -$form = new Form('my-form'); -$form->add($date); -``` - -Here is with the array notation: - -```php -use Zend\Form\Form; - -$form = new Form('my-form'); -$form->add(array( - 'type' => 'Zend\Form\Element\Date', - 'name' => 'appointment-date', - 'options' => array( - 'label' => 'Appointment Date', - 'format' => 'Y-m-d' - ), - 'attributes' => array( - 'min' => '2012-01-01', - 'max' => '2020-01-01', - 'step' => '1', // days; default step interval is 1 day - ) -)); -``` - -> ## Note -Note: the `min`, `max`, and `step` attributes should be set prior to calling Zend\\Form::prepare(). -Otherwise, the default input specification for the element may not contain the correct validation -rules. - -**Public Methods** - -The following methods are in addition to the inherited methods of -Zend\\\\Form\\\\Element\\\\DateTime -<zend.form.element.date-time.methods>. - -### DateTime - -`Zend\Form\Element\DateTime` is meant to be paired with the `Zend\Form\View\Helper\FormDateTime` for -[HTML5 inputs with type -datetime](http://www.whatwg.org/specs/web-apps/current-work/multipage/states-of-the-type-attribute.html#date-and-time-state-(type=datetime)). -This element adds filters and validators to it's input filter specification in order to validate -HTML5 datetime input values on the server. - -**Basic Usage** - -This element automatically adds a `"type"` attribute of value `"datetime"`. - -```php -use Zend\Form\Element; -use Zend\Form\Form; - -$dateTime = new Element\DateTime('appointment-date-time'); -$dateTime - ->setLabel('Appointment Date/Time') - ->setAttributes(array( - 'min' => '2010-01-01T00:00:00Z', - 'max' => '2020-01-01T00:00:00Z', - 'step' => '1', // minutes; default step interval is 1 min - )) - ->setOptions(array( - 'format' => 'Y-m-d\TH:iP' - )); - -$form = new Form('my-form'); -$form->add($dateTime); -``` - -Here is with the array notation: - -```php -use Zend\Form\Form; - -$form = new Form('my-form'); -$form->add(array( - 'type' => 'Zend\Form\Element\DateTime', - 'name' => 'appointment-date-time', - 'options' => array( - 'label' => 'Appointment Date/Time', - 'format' => 'Y-m-d\TH:iP' - ), - 'attributes' => array( - 'min' => '2010-01-01T00:00:00Z', - 'max' => '2020-01-01T00:00:00Z', - 'step' => '1', // minutes; default step interval is 1 min - ) -)); -``` - -> ## Note -Note: the `min`, `max`, and `step` attributes should be set prior to calling Zend\\Form::prepare(). -Otherwise, the default input specification for the element may not contain the correct validation -rules. - -**Public Methods** - -The following methods are in addition to the inherited methods of Zend\\\\Form\\\\Element -<zend.form.element.methods>. - -### DateTimeLocal - -`Zend\Form\Element\DateTimeLocal` is meant to be paired with the -`Zend\Form\View\Helper\FormDateTimeLocal` for [HTML5 inputs with type -datetime-local](http://www.whatwg.org/specs/web-apps/current-work/multipage/states-of-the-type-attribute.html#local-date-and-time-state-(type=datetime-local)). -This element adds filters and validators to it's input filter specification in order to validate -HTML5 a local datetime input values on the server. - -**Basic Usage** - -This element automatically adds a `"type"` attribute of value `"datetime-local"`. - -```php -use Zend\Form\Element; -use Zend\Form\Form; - -$dateTimeLocal = new Element\DateTimeLocal('appointment-date-time'); -$dateTimeLocal - ->setLabel('Appointment Date') - ->setAttributes(array( - 'min' => '2010-01-01T00:00:00', - 'max' => '2020-01-01T00:00:00', - 'step' => '1', // minutes; default step interval is 1 min - )) - ->setOptions(array( - 'format' => 'Y-m-d\TH:i' - )); - -$form = new Form('my-form'); -$form->add($dateTimeLocal); -``` - -Here is with the array notation: - -```php -use Zend\Form\Form; - -$form = new Form('my-form'); -$form->add(array( - 'type' => 'Zend\Form\Element\DateTimeLocal', - 'name' => 'appointment-date-time', - 'options' => array( - 'label' => 'Appointment Date', - 'format' => 'Y-m-d\TH:i' - ), - 'attributes' => array( - 'min' => '2010-01-01T00:00:00', - 'max' => '2020-01-01T00:00:00', - 'step' => '1', // minutes; default step interval is 1 min - ) -)); -``` - -> ## Note -Note: the `min`, `max`, and `step` attributes should be set prior to calling Zend\\Form::prepare(). -Otherwise, the default input specification for the element may not contain the correct validation -rules. - -**Public Methods** - -The following methods are in addition to the inherited methods of -Zend\\\\Form\\\\Element\\\\DateTime -<zend.form.element.date-time.methods>. - -### Email - -`Zend\Form\Element\Email` is meant to be paired with the `Zend\Form\View\Helper\FormEmail` for -[HTML5 inputs with type -email](http://www.whatwg.org/specs/web-apps/current-work/multipage/states-of-the-type-attribute.html#e-mail-state-(type=email)). -This element adds filters and validators to it's input filter specification in order to validate -[HTML5 valid email -address](http://www.whatwg.org/specs/web-apps/current-work/multipage/states-of-the-type-attribute.html#valid-e-mail-address) -on the server. - -**Basic Usage** - -This element automatically adds a `"type"` attribute of value `"email"`. - -```php -use Zend\Form\Element; -use Zend\Form\Form; - -$form = new Form('my-form'); - -// Single email address -$email = new Element\Email('email'); -$email->setLabel('Email Address') -$form->add($email); - -// Comma separated list of emails -$emails = new Element\Email('emails'); -$emails - ->setLabel('Email Addresses') - ->setAttribute('multiple', true); -$form->add($emails); -``` - -Here is with the array notation: - -```php -use Zend\Form\Form; - -$form = new Form('my-form'); -$form->add(array( - 'type' => 'Zend\Form\Element\Email', - 'name' => 'email', - 'options' => array( - 'label' => 'Email Address' - ), -)); - -$form->add(array( - 'type' => 'Zend\Form\Element\Email', - 'name' => 'emails', - 'options' => array( - 'label' => 'Email Addresses' - ), - 'attributes' => array( - 'multiple' => true - ) -)); -``` - -> ## Note -Note: the `multiple` attribute should be set prior to calling Zend\\Form::prepare(). Otherwise, the -default input specification for the element may not contain the correct validation rules. - -**Public Methods** - -The following methods are in addition to the inherited methods of Zend\\\\Form\\\\Element -<zend.form.element.methods>. - -### Month - -`Zend\Form\Element\Month` is meant to be paired with the `Zend\Form\View\Helper\FormMonth` for -[HTML5 inputs with type -month](http://www.whatwg.org/specs/web-apps/current-work/multipage/states-of-the-type-attribute.html#month-state-(type=month)). -This element adds filters and validators to it's input filter specification in order to validate -HTML5 month input values on the server. - -**Basic Usage** - -This element automatically adds a `"type"` attribute of value `"month"`. - -```php -use Zend\Form\Element; -use Zend\Form\Form; - -$month = new Element\Month('month'); -$month - ->setLabel('Month') - ->setAttributes(array( - 'min' => '2012-01', - 'max' => '2020-01', - 'step' => '1', // months; default step interval is 1 month - )); - -$form = new Form('my-form'); -$form->add($month); -``` - -Here is with the array notation: - -```php -use Zend\Form\Form; - -$form = new Form('my-form'); -$form->add(array( - 'type' => 'Zend\Form\Element\Month', - 'name' => 'month', - 'options' => array( - 'label' => 'Month' - ), - 'attributes' => array( - 'min' => '2012-12', - 'max' => '2020-01', - 'step' => '1', // months; default step interval is 1 month - ) -)); -``` - -> ## Note -Note: the `min`, `max`, and `step` attributes should be set prior to calling Zend\\Form::prepare(). -Otherwise, the default input specification for the element may not contain the correct validation -rules. - -**Public Methods** - -The following methods are in addition to the inherited methods of -Zend\\\\Form\\\\Element\\\\DateTime -<zend.form.element.date-time.methods>. - -### Number - -`Zend\Form\Element\Number` is meant to be paired with the `Zend\Form\View\Helper\FormNumber` for -[HTML5 inputs with type -number](http://www.whatwg.org/specs/web-apps/current-work/multipage/states-of-the-type-attribute.html#number-state-(type=number)). -This element adds filters and validators to it's input filter specification in order to validate -HTML5 number input values on the server. - -**Basic Usage** - -This element automatically adds a `"type"` attribute of value `"number"`. - -```php -use Zend\Form\Element; -use Zend\Form\Form; - -$number = new Element\Number('quantity'); -$number - ->setLabel('Quantity') - ->setAttributes(array( - 'min' => '0', - 'max' => '10', - 'step' => '1', // default step interval is 1 - )); - -$form = new Form('my-form'); -$form->add($number); -``` - -Here is with the array notation: - -```php -use Zend\Form\Form; - -$form = new Form('my-form'); -$form->add(array( - 'type' => 'Zend\Form\Element\Number', - 'name' => 'quantity', - 'options' => array( - 'label' => 'Quantity' - ), - 'attributes' => array( - 'min' => '0', - 'max' => '10', - 'step' => '1', // default step interval is 1 - ) -)); -``` - -> ## Note -Note: the `min`, `max`, and `step` attributes should be set prior to calling Zend\\Form::prepare(). -Otherwise, the default input specification for the element may not contain the correct validation -rules. - -**Public Methods** - -The following methods are in addition to the inherited methods of Zend\\\\Form\\\\Element -<zend.form.element.methods>. - -### Range - -`Zend\Form\Element\Range` is meant to be paired with the `Zend\Form\View\Helper\FormRange` for -[HTML5 inputs with type -range](http://www.whatwg.org/specs/web-apps/current-work/multipage/states-of-the-type-attribute.html#range-state-(type=range)). -This element adds filters and validators to it's input filter specification in order to validate -HTML5 range values on the server. - -**Basic Usage** - -This element automatically adds a `"type"` attribute of value `"range"`. - -```php -use Zend\Form\Element; -use Zend\Form\Form; - -$range = new Element\Range('range'); -$range - ->setLabel('Minimum and Maximum Amount') - ->setAttributes(array( - 'min' => '0', // default minimum is 0 - 'max' => '100', // default maximum is 100 - 'step' => '1', // default interval is 1 - )); - -$form = new Form('my-form'); -$form->add($range); -``` - -Here is with the array notation: - -```php -use Zend\Form\Form; - -$form = new Form('my-form'); -$form->add(array( - 'type' => 'Zend\Form\Element\Range', - 'name' => 'range', - 'options' => array( - 'label' => 'Minimum and Maximum Amount' - ), - 'attributes' => array( - 'min' => 0, // default minimum is 0 - 'max' => 100, // default maximum is 100 - 'step' => 1 // default interval is 1 - ) -)); -``` - -> ## Note -Note: the `min`, `max`, and `step` attributes should be set prior to calling Zend\\Form::prepare(). -Otherwise, the default input specification for the element may not contain the correct validation -rules. - -**Public Methods** - -The following methods are in addition to the inherited methods of Zend\\\\Form\\\\Element\\\\Number -<zend.form.element.number.methods>. - -### Time - -`Zend\Form\Element\Time` is meant to be paired with the `Zend\Form\View\Helper\FormTime` for [HTML5 -inputs with type -time](http://www.whatwg.org/specs/web-apps/current-work/multipage/states-of-the-type-attribute.html#time-state-(type=time)). -This element adds filters and validators to it's input filter specification in order to validate -HTML5 time input values on the server. - -**Basic Usage** - -This element automatically adds a `"type"` attribute of value `"time"`. - -```php -use Zend\Form\Element; -use Zend\Form\Form; - -$time = new Element\Time('time'); -$time - ->setLabel('Time') - ->setAttributes(array( - 'min' => '00:00:00', - 'max' => '23:59:59', - 'step' => '60', // seconds; default step interval is 60 seconds - )) - ->setOptions(array( - 'format' => 'H:i:s' - )); - -$form = new Form('my-form'); -$form->add($time); -``` - -Here is the same example using the array notation: - -```php -use Zend\Form\Form; - -$form = new Form('my-form'); -$form->add(array( - 'type' => 'Zend\Form\Element\Time', - 'name' => 'time', - 'options'=> array( - 'label' => 'Time', - 'format' => 'H:i:s' - ), - 'attributes' => array( - 'min' => '00:00:00', - 'max' => '23:59:59', - 'step' => '60', // seconds; default step interval is 60 seconds - ) -)); -``` - -> ## Note -The `min`, `max`, and `step` attributes should be set prior to calling Zend\\Form::prepare(). -Otherwise, the default input specification for the element may not contain the correct validation -rules. - -> ## Note -The default date format for the validator is `H:i:s`. A valid time string is however not required to -have a seconds part. In fact some user agent UIs such as Google Chrome and Opera submits a value on -the `H:i` format (i.e. without a second part). You might therefore want to set the date format -accordingly. - -**Public Methods** - -The following methods are in addition to the inherited methods of -Zend\\\\Form\\\\Element\\\\DateTime -<zend.form.element.date-time.methods>. - -### Url - -`Zend\Form\Element\Url` is meant to be paired with the `Zend\Form\View\Helper\FormUrl` for [HTML5 -inputs with type -url](http://www.whatwg.org/specs/web-apps/current-work/multipage/states-of-the-type-attribute.html#url-state-(type=url)). -This element adds filters and a `Zend\Validator\Uri` validator to it's input filter specification -for validating HTML5 URL input values on the server. - -**Basic Usage** - -This element automatically adds a `"type"` attribute of value `"url"`. - -```php -use Zend\Form\Element; -use Zend\Form\Form; - -$url = new Element\Url('webpage-url'); -$url->setLabel('Webpage URL'); - -$form = new Form('my-form'); -$form->add($url); -``` - -Here is the same example using the array notation: - -```php -use Zend\Form\Form; - -$form = new Form('my-form'); -$form->add(array( - 'type' => 'Zend\Form\Element\Url', - 'name' => 'webpage-url', - 'options' => array( - 'label' => 'Webpage URL' - ) -)); -``` - -**Public Methods** - -The following methods are in addition to the inherited methods of Zend\\\\Form\\\\Element -<zend.form.element.methods>. - -### Week - -`Zend\Form\Element\Week` is meant to be paired with the `Zend\Form\View\Helper\FormWeek` for [HTML5 -inputs with type -week](http://www.whatwg.org/specs/web-apps/current-work/multipage/states-of-the-type-attribute.html#week-state-(type=week)). -This element adds filters and validators to it's input filter specification in order to validate -HTML5 week input values on the server. - -**Basic Usage** - -This element automatically adds a `"type"` attribute of value `"week"`. - -```php -use Zend\Form\Element; -use Zend\Form\Form; - -$week = new Element\Week('week'); -$week - ->setLabel('Week') - ->setAttributes(array( - 'min' => '2012-W01', - 'max' => '2020-W01', - 'step' => '1', // weeks; default step interval is 1 week - )); - -$form = new Form('my-form'); -$form->add($week); -``` - -Here is the same example using the array notation: - -```php -use Zend\Form\Form; - -$form = new Form('my-form'); -$form->add(array( - 'type' => 'Zend\Form\Element\Week', - 'name' => 'week', - 'options' => array( - 'label' => 'Week' - ), - 'attributes' => array( - 'min' => '2012-W01', - 'max' => '2020-W01', - 'step' => '1', // weeks; default step interval is 1 week - ) -)); -``` - -> ## Note -Note: the `min`, `max`, and `step` attributes should be set prior to calling Zend\\Form::prepare(). -Otherwise, the default input specification for the element may not contain the correct validation -rules. - -**Public Methods** - -The following methods are in addition to the inherited methods of -Zend\\\\Form\\\\Element\\\\DateTime -<zend.form.element.date-time.methods>. diff --git a/book/zend.form.file-upload.md b/book/zend.form.file-upload.md deleted file mode 100644 index 2c3b5c57..00000000 --- a/book/zend.form.file-upload.md +++ /dev/null @@ -1,660 +0,0 @@ -# File Uploading - -Zend Framework provides support for file uploading by using features in `Zend\Form`, -`Zend\InputFilter`, `Zend\Validator`, `Zend\Filter`, and `Zend\ProgressBar`. These reusable -framework components provide a convenient and secure way for handling file uploads in your projects. - -> ## Note -If the reader has experience with file uploading in Zend Framework v1.x, he/she will notice some -major differences. `Zend_File\Transfer` has been deprecated in favor of using the standard ZF2 -`Zend\Form` and `Zend\InputFilter` features. - -> ## Note -The file upload features described here are specifically for forms using the `POST` method. Zend -Framework itself does not currently provide specific support for handling uploads via the `PUT` -method, but it is possible with PHP. See the [PUT Method -Support](http://php.net/manual/en/features.file-upload.put-method.php) in the PHP documentation for -more information. - -## Standard Example - -Handling file uploads is *essentially* the same as how you would use `Zend\Form` for form -processing, but with some slight caveats that will be described below. - -In this example we will: - -- Define a **Form** for backend validation and filtering. -- Create a **view template** with a `
` containing a file input. -- Process the form within a **Controller action**. - -### The Form and InputFilter - -Here we define a `Zend\Form\Element\File` input in a Form class named `UploadForm`. - -```php -// File: UploadForm.php - -use Zend\Form\Element; -use Zend\Form\Form; - -class UploadForm extends Form -{ - public function __construct($name = null, $options = array()) - { - parent::__construct($name, $options); - $this->addElements(); - } - - public function addElements() - { - // File Input - $file = new Element\File('image-file'); - $file->setLabel('Avatar Image Upload') - ->setAttribute('id', 'image-file'); - $this->add($file); - } -} -``` - -The `File` element provides some automatic features that happen behind the scenes: - -- The form's `enctype` will automatically be set to `multipart/form-data` when the form `prepare()` - method is called. -- The file element's default input specification will create the correct `Input` type: - \[Zend\\InputFilter\\FileInput\](zend.input-filter.file-input). -- The `FileInput` will automatically prepend an \[UploadFile - Validator\](zend.validator.file.upload-file), to securely validate that the file is actually an - uploaded file, and to report other types of upload errors to the user. - -### The View Template - -In the view template we render the ``, a file input (with label and errors), and a submit -button. - -```php -// File: upload-form.phtml -prepare(); // The correct enctype is set here ?> -form()->openTag($form); ?> - -
- get('image-file'); ?> - formLabel($fileElement); ?> - formFile($fileElement); ?> - formElementErrors($fileElement); ?> -
- - - -form()->closeTag(); ?> -``` - -When rendered, the HTML should look similar to: - -```html - -
- - -
- - -
-``` - -### The Controller Action - -For the final step, we will instantiate the `UploadForm` and process any postbacks in a Controller -action. - -The form processing in the controller action will be similar to normal forms, *except* that you -**must** merge the `$_FILES` information in the request with the other post data. - -```php -// File: MyController.php - -public function uploadFormAction() -{ - $form = new UploadForm('upload-form'); - - $request = $this->getRequest(); - if ($request->isPost()) { - // Make certain to merge the files info! - $post = array_merge_recursive( - $request->getPost()->toArray(), - $request->getFiles()->toArray() - ); - - $form->setData($post); - if ($form->isValid()) { - $data = $form->getData(); - // Form is valid, save the form! - return $this->redirect()->toRoute('upload-form/success'); - } - } - - return array('form' => $form); -} -``` - -Upon a successful file upload, `$form->getData()` would return: - -```php -array(1) { - ["image-file"] => array(5) { - ["name"] => string(11) "myimage.png" - ["type"] => string(9) "image/png" - ["tmp_name"] => string(22) "/private/tmp/phpgRXd58" - ["error"] => int(0) - ["size"] => int(14908679) - } -} -``` - -> ## Note -It is suggested that you always use the `Zend\Http\PhpEnvironment\Request` object to retrieve and -merge the `$_FILES` information with the form, instead of using `$_FILES` directly. -This is due to how the file information is mapped in the `$_FILES` array: - -```php -// A $_FILES array with single input and multiple files: -array(1) { -["image-file"]=array(2) { -["name"]=array(2) { -[0]=string(9)"file0.txt" -[1]=string(9)"file1.txt" -} -["type"]=array(2) { -[0]=string(10)"text/plain" -[1]=string(10)"text/html" -} -} -} -// How Zend\Http\PhpEnvironment\Request remaps the $_FILES array: -array(1) { -["image-file"]=array(2) { -[0]=array(2) { -["name"]=string(9)"file0.txt" -["type"]=string(10)"text/plain" -}, -[1]=array(2) { -["name"]=string(9)"file1.txt" -["type"]=string(10)"text/html" -} -} -} -``` - -\[Zend\\InputFilter\\FileInput\](zend.input-filter.file-input) expects the file data be in this -re-mapped array format. - -## File Post-Redirect-Get Plugin - -When using other standard form inputs (i.e. `text`, `checkbox`, `select`, etc.) along with file -inputs in a Form, you can encounter a situation where some inputs may become invalid and the user -must re-select the file and re-upload. PHP will delete uploaded files from the temporary directory -at the end of the request if it has not been moved away or renamed. Re-uploading a valid file each -time another form input is invalid is inefficient and annoying to users. - -One strategy to get around this is to split the form into multiple forms. One form for the file -upload inputs and another for the other standard inputs. - -When you cannot separate the forms, the \[File Post-Redirect-Get Controller -Plugin\](zend.mvc.controller-plugins.file-postredirectget) can be used to manage the file inputs and -save off valid uploads until the entire form is valid. - -Changing our earlier example to use the `fileprg` plugin will require two changes. - -1. Adding a `RenameUpload` filter to our form's file input, with details on where the valid files -should be stored: - - ```php - // File: UploadForm.php - - use Zend\InputFilter; - use Zend\Form\Element; - use Zend\Form\Form; - - class UploadForm extends Form - { - public function __construct($name = null, $options = array()) - { - parent::__construct($name, $options); - $this->addElements(); - $this->addInputFilter(); - } - - public function addElements() - { - // File Input - $file = new Element\File('image-file'); - $file->setLabel('Avatar Image Upload') - ->setAttribute('id', 'image-file'); - $this->add($file); - } - - public function addInputFilter() - { - $inputFilter = new InputFilter\InputFilter(); - - // File Input - $fileInput = new InputFilter\FileInput('image-file'); - $fileInput->setRequired(true); - $fileInput->getFilterChain()->attachByName( - 'filerenameupload', - array( - 'target' => './data/tmpuploads/avatar.png', - 'randomize' => true, - ) - ); - $inputFilter->add($fileInput); - - $this->setInputFilter($inputFilter); - } - } - ``` - - The `filerenameupload` options above would cause an uploaded file to be renamed and moved to: -`./data/tmpuploads/avatar_4b3403665fea6.png`. - - See the \[RenameUpload filter\](zend.filter.file.rename-upload) documentation for more -information on its supported options. - -2. And, changing the Controller action to use the `fileprg` plugin: - - ```php - // File: MyController.php - - public function uploadFormAction() - { - $form = new UploadForm('upload-form'); - $tempFile = null; - - $prg = $this->fileprg($form); - if ($prg instanceof \Zend\Http\PhpEnvironment\Response) { - return $prg; // Return PRG redirect response - } elseif (is_array($prg)) { - if ($form->isValid()) { - $data = $form->getData(); - // Form is valid, save the form! - return $this->redirect()->toRoute('upload-form/success'); - } else { - // Form not valid, but file uploads might be valid... - // Get the temporary file information to show the user in the view - $fileErrors = $form->get('image-file')->getMessages(); - if (empty($fileErrors)) { - $tempFile = $form->get('image-file')->getValue(); - } - } - } - - return array( - 'form' => $form, - 'tempFile' => $tempFile, - ); - } - ``` - -Behind the scenes, the `FilePRG` plugin will: - -- Run the Form's filters, namely the `RenameUpload` filter, to move the files out of temporary - storage. -- Store the valid POST data in the session across requests. -- Change the `required` flag of any file inputs that had valid uploads to `false`. This is so that - form re-submissions without uploads will not cause validation errors. - -> ## Note -In the case of a partially valid form, it is up to the developer whether to notify the user that -files have been uploaded or not. For example, you may wish to hide the form input and/or display the -file information. These things would be implementation details in the view or in a custom view -helper. Just note that neither the `FilePRG` plugin nor the `formFile` view helper will do any -automatic notifications or view changes when files have been successfully uploaded. - -## HTML5 Multi-File Uploads - -With HTML5 we are able to select multiple files from a single file input using the `multiple` -attribute. Not all [browsers support multiple file uploads](http://caniuse.com/#feat=forms), but the -file input will safely remain a single file upload for those browsers that do not support the -feature. - -To enable multiple file uploads in Zend Framework, just set the file element's `multiple` attribute -to true: - -```php -// File: UploadForm.php - -use Zend\InputFilter; -use Zend\Form\Element; -use Zend\Form\Form; - -class UploadForm extends Form -{ - public function __construct($name = null, $options = array()) - { - parent::__construct($name, $options); - $this->addElements(); - $this->addInputFilter(); - } - - public function addElements() - { - // File Input - $file = new Element\File('image-file'); - $file->setLabel('Avatar Image Upload') - ->setAttribute('id', 'image-file') - ->setAttribute('multiple', true); // That's it - $this->add($file); - } - - public function addInputFilter() - { - $inputFilter = new InputFilter\InputFilter(); - - // File Input - $fileInput = new InputFilter\FileInput('image-file'); - $fileInput->setRequired(true); - - // You only need to define validators and filters - // as if only one file was being uploaded. All files - // will be run through the same validators and filters - // automatically. - $fileInput->getValidatorChain() - ->attachByName('filesize', array('max' => 204800)) - ->attachByName('filemimetype', array('mimeType' => 'image/png,image/x-png')) - ->attachByName('fileimagesize', array('maxWidth' => 100, 'maxHeight' => 100)); - - // All files will be renamed, i.e.: - // ./data/tmpuploads/avatar_4b3403665fea6.png, - // ./data/tmpuploads/avatar_5c45147660fb7.png - $fileInput->getFilterChain()->attachByName( - 'filerenameupload', - array( - 'target' => './data/tmpuploads/avatar.png', - 'randomize' => true, - ) - ); - $inputFilter->add($fileInput); - - $this->setInputFilter($inputFilter); - } -} -``` - -You do not need to do anything special with the validators and filters to support multiple file -uploads. All of the files that are uploaded will have the same validators and filters run against -them automatically (from logic within `FileInput`). You only need to define them as if one file was -being uploaded. - -## Upload Progress - -While pure client-based upload progress meters are starting to become available with [HTML5's -Progress Events](http://www.w3.org/TR/progress-events/), not all browsers have [XMLHttpRequest level -2 support](http://caniuse.com/#feat=xhr2). For upload progress to work in a greater number of -browsers (IE9 and below), you must use a server-side progress solution. - -`Zend\ProgressBar\Upload` provides handlers that can give you the actual state of a file upload in -progress. To use this feature you need to choose one of the \[Upload Progress -Handlers\](zend.progress-bar.upload) (APC, uploadprogress, or Session) and ensure that your server -setup has the appropriate extension or feature enabled. - -> ## Note -For this example we will use PHP **5.4**'s [Session progress -handler](http://php.net/manual/en/session.upload-progress.php) -**PHP 5.4 is required** and you may need to verify these php.ini settings for it to work: - -```php -file_uploads = On -post_max_size = 50M -upload_max_filesize = 50M -session.upload_progress.enabled = On -session.upload_progress.freq = "1%" -session.upload_progress.min_freq = "1" -; Also make certain 'upload_tmp_dir' is writable -``` - -When uploading a file with a form POST, you must also include the progress identifier in a hidden -input. The \[File Upload Progress View Helpers\](zend.form.view.helper.file) provide a convenient -way to add the hidden input based on your handler type. - -```php -// File: upload-form.phtml -prepare(); ?> -form()->openTag($form); ?> - formFileSessionProgress(); // Must come before the file input! ?> - -
- get('image-file'); ?> - formLabel($fileElement); ?> - formFile($fileElement); ?> - formElementErrors($fileElement); ?> -
- - - -form()->closeTag(); ?> -``` - -When rendered, the HTML should look similar to: - -```html -
- - -
- - -
- - -
-``` - -There are a few different methods for getting progress information to the browser (long vs. short -polling). Here we will use short polling since it is simpler and less taxing on server resources, -though keep in mind it is not as responsive as long polling. - -When our form is submitted via AJAX, the browser will continuously poll the server for upload -progress. - -The following is an example Controller action which provides the progress information: - -```php -// File: MyController.php - -public function uploadProgressAction() -{ - $id = $this->params()->fromQuery('id', null); - $progress = new \Zend\ProgressBar\Upload\SessionProgress(); - return new \Zend\View\Model\JsonModel($progress->getProgress($id)); -} - -// Returns JSON -//{ -// "total" : 204800, -// "current" : 10240, -// "rate" : 1024, -// "message" : "10kB / 200kB", -// "done" : false -//} -``` - -> ## Warning -This is *not* the most efficient way of providing upload progress, since each polling request must -go through the Zend Framework bootstrap process. A better example would be to use a standalone php -file in the public folder that bypasses the MVC bootstrapping and only uses the essential -`Zend\ProgressBar` adapters. - -Back in our view template, we will add the JavaScript to perform the AJAX POST of the form data, and -to start a timeout interval for the progress polling. To keep the example code relatively short, we -are using the [jQuery Form plugin](https://github.com/malsup/form) to do the AJAX form POST. If your -project uses a different JavaScript framework (or none at all), this will hopefully at least -illustrate the necessary high-level logic that would need to be performed. - -```html - - - - -
-
-
-
-

-
- - - - -``` - -And finally, our Controller action can be modified to return form status and validation messages in -JSON format if we see the 'isAjax' post parameter (which was set in the JavaScript just before -submit): - -```php -// File: MyController.php - -public function uploadFormAction() -{ - $form = new UploadForm('upload-form'); - - $request = $this->getRequest(); - if ($request->isPost()) { - // Make certain to merge the files info! - $post = array_merge_recursive( - $request->getPost()->toArray(), - $request->getFiles()->toArray() - ); - - $form->setData($post); - if ($form->isValid()) { - $data = $form->getData(); - // Form is valid, save the form! - if (!empty($post['isAjax'])) { - return new JsonModel(array( - 'status' => true, - 'redirect' => $this->url()->fromRoute('upload-form/success'), - 'formData' => $data, - )); - } else { - // Fallback for non-JS clients - return $this->redirect()->toRoute('upload-form/success'); - } - } else { - if (!empty($post['isAjax'])) { - // Send back failure information via JSON - return new JsonModel(array( - 'status' => false, - 'formErrors' => $form->getMessages(), - 'formData' => $form->getData(), - )); - } - } - } - - return array('form' => $form); -} -``` - -## Additional Info - -Related documentation: - -- \[Form File Element\](zend.form.element.file) -- \[Form File View Helper\](zend.form.view.helper.form-file) -- \[List of File Validators\](zend.validator.file) -- \[List of File Filters\](zend.filter.file) -- \[File Post-Redirect-Get Controller Plugin\](zend.mvc.controller-plugins.file-postredirectget) -- \[Zend\\InputFilter\\FileInput\](zend.input-filter.file-input) -- \[Upload Progress Handlers\](zend.progress-bar.upload) -- \[Upload Progress View Helpers\](zend.form.view.helper.file) - -External resources and blog posts from the community: - -- [ZF2FileUploadExamples](https://github.com/cgmartin/ZF2FileUploadExamples) : A ZF2 module with - several file upload examples. - diff --git a/book/zend.form.intro.md b/book/zend.form.intro.md deleted file mode 100644 index c862c5fb..00000000 --- a/book/zend.form.intro.md +++ /dev/null @@ -1,32 +0,0 @@ -# Introduction - -`Zend\Form` is intended primarily as a bridge between your domain models and the View Layer. It -composes a thin layer of objects representing form elements, an \[InputFilter\](zend.input-filter), -and a small number of methods for binding data to and from the form and attached objects. - -The `Zend\Form` component consists of the following objects: - -- `Elements`, which simply consist of a name and attributes. -- `Fieldsets`, which extend from `Elements`, but allow composing other fieldsets and elements. -- `Forms`, which extend from `Fieldsets` (and thus `Elements`). They provide data and object - binding, and compose \[InputFilters\](zend.input-filter.intro). Data binding is done via - \[Zend\\Stdlib\\Hydrator\](zend.stdlib.hydrator). - -To facilitate usage with the view layer, the `Zend\Form` component also aggregates a number of -form-specific view helpers. These accept elements, fieldsets, and/or forms, and use the attributes -they compose to render markup. - -A small number of specialized elements are provided for accomplishing application-centric tasks. -These include the `Csrf` element, used to prevent Cross Site Request Forgery attacks, and the -`Captcha` element, used to display and validate \[CAPTCHAs\](zend.captcha). - -A `Factory` is provided to facilitate creation of elements, fieldsets, forms, and the related input -filter. The default `Form` implementation is backed by a factory to facilitate extension and ease -the process of form creation. - -The code related to forms can often spread between a variety of concerns: a form definition, an -input filter definition, a domain model class, and one or more hydrator implementations. As such, -finding the various bits of code and how they relate can become tedious. To simplify the situation, -you can also annotate your domain model class, detailing the various input filter definitions, -attributes, and hydrators that should all be used together. `Zend\Form\Annotation\AnnotationBuilder` -can then be used to build the various objects you need. diff --git a/book/zend.form.quick-start.md b/book/zend.form.quick-start.md deleted file mode 100644 index 65462c34..00000000 --- a/book/zend.form.quick-start.md +++ /dev/null @@ -1,975 +0,0 @@ -# Quick Start - -Forms are relatively easy to create. At the bare minimum, each element or fieldset requires a name; -typically, you'll also provide some attributes to hint to the view layer how it might render the -item. The form itself will also typically compose an `InputFilter`-- which you can also conveniently -create directly in the form via a factory. Individual elements can hint as to what defaults to use -when generating a related input for the input filter. - -Form validation is as easy as providing an array of data to the `setData()` method. If you want to -simplify your work even more, you can bind an object to the form; on successful validation, it will -be populated from the validated values. - -## Programmatic Form Creation - -If nothing else, you can simply start creating elements, fieldsets, and forms and wiring them -together. - -```php -use Zend\Captcha; -use Zend\Form\Element; -use Zend\Form\Fieldset; -use Zend\Form\Form; -use Zend\InputFilter\Input; -use Zend\InputFilter\InputFilter; - -$name = new Element('name'); -$name->setLabel('Your name'); -$name->setAttributes(array( - 'type' => 'text' -)); - -$email = new Element\Email('email'); -$email->setLabel('Your email address'); - -$subject = new Element('subject'); -$subject->setLabel('Subject'); -$subject->setAttributes(array( - 'type' => 'text' -)); - -$message = new Element\Textarea('message'); -$message->setLabel('Message'); - -$captcha = new Element\Captcha('captcha'); -$captcha->setCaptcha(new Captcha\Dumb()); -$captcha->setLabel('Please verify you are human'); - -$csrf = new Element\Csrf('security'); - -$send = new Element('send'); -$send->setValue('Submit'); -$send->setAttributes(array( - 'type' => 'submit' -)); - - -$form = new Form('contact'); -$form->add($name); -$form->add($email); -$form->add($subject); -$form->add($message); -$form->add($captcha); -$form->add($csrf); -$form->add($send); - -$nameInput = new Input('name'); -// configure input... and all others -$inputFilter = new InputFilter(); -// attach all inputs - -$form->setInputFilter($inputFilter); -``` - -As a demonstration of fieldsets, let's alter the above slightly. We'll create two fieldsets, one for -the sender information, and another for the message details. - -```php -$sender = new Fieldset('sender'); -$sender->add($name); -$sender->add($email); - -$details = new Fieldset('details'); -$details->add($subject); -$details->add($message); - -$form = new Form('contact'); -$form->add($sender); -$form->add($details); -$form->add($captcha); -$form->add($csrf); -$form->add($send); -``` - -Regardless of approach, as you can see, this can be tedious. - -## Creation via Factory - -You can create the entire form, and input filter, using the `Factory`. This is particularly nice if -you want to store your forms as pure configuration; you can simply pass the configuration to the -factory and be done. - -```php -use Zend\Form\Factory; - -$factory = new Factory(); -$form = $factory->createForm(array( - 'hydrator' => 'Zend\Stdlib\Hydrator\ArraySerializable', - 'elements' => array( - array( - 'spec' => array( - 'name' => 'name', - 'options' => array( - 'label' => 'Your name', - ), - 'type' => 'Text', - ) - ), - array( - 'spec' => array( - 'type' => 'Zend\Form\Element\Email', - 'name' => 'email', - 'options' => array( - 'label' => 'Your email address', - ) - ), - ), - array( - 'spec' => array( - 'name' => 'subject', - 'options' => array( - 'label' => 'Subject', - ), - 'type' => 'Text', - ), - ), - array( - 'spec' => array( - 'type' => 'Zend\Form\Element\Textarea', - 'name' => 'message', - 'options' => array( - 'label' => 'Message', - ) - ), - ), - array( - 'spec' => array( - 'type' => 'Zend\Form\Element\Captcha', - 'name' => 'captcha', - 'options' => array( - 'label' => 'Please verify you are human.', - 'captcha' => array( - 'class' => 'Dumb', - ), - ), - ), - ), - array( - 'spec' => array( - 'type' => 'Zend\Form\Element\Csrf', - 'name' => 'security', - ), - ), - array( - 'spec' => array( - 'name' => 'send', - 'type' => 'Submit', - 'attributes' => array( - 'value' => 'Submit', - ), - ), - ), - ), - /* If we had fieldsets, they'd go here; fieldsets contain - * "elements" and "fieldsets" keys, and potentially a "type" - * key indicating the specific FieldsetInterface - * implementation to use. - 'fieldsets' => array( - ), - */ - - // Configuration to pass on to - // Zend\InputFilter\Factory::createInputFilter() - 'input_filter' => array( - /* ... */ - ), -)); -``` - -If we wanted to use fieldsets, as we demonstrated in the previous example, we could do the -following: - -```php -use Zend\Form\Factory; - -$factory = new Factory(); -$form = $factory->createForm(array( - 'hydrator' => 'Zend\Stdlib\Hydrator\ArraySerializable', - 'fieldsets' => array( - array( - 'spec' => array( - 'name' => 'sender', - 'elements' => array( - array( - 'spec' => array( - 'name' => 'name', - 'options' => array( - 'label' => 'Your name', - ), - 'type' => 'Text' - ), - ), - array( - 'spec' => array( - 'type' => 'Zend\Form\Element\Email', - 'name' => 'email', - 'options' => array( - 'label' => 'Your email address', - ), - ), - ), - ), - ), - ), - array( - 'spec' => array( - 'name' => 'details', - 'elements' => array( - array( - 'spec' => array( - 'name' => 'subject', - 'options' => array( - 'label' => 'Subject', - ), - 'type' => 'Text', - ), - ), - array( - 'spec' => array( - 'name' => 'message', - 'type' => 'Zend\Form\Element\Textarea', - 'options' => array( - 'label' => 'Message', - ), - ), - ), - ), - ), - ), - ), - 'elements' => array( - array( - 'spec' => array( - 'type' => 'Zend\Form\Element\Captcha', - 'name' => 'captcha', - 'options' => array( - 'label' => 'Please verify you are human. ', - 'captcha' => array( - 'class' => 'Dumb', - ), - ), - ), - ), - array( - 'spec' => array( - 'type' => 'Zend\Form\Element\Csrf', - 'name' => 'security', - ), - ), - array( - 'spec' => array( - 'name' => 'send', - 'type' => 'Submit', - 'attributes' => array( - 'value' => 'Submit', - ), - ), - ), - ), - // Configuration to pass on to - // Zend\InputFilter\Factory::createInputFilter() - 'input_filter' => array( - /* ... */ - ), -)); -``` - -Note that the chief difference is nesting; otherwise, the information is basically the same. - -The chief benefits to using the `Factory` are allowing you to store definitions in configuration, -and usage of significant whitespace. - -## Factory-backed Form Extension - -The default `Form` implementation is backed by the `Factory`. This allows you to extend it, and -define your form internally. This has the benefit of allowing a mixture of programmatic and -factory-backed creation, as well as defining a form for re-use in your application. - -```php -namespace Contact; - -use Zend\Captcha\AdapterInterface as CaptchaAdapter; -use Zend\Form\Element; -use Zend\Form\Form; - -class ContactForm extends Form -{ - protected $captcha; - - public function __construct(CaptchaAdapter $captcha) - { - - parent::__construct(); - - $this->captcha = $captcha; - - // add() can take either an Element/Fieldset instance, - // or a specification, from which the appropriate object - // will be built. - - $this->add(array( - 'name' => 'name', - 'options' => array( - 'label' => 'Your name', - ), - 'type' => 'Text', - )); - $this->add(array( - 'type' => 'Zend\Form\Element\Email', - 'name' => 'email', - 'options' => array( - 'label' => 'Your email address', - ), - )); - $this->add(array( - 'name' => 'subject', - 'options' => array( - 'label' => 'Subject', - ), - 'type' => 'Text', - )); - $this->add(array( - 'type' => 'Zend\Form\Element\Textarea', - 'name' => 'message', - 'options' => array( - 'label' => 'Message', - ), - )); - $this->add(array( - 'type' => 'Zend\Form\Element\Captcha', - 'name' => 'captcha', - 'options' => array( - 'label' => 'Please verify you are human.', - 'captcha' => $this->captcha, - ), - )); - $this->add(new Element\Csrf('security')); - $this->add(array( - 'name' => 'send', - 'type' => 'Submit', - 'attributes' => array( - 'value' => 'Submit', - ), - )); - - // We could also define the input filter here, or - // lazy-create it in the getInputFilter() method. - } -} -``` - -You'll note that this example, the elements are added in the constructor. This is done to allow -altering and/or configuring either the form or input filter factory instances, which could then have -bearing on how elements, inputs, etc. are created. In this case, it also allows injection of the -CAPTCHA adapter, allowing us to configure it elsewhere in our application and inject it into the -form. - -## Validating Forms - -Validating forms requires three steps. First, the form must have an input filter attached. Second, -you must inject the data to validate into the form. Third, you validate the form. If invalid, you -can retrieve the error messages, if any. - -```php -// assuming $captcha is an instance of some Zend\Captcha\AdapterInterface -$form = new Contact\ContactForm($captcha); - -// If the form doesn't define an input filter by default, inject one. -$form->setInputFilter(new Contact\ContactFilter()); - -// Get the data. In an MVC application, you might try: -$data = $request->getPost(); // for POST data -$data = $request->getQuery(); // for GET (or query string) data - -$form->setData($data); - -// Validate the form -if ($form->isValid()) { - $validatedData = $form->getData(); -} else { - $messages = $form->getMessages(); -} -``` - -You can get the raw data if you want, by accessing the composed input filter. - -```php -$filter = $form->getInputFilter(); - -$rawValues = $filter->getRawValues(); -$nameRawValue = $filter->getRawValue('name'); -``` - -## Hinting to the Input Filter - -Often, you'll create elements that you expect to behave in the same way on each usage, and for which -you'll want specific filters or validation as well. Since the input filter is a separate object, how -can you achieve these latter points? - -Because the default form implementation composes a factory, and the default factory composes an -input filter factory, you can have your elements and/or fieldsets hint to the input filter. If no -input or input filter is provided in the input filter for that element, these hints will be -retrieved and used to create them. - -To do so, one of the following must occur. For elements, they must implement -`Zend\InputFilter\InputProviderInterface`, which defines a `getInputSpecification()` method; for -fieldsets, they must implement `Zend\InputFilter\InputFilterProviderInterface`, which defines a -`getInputFilterSpecification()` method. - -In the case of an element, the `getInputSpecification()` method should return data to be used by the -input filter factory to create an input. Every HTML5 (email, url, color…) elements have a built-in -element that use this logic. For instance, here is how the `Zend\Form\Element\Color` element is -defined: - -```php -namespace Zend\Form\Element; - -use Zend\Form\Element; -use Zend\InputFilter\InputProviderInterface; -use Zend\Validator\Regex as RegexValidator; -use Zend\Validator\ValidatorInterface; - -class Color extends Element implements InputProviderInterface -{ - /** - * Seed attributes - * - * @var array - */ - protected $attributes = array( - 'type' => 'color', - ); - - /** - * @var ValidatorInterface - */ - protected $validator; - - /** - * Get validator - * - * @return ValidatorInterface - */ - protected function getValidator() - { - if (null === $this->validator) { - $this->validator = new RegexValidator('/^#[0-9a-fA-F]{6}$/'); - } - return $this->validator; - } - - /** - * Provide default input rules for this element - * - * Attaches an email validator. - * - * @return array - */ - public function getInputSpecification() - { - return array( - 'name' => $this->getName(), - 'required' => true, - 'filters' => array( - array('name' => 'Zend\Filter\StringTrim'), - array('name' => 'Zend\Filter\StringToLower'), - ), - 'validators' => array( - $this->getValidator(), - ), - ); - } -} -``` - -The above would hint to the input filter to create and attach an input named after the element, -marking it as required, and giving it a `StringTrim` and `StringToLower` filters and a `Regex` -validator. Note that you can either rely on the input filter to create filters and validators, or -directly instantiate them. - -For fieldsets, you do very similarly; the difference is that `getInputFilterSpecification()` must -return configuration for an input filter. - -```php -namespace Contact\Form; - -use Zend\Form\Fieldset; -use Zend\InputFilter\InputFilterProviderInterface; -use Zend\Validator; - -class SenderFieldset extends Fieldset implements InputFilterProviderInterface -{ - public function getInputFilterSpecification() - { - return array( - 'name' => array( - 'required' => true, - 'filters' => array( - array('name' => 'Zend\Filter\StringTrim'), - ), - 'validators' => array( - array( - 'name' => 'Zend\Validator\StringLength', - 'options' => array( - 'min' => 3, - 'max' => 256 - ), - ), - ), - ), - 'email' => array( - 'required' => true, - 'filters' => array( - array('name' => 'Zend\Filter\StringTrim'), - ), - 'validators' => array( - new Validator\EmailAddress(), - ), - ), - ); - } -} -``` - -Specifications are a great way to make forms, fieldsets, and elements re-usable trivially in your -applications. In fact, the `Captcha` and `Csrf` elements define specifications in order to ensure -they can work without additional user configuration! - -> ## Note -If you set custom input filter specification either in `getInputSpecification()` or in -`getInputFilterSpecification()`, the `Zend\InputFilter\InputInterface` set for that specific field -is reset to the default `Zend\InputFilter\Input`. -Some form elements may need a particular input filter, like `Zend\Form\Element\File`: in this case -it's mandatory to specify the `type` key in your custom specification to match the original one (in -ex. for the file element it's `Zend\InputFilter\FileInput`). - -## Binding an object - -As noted in the intro, forms in Zend Framework bridge the domain model and the view layer. Let's see -that in action. - -When you `bind()` an object to the form, the following happens: - -- The composed `Hydrator` calls `extract()` on the object, and uses the values returned, if any, to - populate the `value` attributes of all elements. If a form contains a fieldset that itself contains - another fieldset, the form will recursively extract the values. -- When `isValid()` is called, if `setData()` has not been previously set, the form uses the composed - `Hydrator` to extract values from the object, and uses those during validation. -- If `isValid()` is successful (and the `bindOnValidate` flag is enabled, which is true by default), - then the `Hydrator` will be passed the validated values to use to hydrate the bound object. (If you - do not want this behavior, call `setBindOnValidate(FormInterface::BIND_MANUAL)`). -- If the object implements `Zend\InputFilter\InputFilterAwareInterface`, the input filter it - composes will be used instead of the one composed on the form. - -This is easier to understand in practice. - -```php -$contact = new ArrayObject; -$contact['subject'] = '[Contact Form] '; -$contact['message'] = 'Type your message here'; - -$form = new Contact\ContactForm; - -$form->bind($contact); // form now has default values for - // 'subject' and 'message' - -$data = array( - 'name' => 'John Doe', - 'email' => 'j.doe@example.tld', - 'subject' => '[Contact Form] \'sup?', -); -$form->setData($data); - -if ($form->isValid()) { - // $contact now looks like: - // array( - // 'name' => 'John Doe', - // 'email' => 'j.doe@example.tld', - // 'subject' => '[Contact Form] \'sup?', - // 'message' => 'Type your message here', - // ) - // only as an ArrayObject -} -``` - -When an object is bound to the form, calling `getData()` will return that object by default. If you -want to return an associative array instead, you can pass the `FormInterface::VALUES_AS_ARRAY` flag -to the method. - -```php -use Zend\Form\FormInterface; -$data = $form->getData(FormInterface::VALUES_AS_ARRAY); -``` - -Zend Framework ships several standard \[hydrators\](zend.stdlib.hydrator), and implementation is as -simple as implementing `Zend\Stdlib\Hydrator\HydratorInterface`, which looks like this: - -```php -namespace Zend\Stdlib\Hydrator; - -interface HydratorInterface -{ - /** @return array */ - public function extract($object); - public function hydrate(array $data, $object); -} -``` - -## Rendering - -As noted previously, forms are meant to bridge the domain model and view layer. We've discussed the -domain model binding, but what about the view? - -The form component ships a set of form-specific view helpers. These accept the various form objects, -and introspect them in order to generate markup. Typically, they will inspect the attributes, but in -special cases, they may look at other properties and composed objects. - -When preparing to render, you will likely want to call `prepare()`. This method ensures that certain -injections are done, and will likely in the future munge names to allow for -`scoped[array][notation]`. - -The simplest view helpers available are `Form`, `FormElement`, `FormLabel`, and `FormElementErrors`. -Let's use them to display the contact form. - -```php -form; -$form->prepare(); - -// Assuming the "contact/process" route exists... -$form->setAttribute('action', $this->url('contact/process')); - -// Set the method attribute for the form -$form->setAttribute('method', 'post'); - -// Get the form label plugin -$formLabel = $this->plugin('formLabel'); - -// Render the opening tag -echo $this->form()->openTag($form); -?> -
-get('name'); - echo $formLabel->openTag() . $name->getOption('label'); - echo $this->formInput($name); - echo $this->formElementErrors($name); - echo $formLabel->closeTag(); -?>
- -
-get('subject'); - echo $formLabel->openTag() . $subject->getOption('label'); - echo $this->formInput($subject); - echo $this->formElementErrors($subject); - echo $formLabel->closeTag(); -?>
- -
-get('message'); - echo $formLabel->openTag() . $message->getOption('label'); - echo $this->formTextarea($message); - echo $this->formElementErrors($message); - echo $formLabel->closeTag(); -?>
- -
-get('captcha'); - echo $formLabel->openTag() . $captcha->getOption('label'); - echo $this->formCaptcha($captcha); - echo $this->formElementErrors($captcha); - echo $formLabel->closeTag(); -?>
- -formElement($form->get('security')) ?> -formElement($form->get('send')) ?> - -form()->closeTag() ?> -``` - -There are a few things to note about this. First, to prevent confusion in IDEs and editors when -syntax highlighting, we use helpers to both open and close the form and label tags. Second, there's -a lot of repetition happening here; we could easily create a partial view script or a composite -helper to reduce boilerplate. Third, note that not all elements are created equal -- the CSRF and -submit elements don't need labels or error messages necessarily. Finally, note that the -`FormElement` helper tries to do the right thing -- it delegates actual markup generation to other -view helpers; however, it can only guess what specific form helper to delegate to based on the list -it has. If you introduce new form view helpers, you'll need to extend the `FormElement` helper, or -create your own. - -However, your view files can quickly become long and repetitive to write. While we do not currently -provide a single-line form view helper (as this reduces the form customization), the simplest and -most recommended way to render your form is by using the `FormRow` view helper. This view helper -automatically renders a label (if present), the element itself using the `FormElement` helper, as -well as any errors that could arise. Here is the previous form, rewritten to take advantage of this -helper : - -```php -form; -$form->prepare(); - -// Assuming the "contact/process" route exists... -$form->setAttribute('action', $this->url('contact/process')); - -// Set the method attribute for the form -$form->setAttribute('method', 'post'); - -// Render the opening tag -echo $this->form()->openTag($form); -?> -
-get('name'); - echo $this->formRow($name); -?>
- -
-get('subject'); - echo $this->formRow($subject); -?>
- -
-get('message'); - echo $this->formRow($message); -?>
- -
-get('captcha'); - echo $this->formRow($captcha); -?>
- -formElement($form->get('security')) ?> -formElement($form->get('send')) ?> - -form()->closeTag() ?> -``` - -Note that `FormRow` helper automatically prepends the label. If you want it to be rendered after the -element itself, you can pass an optional parameter to the `FormRow` view helper : - -```php -
-get('name'); - echo $this->formRow($name, 'append'); -?>
-``` - -### Taking advantage of HTML5 input attributes - -HTML5 brings a lot of exciting features, one of them being a simplified client form validations. -Adding HTML5 attributes is simple as you just need to add specify the attributes. However, please -note that adding those attributes does not automatically add Zend validators to the form's input -filter. You still need to manually add them. - -```php -$form->add(array( - 'name' => 'phoneNumber', - 'options' => array( - 'label' => 'Your phone number' - ), - 'attributes' => array( - 'type' => 'tel' - 'required' => 'required', - 'pattern' => '^0[1-68]([-. ]?[0-9]{2}){4}$' - ) -)); -``` - -View helpers will automatically render those attributes, and hence allowing modern browsers to -perform automatic validation. - -> ## Note -Although client validation is nice from a user experience point of view, it has to be used in -addition with server validation, as client validation can be easily fooled. - -## Validation Groups - -Sometimes you want to validate only a subset of form elements. As an example, let's say we're -re-using our contact form over a web service; in this case, the `Csrf`, `Captcha`, and submit button -elements are not of interest, and shouldn't be validated. - -`Zend\Form` provides a proxy method to the underlying `InputFilter`'s `setValidationGroup()` method, -allowing us to perform this operation. - -```php -$form->setValidationGroup('name', 'email', 'subject', 'message'); -$form->setData($data); -if ($form->isValid()) { - // Contains only the "name", "email", "subject", and "message" values - $data = $form->getData(); -} -``` - -If you later want to reset the form to validate all, simply pass the `FormInterface::VALIDATE_ALL` -flag to the `setValidationGroup()` method. - -```php -use Zend\Form\FormInterface; -$form->setValidationGroup(FormInterface::VALIDATE_ALL); -``` - -When your form contains nested fieldsets, you can use an array notation to validate only a subset of -the fieldsets : - -```php -$form->setValidationGroup(array( - 'profile' => array( - 'firstname', - 'lastname' - ) -)); -$form->setData($data); -if ($form->isValid()) { - // Contains only the "firstname" and "lastname" values from the - // "profile" fieldset - $data = $form->getData(); -} -``` - -## Using Annotations - -Creating a complete forms solution can often be tedious: you'll create some domain model object, an -input filter for validating it, a form object for providing a representation for it, and potentially -a hydrator for mapping the form elements and fieldsets to the domain model. Wouldn't it be nice to -have a central place to define all of these? - -Annotations allow us to solve this problem. You can define the following behaviors with the shipped -annotations in `Zend\Form`: - -- *AllowEmpty*: mark an input as allowing an empty value. This annotation does not require a value. -- *Attributes*: specify the form, fieldset, or element attributes. This annotation requires an - associative array of values, in a JSON object format: - `@Attributes({"class":"zend_form","type":"text"})`. -- *ComposedObject*: specify another object with annotations to parse. Typically, this is used if a - property references another object, which will then be added to your form as an additional fieldset. - Expects a string value indicating the class for the object being composed - `@ComposedObject("Namespace\Model\ComposedObject")` or an array to compose a collection: - `@ComposedObject({ "target_object":"Namespace\Model\ComposedCollection", "is_collection":"true", - "options":{"count":2}})` `target_object` is the element to compose, `is_collection` flags this as a - collection and `options` can take an array of options to pass into the collection. -- *ErrorMessage*: specify the error message to return for an element in the case of a failed - validation. Expects a string value. -- *Exclude*: mark a property to exclude from the form or fieldset. This annotation does not require - a value. -- *Filter*: provide a specification for a filter to use on a given element. Expects an associative - array of values, with a "name" key pointing to a string filter name, and an "options" key pointing - to an associative array of filter options for the constructor: `@Filter({"name": "Boolean", - "options": {"casting":true}})`. This annotation may be specified multiple times. -- *Flags*: flags to pass to the fieldset or form composing an element or fieldset; these are usually - used to specify the name or priority. The annotation expects an associative array: - `@Flags({"priority": 100})`. -- *Hydrator*: specify the hydrator class to use for this given form or fieldset. A string value is - expected. -- *InputFilter*: specify the input filter class to use for this given form or fieldset. A string - value is expected. -- *Input*: specify the input class to use for this given element. A string value is expected. -- *Instance*: specify an object class instance to bind to the form or fieldset. -- *Name*: specify the name of the current element, fieldset, or form. A string value is expected. -- *Object*: specify an object class instance to bind to the form or fieldset. (Note: this is - deprecated in 2.4.0; use *Instance* instead.) -- *Options*: options to pass to the fieldset or form that are used to inform behavior -- things that - are not attributes; e.g. labels, CAPTCHA adapters, etc. The annotation expects an associative array: - `@Options({"label": "Username:"})`. -- *Required*: indicate whether an element is required. A boolean value is expected. By default, all - elements are required, so this annotation is mainly present to allow disabling a requirement. -- *Type*: indicate the class to use for the current element, fieldset, or form. A string value is - expected. -- *Validator*: provide a specification for a validator to use on a given element. Expects an - associative array of values, with a "name" key pointing to a string validator name, and an "options" - key pointing to an associative array of validator options for the constructor: `@Validator({"name": - "StringLength", "options": {"min":3, "max": 25}})`. This annotation may be specified multiple times. - -To use annotations, you simply include them in your class and/or property docblocks. Annotation -names will be resolved according to the import statements in your class; as such, you can make them -as long or as short as you want depending on what you import. - -> ## Note -Form annotations require `Doctrine\Common`, which contains an annotation parsering engine. The -simplest way to install `Doctrine\Common` is if you are using `Composer`; simply update your -`composer.json` and add the following line to the `require` section: -```php -"doctrine/common": "=2.1", -``` -Then run `php composer.phar update` to install the dependency. -If you're not using `Composer`, visit [the Doctrine project -website](http://www.doctrine-project.org/projects/common.html) for more details on installation. - -Here's a simple example. - -```php -use Zend\Form\Annotation; - -/** - * @Annotation\Name("user") - * @Annotation\Hydrator("Zend\Stdlib\Hydrator\ObjectProperty") - */ -class User -{ - /** - * @Annotation\Exclude() - */ - public $id; - - /** - * @Annotation\Filter({"name":"StringTrim"}) - * @Annotation\Validator({"name":"StringLength", "options":{"min":1, "max":25}}) - * @Annotation\Validator({"name":"Regex", -"options":{"pattern":"/^[a-zA-Z][a-zA-Z0-9_-]{0,24}$/"}}) - * @Annotation\Attributes({"type":"text"}) - * @Annotation\Options({"label":"Username:"}) - */ - public $username; - - /** - * @Annotation\Type("Zend\Form\Element\Email") - * @Annotation\Options({"label":"Your email address:"}) - */ - public $email; -} -``` - -The above will hint to the annotation build to create a form with name "user", which uses the -hydrator `Zend\Stdlib\Hydrator\ObjectProperty`. That form will have two elements, "username" and -"email". The "username" element will have an associated input that has a `StringTrim` filter, and -two validators: a `StringLength` validator indicating the username is between 1 and 25 characters, -and a `Regex` validator asserting it follows a specific accepted pattern. The form element itself -will have an attribute "type" with value "text" (a text element), and a label "Username:". The -"email" element will be of type `Zend\Form\Element\Email`, and have the label "Your email address:". - -To use the above, we need `Zend\Form\Annotation\AnnotationBuilder`: - -```php -use Zend\Form\Annotation\AnnotationBuilder; - -$builder = new AnnotationBuilder(); -$form = $builder->createForm('User'); -``` - -At this point, you have a form with the appropriate hydrator attached, an input filter with the -appropriate inputs, and all elements. - -> ## Note -#### You're not done -In all likelihood, you'll need to add some more elements to the form you construct. For example, -you'll want a submit button, and likely a CSRF-protection element. We recommend creating a fieldset -with common elements such as these that you can then attach to the form you build via annotations. diff --git a/book/zend.form.view.helpers.md b/book/zend.form.view.helpers.md deleted file mode 100644 index 8dab4ecd..00000000 --- a/book/zend.form.view.helpers.md +++ /dev/null @@ -1,1235 +0,0 @@ -# Form View Helpers - -## Introduction - -Zend Framework comes with an initial set of helper classes related to Forms: e.g., rendering a text -input, selection box, or form labels. You can use helper, or plugin, classes to perform these -behaviors for you. - -See the section on \[view helpers\](zend.view.helpers) for more information. - -## Standard Helpers - -### Form - -The `Form` view helper is used to render a `
` HTML element and its attributes. - -It iterates through all its elements and relies on the `FormCollection` and `FormRow` view helpers -to render them appropriately. - -You can also use \[Zend\\Form\\View\\Helper\\FormRow\](zend.form.view.helper.form-row) in -conjunction with `Form::openTag()` and `Form::closeTag()` to have a more fine grained control over -the output. - -Basic usage: - -```php -/** - * inside view template - * - * @var \Zend\View\Renderer\PhpRenderer $this - * @var \Zend\Form\Form $form - */ - -echo $this->form($form); -// i.e. -// -// -//
-``` - -The following public methods are in addition to those inherited from -\[Zend\\Form\\View\\Helper\\AbstractHelper\](zend.form.view.helper.abstract-helper.methods). - -### FormButton - -The `FormButton` view helper is used to render a ` - -/** - * Example #2: Render button in 3 steps - */ -// Render the opening tag -echo $this->formButton()->openTag($element); -// - -/** - * Example #3: Override the element label - */ -echo $this->formButton()->render($element, 'My Content'); -// -``` - -The following public methods are in addition to those inherited from -\[Zend\\Form\\View\\Helper\\FormInput\](zend.form.view.helper.form-input.methods). - -### FormCaptcha - -TODO - -Basic usage: - -```php -use Zend\Captcha; -use Zend\Form\Element; - -$captcha = new Element\Captcha('captcha'); -$captcha - ->setCaptcha(new Captcha\Dumb()) - ->setLabel('Please verify you are human'); - -// Within your view... - -echo $this->formCaptcha($captcha); - -// TODO -``` - -### FormCheckbox - -The `FormCheckbox` view helper can be used to render a `` HTML form input. It -is meant to work with the \[Zend\\Form\\Element\\Checkbox\](zend.form.element.checkbox) element, -which provides a default input specification for validating the checkbox values. - -`FormCheckbox` extends from -\[Zend\\Form\\View\\Helper\\FormInput\](zend.form.view.helper.form-input.methods). - -Basic usage: - -```php -use Zend\Form\Element; - -$element = new Element\Checkbox('my-checkbox'); - -// Within your view... - -/** - * Example #1: Default options - */ -echo $this->formCheckbox($element); -// -// - -/** - * Example #2: Disable hidden element - */ -$element->setUseHiddenElement(false); -echo $this->formCheckbox($element); -// - -/** - * Example #3: Change checked/unchecked values - */ -$element->setUseHiddenElement(true) - ->setUncheckedValue('no') - ->setCheckedValue('yes'); -echo $this->formCheckbox($element); -// -// -``` - -### FormCollection - -TODO - -Basic usage: - -TODO - -### FormElement - -The `FormElement` view helper proxies the rendering to specific form view helpers depending on the -type of the `Zend\Form\Element` that is passed in. For instance, if the passed in element had a type -of "text", the `FormElement` helper will retrieve and use the `FormText` helper to render the -element. - -Basic usage: - -```php -use Zend\Form\Form; -use Zend\Form\Element; - -// Within your view... - -/** - * Example #1: Render different types of form elements - */ -$textElement = new Element\Text('my-text'); -$checkboxElement = new Element\Checkbox('my-checkbox'); - -echo $this->formElement($textElement); -// - -echo $this->formElement($checkboxElement); -// -// - -/** - * Example #2: Loop through form elements and render them - */ -$form = new Form(); -// ...add elements and input filter to form... -$form->prepare(); - -// Render the opening tag -echo $this->form()->openTag($form); - -// ...loop through and render the form elements... -foreach ($form as $element) { - echo $this->formElement($element); // <-- Magic! - echo $this->formElementErrors($element); -} - -// Render the closing tag -echo $this->form()->closeTag(); -``` - -### FormElementErrors - -The `FormElementErrors` view helper is used to render the validation error messages of an element. - -Basic usage: - -```php -use Zend\Form\Form; -use Zend\Form\Element; -use Zend\InputFilter\InputFilter; -use Zend\InputFilter\Input; - -// Create a form -$form = new Form(); -$element = new Element\Text('my-text'); -$form->add($element); - -// Create a input -$input = new Input('my-text'); -$input->setRequired(true); - -$inputFilter = new InputFilter(); -$inputFilter->add($input); -$form->setInputFilter($inputFilter); - -// Force a failure -$form->setData(array()); // Empty data -$form->isValid(); // Not valid - -// Within your view... - -/** - * Example #1: Default options - */ -echo $this->formElementErrors($element); -// - -/** - * Example #2: Add attributes to open format - */ -echo $this->formElementErrors($element, array('class' => 'help-inline')); -// - -/** - * Example #3: Custom format - */ -echo $this->formElementErrors() - ->setMessageOpenFormat('
') - ->setMessageSeparatorString('
') - ->setMessageCloseString('
') - ->render($element); -//
Value is required and can't be empty
-``` - -The following public methods are in addition to those inherited from -\[Zend\\Form\\View\\Helper\\AbstractHelper\](zend.form.view.helper.abstract-helper.methods). - -### FormFile - -The `FormFile` view helper can be used to render a `` form input. It is meant to -work with the \[Zend\\Form\\Element\\File\](zend.form.element.file) element. - -`FormFile` extends from \[Zend\\Form\\View\\Helper\\FormInput\](zend.form.view.helper.form-input). - -Basic usage: - -```php -use Zend\Form\Element; - -$element = new Element\File('my-file'); - -// Within your view... - -echo $this->formFile($element); -// -``` - -For HTML5 multiple file uploads, the `multiple` attribute can be used. Browsers that do not support -HTML5 will default to a single upload input. - -```php -use Zend\Form\Element; - -$element = new Element\File('my-file'); -$element->setAttribute('multiple', true); - -// Within your view... - -echo $this->formFile($element); -// -``` - -### FormHidden - -The `FormHidden` view helper can be used to render a `` HTML form input. It is -meant to work with the \[Zend\\Form\\Element\\Hidden\](zend.form.element.hidden) element. - -`FormHidden` extends from \[Zend\\Form\\View\\Helper\\FormInput\](zend.form.view.helper.form-input). - -Basic usage: - -```php -use Zend\Form\Element; - -$element = new Element\Hidden('my-hidden'); -$element->setValue('foo'); - -// Within your view... - -echo $this->formHidden($element); -// -``` - -### FormImage - -The `FormImage` view helper can be used to render a `` HTML form input. It is -meant to work with the \[Zend\\Form\\Element\\Image\](zend.form.element.image) element. - -`FormImage` extends from \[Zend\\Form\\View\\Helper\\FormInput\](zend.form.view.helper.form-input). - -Basic usage: - -```php -use Zend\Form\Element; - -$element = new Element\Image('my-image'); -$element->setAttribute('src', '/img/my-pic.png'); - -// Within your view... - -echo $this->formImage($element); -// -``` - -### FormInput - -The `FormInput` view helper is used to render a `` HTML form input tag. It acts as a base -class for all of the specifically typed form input helpers (FormText, FormCheckbox, FormSubmit, -etc.), and is not suggested for direct use. - -It contains a general map of valid tag attributes and types for attribute filtering. Each subclass -of `FormInput` implements it's own specific map of valid tag attributes. - -The following public methods are in addition to those inherited from -\[Zend\\Form\\View\\Helper\\AbstractHelper\](zend.form.view.helper.abstract-helper.methods). - -### FormLabel - -The `FormLabel` view helper is used to render a `