Welcome to Abdul Malik Ikhsan's Blog

Zend Framework 2 : Step by Step build Form using Annotation Builder

Posted in Tutorial PHP, Zend Framework 2 by samsonasik on October 4, 2012

Zend Framework provide AnnotationBuilder that can createForm by entity which we defined. An entity can be one class that consists of Annotation Type, Filter, Validator, etc in each of the properties. This feature need doctrine Annotation. In this post, i will give you step by step how to use this annotation .


1. First, grab skeleton application from github.

git clone git://github.com/zendframework/ZendSkeletonApplication.git
cd ZendSkeletonApplication

2. Add doctrine/common to composer.json

{
    "repositories": [
        {
            "type": "composer",
            "url": "http://packages.zendframework.com/"
        }
    ],
    
    "name": "zendframework/skeleton-application",
    "description": "Skeleton Application for ZF2",
    "license": "BSD-3-Clause",
    "keywords": [
        "framework",
        "zf2"
    ],
    "homepage": "http://framework.zend.com/",
    "require": {
        "php": ">=5.3.3",
        "zendframework/zendframework": "2.*",
        "doctrine/common" : ">=2.1"
    }
}

3. run install by :

COMPOSER_PROCESS_TIMEOUT=5000 php composer.phar install

The process will be like the following :

4. Let’s code :
a. create an entity

namespace SampleModule\Model;

use Zend\Form\Annotation;

/**
 * @Annotation\Hydrator("Zend\Stdlib\Hydrator\ObjectProperty")
 * @Annotation\Name("Student")
 */
class Student
{
    /**
     * @Annotation\Type("Zend\Form\Element\Text")
     * @Annotation\Required({"required":"true"})
     * @Annotation\Filter({"name":"StripTags"})
     * @Annotation\Filter({"name":"StringToUpper"})
     * @Annotation\Validator({"name":"StringLength", "options":{"min":"5"}})
     * @Annotation\Options({"label":"Absent Id:"})
     */
    public $absentid;
    
    /**
     * @Annotation\Type("Zend\Form\Element\Text")
     * @Annotation\Required({"required":"true" })
     * @Annotation\Filter({"name":"StripTags"})
     * @Annotation\Validator({"name":"StringLength", "options":{"min":"1"}})
     * @Annotation\Options({"label":"Name:"})
     */
    public $name;
    
    /**
     * @Annotation\Type("Zend\Form\Element\Radio")
     * @Annotation\Required({"required":"true" })
     * @Annotation\Filter({"name":"StripTags"})
     * @Annotation\Options({"label":"Gender:",
     *                      "value_options" : {"1":"Male","2":"Female"}})
     * @Annotation\Validator({"name":"InArray",
     *                        "options":{"haystack":{"1","2"},
     *                              "messages":{"notInArray":"Gender is not valid"}}})
     * @Annotation\Attributes({"value":"1"})
     */
    public $gender;
    
    /**
     * @Annotation\Type("Zend\Form\Element\Select")
     * @Annotation\Required({"required":"true" })
     * @Annotation\Filter({"name":"StripTags"})
     * @Annotation\Options({"label":"Class:",
     *                      "value_options" : {"0":"Select a Class","1":"A","2":"B","3":"C"}})
     * @Annotation\Validator({"name":"InArray",
     *                        "options":{"haystack":{"1","2","3"},
     *                              "messages":{"notInArray":"Please Select a Class"}}})
     * @Annotation\Attributes({"value":"0"})
     */
    public $class;
    
    
    /**
     * @Annotation\Type("Zend\Form\Element\Submit")
     * @Annotation\Attributes({"value":"Submit"})
     */
    public $submit;
}

b. Call it in controller

namespace SampleModule\Controller;

use Zend\Mvc\Controller\AbstractActionController;
use Zend\Form\Annotation\AnnotationBuilder;
use SampleModule\Model\Student;

class StudentController extends AbstractActionController
{
    public function addAction()
    {
        $student    = new Student();
        $builder    = new AnnotationBuilder();
        $form       = $builder->createForm($student);
        
        $request = $this->getRequest();
        if ($request->isPost()){
            $form->bind($student);
            $form->setData($request->getPost());
            if ($form->isValid()){
                print_r($form->getData());
            }
        }
        
        return array('form'=>$form);
    }
}

c. show it in the view :

$form = $this->form;
$form->setAttribute('action', $this->url(
    'SampleModule/default',
    array(
        'action'     => 'add',
        'controller' => 'student'
    )
));
$form->prepare();

echo $this->form()->openTag($form);
echo $this->formCollection($form);
echo $this->form()->closeTag();

Done !

References :
1. http://mwop.net/blog/2012-07-02-zf2-beta5-forms.html

77 Responses

Subscribe to comments with RSS.

  1. […] For example, i have the following form like this to utilize rememberMe() function for authentication with DbTable adapter : 1. Prepare a Login Form with this entity. […]

  2. houssemzaier said, on October 25, 2012 at 8:30 pm

    SALAM ALAYKOM ABUL MALEK happy EID ADHA MUBARAK ! thanks a lot for this great blog !

  3. samsonasik said, on October 25, 2012 at 11:01 pm

    Wa’alaikumsalam, happy ied adha mubarak. Allohu Akbar Allohu Akbar Allohu Akbar, Laa ilaa haillallohu wallohuakbar Allohuakbar walillahilhamd. You’re welcome.

  4. Pierre said, on December 13, 2012 at 8:46 pm

    Sorry delete the previous post I was on the wrong tutorial. I posted it on the Zend Framework 2 : Using Zend\Form and Ajax.

    • samsonasik said, on December 14, 2012 at 11:22 am

      ok, deleted 🙂

    • prashant gautam said, on June 13, 2014 at 8:09 pm

      Hey
      kindly give me the steps to develop a application in zf2 tutorial…..
      Thanks in advance..

  5. Create Simple Login With Zend said, on December 19, 2012 at 2:43 pm

    […] 1. Prepare a Login Form with this entity. […]

  6. IngeniousKid said, on February 20, 2013 at 10:15 pm

    Thank’s for your tutorials, dude! But i have 1 question – where i can find list of all options for annotations? I need more control to create elements (wrappers, classes, etc). Thank you!

  7. zirtrex said, on March 12, 2013 at 10:12 pm

    Hi! how do yo for validate a email

  8. Mohammad Nomaan Patel said, on March 20, 2013 at 7:26 pm

    Hi,
    Can u provide a post about generating an entities from existing database using a command line tool…
    Thanks in advance

  9. michaelrichter107639320Michael said, on March 25, 2013 at 12:07 am

    Wow, great tutorial. Works fine… i tried to use annotation with a translator… first solution, dropping labels and setting them in the view, which works but… do you know a better way, especially when thinking about value_options in radio or select-elements!?

    Kind regards from snowy Hanover, Germany

    • samsonasik said, on March 25, 2013 at 2:34 pm

      I’m not fan with AnnotationBuilder, just want to share the other options instead of extends Zend\Form\Form. for value_options, if values are come from db, i think you should extends Zend\Form\Form, and pass a db to the form.

      Thanks for the comment 😉

      • yves said, on January 23, 2017 at 4:39 pm

        What is your favorite method to create a form quickly ?

      • samsonasik said, on January 25, 2017 at 2:32 pm

        quicker is using config file via “form_elements” config, but will be more programmable with extends \Zend\Form\Form.

      • yves said, on January 25, 2017 at 4:18 pm

        ok, i’m beginner in zf, but with annotation builder and doctrine it seems like a easy way to create a form, and i try to understand why you’re not fan.
        in my case a want to create a back office, and a form based on entity doctrine make me automatique form with association mapping

      • David Mintz said, on May 30, 2017 at 8:38 pm

        @yves the question wasn’t addressed to me, but I think the answer for at least some people is that with annotations it’s harder to cache and (arguably) it blends different areas of responsibility into one place. For me, the attraction is greatest where the validation rules are intimately related to the database column definitions. Enforcing a maximum string length is a good example. When you’re using Doctrine, you likely have Doctrine annotations specifying the column width, and logical place for a string-length validator would be located right there in the same file — or so some people think. Makes it convenient in case you have to make a change to your schema.

  10. Edgar said, on March 25, 2013 at 1:35 pm

    gracias ¡¡¡

  11. nosdor said, on April 7, 2013 at 9:12 am

    How to fill options from database?

  12. Thomas Szteliga said, on April 12, 2013 at 3:52 am

    @samsonasik Thank You! This is a great article, everything nicely explained, found few good hints here. But I have a question. I have two entities VpnServer and VpnClient, each VpnClient belongs to one VpnServer. The most important part is the client:

    class VpnClient
    {

    /**
    * @ORM\OneToOne(targetEntity="VpnServer")
    * @ORM\JoinColumn(name="vpn_server_id", referencedColumnName="id")
    * @Annotation\Type("Zend\Form\Element\Select")
    * @Annotation\Options({"label":"VpnServer:"})
    * @Annotation\Required({"required": true})
    */
    private $vpnServer;

    Of course I’m building the form with AnnotationBuilder from the entity. An my question: is it possible with ZF + Doctrine + Annotations to fill the shown above Zend\Form\Element\Select with values from the VpnServer table? Or do I have to do this by my own (I mean in the controller, before passing the form to the ViewModel)?

  13. Musafar said, on April 16, 2013 at 11:58 am

    COMPOSER_PROCESS_TIMEOUT=5000 php composer.phar install

    ‘COMPOSER_PROCESS_TIMEOUT’ is not recognized as an internal or external command,
    operable program or batch file.

  14. Phuc said, on April 17, 2013 at 8:04 pm

    Error: Add doctrine/common to composer.json
    I don’t know add
    or
    add error:

    D:\wamp\www\LVTN\TK\Zf2Demo>php composer.phar install
    Loading composer repositories with package information
    Installing dependencies from lock file
    Warning: The lock file is not up to date with the latest changes in composer.jso
    n. You may be getting outdated dependencies. Run update to update them.
    Nothing to install or update
    Generating autoload files

    Please help ! (I am from VietNam) Thank you !
    mail: daonhamphucbdvn@gmail.com
    yahoo: goro_kolo@yahoo.com.vn

    • samsonasik said, on April 18, 2013 at 12:51 am

      try php composer.phar update

      • Phuc said, on April 18, 2013 at 7:00 pm

        but error

      • samsonasik said, on April 19, 2013 at 5:38 am

        try remove your vendor folder, clear composer cache, and try again.

      • Phuc said, on April 23, 2013 at 10:11 am

        I try: php composer.phar update
        but when I try: http://localhost/LVTN/TK/Zf2Demo/public/home/auth/login
        then error:

        Warning: require(D:\wamp\www\LVTN\TK\Zf2Demo\vendor/zendframework/zendframework/library/Zend/Stdlib/compatibility/autoload.php) [function.require]: failed to open stream: No such file or directory in D:\wamp\www\LVTN\TK\Zf2Demo\vendor\composer\autoload_real.php on line 41

        Call Stack
        # Time Memory Function Location
        1 0.0017 672192 {main}( ) ..\index.php:0
        2 0.0023 682648 require( ‘D:\wamp\www\LVTN\TK\Zf2Demo\init_autoloader.php’ ) ..\index.php:9
        3 0.0030 685096 include( ‘D:\wamp\www\LVTN\TK\Zf2Demo\vendor\autoload.php’ ) ..\init_autoloader.php:14
        4 0.0042 704232 ComposerAutoloaderInitfc7b3736a88486e977161f8d40605ff4::getLoader( ) ..\autoload.php:7

        Fatal error: require() [function.require]: Failed opening required ‘D:\wamp\www\LVTN\TK\Zf2Demo\vendor/zendframework/zendframework/library/Zend/Stdlib/compatibility/autoload.php’ (include_path=’.;C:\php\pear’) in D:\wamp\www\LVTN\TK\Zf2Demo\vendor\composer\autoload_real.php on line 41
        Call Stack
        # Time Memory Function Location
        1 0.0017 672192 {main}( ) ..\index.php:0
        2 0.0023 682648 require( ‘D:\wamp\www\LVTN\TK\Zf2Demo\init_autoloader.php’ ) ..\index.php:9
        3 0.0030 685096 include( ‘D:\wamp\www\LVTN\TK\Zf2Demo\vendor\autoload.php’ ) ..\init_autoloader.php:14
        4 0.0042 704232 ComposerAutoloaderInitfc7b3736a88486e977161f8d40605ff4::getLoader( ) ..\autoload.php:7

        Help

      • Phuc said, on April 23, 2013 at 10:14 am

        Can you add facebook of me : http://www.facebook.com/oppa.boo.1368
        Thank’s you !

      • samsonasik said, on April 23, 2013 at 3:52 pm

        if you’re failed with composer, try another way, follow readme in this repo : https://github.com/zendframework/ZendSkeletonApplication#using-git-submodules

  15. Mayckon said, on July 19, 2013 at 9:10 pm

    Why do you install doctrine? Can I use annotation builder without install doctrine?

    • samsonasik said, on July 20, 2013 at 12:34 am

      because, in this case, I use annotation builder. no, we can not build annotation without doctrine at this case.

  16. ram said, on August 18, 2013 at 6:58 pm

    hi
    iam very happy on seeing this most of my problems are solved

    please provide me validation code for registration form links…..

  17. Paul said, on August 23, 2013 at 5:13 am

    Hi, I try to reproduce it, but I get a checkbox instead of Zend\Form\Element\Radio. Thx.

    • samsonasik said, on August 26, 2013 at 3:54 pm

      checkbox must be named independently, should be set value, not value_options.

  18. Larry Simon said, on August 27, 2013 at 10:02 pm

    @ComposedObject adds another annotated class as a FieldSet. Is there an annotation to direct the AnnotationBuilder to add the other annotated class added as a FormCollection instead?

    • Larry Simon said, on August 27, 2013 at 10:04 pm

      Edit: @ComposedObject adds another annotated class as a FieldSet. Is there an annotation to direct the AnnotationBuilder to add the other annotated class as a FormCollection instead?

  19. Hanita said, on August 29, 2013 at 4:02 am

    thank you very much for all your perfect tutorials , plz i need to know the difference between required and allowEmpty Annotations . when i set required annotation to false i still have an error msg indicating that i should fill the input .

    • samsonasik said, on August 29, 2013 at 3:27 pm

      you need to set allowempty = true

    • Chirag said, on December 12, 2013 at 4:16 pm

      You should use * @Annotation\AllowEmpty({“allowempty”:”true”}) instead of * @Annotation\Required({“required”:”true” })

      • jjordaa said, on August 20, 2014 at 8:37 pm

        Thanks! Life saver! I had been struggling with this for ages!

  20. wisniaa said, on November 27, 2013 at 12:02 am

    Hi,
    i can’t get annotations to work, when generating form from annotations only empty fields are in form spec, I’ve copied the code from here.
    I am using ZF 2.2.5, has something changed recently?

    Any troubleshooting tips appreciated

    • samsonasik said, on November 27, 2013 at 12:03 am

      do you use windows ? I’m not sure enough about windows ^^

      • wisniaa said, on November 27, 2013 at 12:31 am

        yes, i’m on windows, does it matter? I’ve installed everything fine.

        I’m trying to manually read annotations for Album class, using ClassReflection, and for a single property I’m having

        object(Zend\Code\Scanner\AnnotationScanner)#255 (6) {
        [“isScanned”:protected]=>
        bool(false)
        [“docComment”:protected]=>
        string(95) “/**
        *
        * @Annotation\Required(false)
        * @Annotation\Attributes({“type”:”hidden”})
        */”
        [“nameInformation”:protected]=>
        object(Zend\Code\NameInformation)#256 (2) {
        [“namespace”:protected]=>
        string(11) “Album\Model”
        [“uses”:protected]=>
        array(3) {
        [“CherryTools\Model\AnnotatedModelFactory”]=>
        string(21) “AnnotatedModelFactory”
        [“Zend\InputFilter\InputFilterInterface”]=>
        string(20) “InputFilterInterface”
        [“Zend\Form\Annotation”]=>
        string(10) “Annotation”
        }
        }
        [“annotationManager”:protected]=>
        object(Zend\Code\Annotation\AnnotationManager)#247 (1) {
        [“events”:protected]=>
        NULL
        }

        —– FU*K ———–
        [“annotations”:protected]=>
        array(0) {
        }
        —– FU*K ———–

        [“storage”:”ArrayObject”:private]=>
        array(0) {
        }
        }

    • wisniaa said, on November 27, 2013 at 12:39 am

      okay, got it.

      tip: use spaces, not tabs, as annotations parser won’t parse spaces 😛

  21. wisniaa said, on November 27, 2013 at 12:33 am

    Going further, when tokenizing in parser I’m having

    array(2) {
    [0]=>
    string(17) “ANNOTATION_IGNORE”
    [1]=>
    string(46) ” * @Annotation\Attributes({“type”:”hidden”})

    WTF 😛

  22. Ky Hip said, on December 16, 2013 at 10:31 pm

    * @Annotation\Required({“required”:”true” }) not work at submit form?

    Please help me

  23. Bharath said, on February 10, 2014 at 7:05 pm

    how to bind single form with multiple entity using ZF2 with ORM doctrine2 for edit action in controller

  24. dredog1 said, on February 12, 2014 at 12:08 am

    Great tutorial, thank you!!

  25. Marcelo Burkard said, on May 28, 2014 at 10:58 am

    Great Abdul, I’ve copied and pasted your code and it simply doesn’t work, it seems that my annotations had been ignored and at the end I only have an empty fieldset “”. Is there any other dependency or even some sort of PHP extension that could be missing on my computer?

    • Erik said, on July 3, 2014 at 8:12 pm

      Remove zenddevelopertools from module array in application.config.php

      • diemuzi said, on July 15, 2014 at 6:34 am

        Actually all you need to do is sent the “Events” -> “Enabled” option to false in the ZDT autoload configuration file. I’m not sure why this effects the loading of Annotations but at least you can keep ZDT.

      • Marcelo Burkard said, on September 3, 2014 at 4:17 am

        As diemuzi said I just needed to set ‘Events’ => ‘Enabled’ = false, on ApplicationPath/config/autoload/zdt.local.php

        Thanks a lot both of you guys. Now it’s finally working!

  26. Umair Hamid said, on July 22, 2014 at 5:29 pm

    How can I pass id to the form for update the record?

  27. weeam said, on March 26, 2015 at 11:40 pm

    Hi my Friend , Your work is very helpful , But I wonder if i wont the user to be redirect to the Auth Form befor he can access any URL or multiple URLs in the Application , How that can be done in me Zend Application

    • samsonasik said, on March 27, 2015 at 2:18 am

      there are other strategy, you can break it with “non-authorized” page.

  28. Zarif said, on April 22, 2015 at 8:00 pm

    Brother I have followed your steps of installation but not able to install, its giving me the following error
    A 404 error occurred
    Page not found.
    The requested URL could not be matched by routing.

    No Exception available
    Please help me out!!!!

  29. Cerdobot said, on May 14, 2015 at 11:26 am

    Hi…. how can we add class to ours form elements¡? with the AnnotationBuilder
    Thank You in Advance

  30. Lowtower said, on September 19, 2016 at 3:19 pm

    Hi Samsonasik,

    does this also/still work in zend expressive 1.0?

  31. Lowtower said, on September 19, 2016 at 3:48 pm

    Hello Samsonasik,
    found the answer myself:
    PHP7 is the problem: https://github.com/zendframework/zend-form/issues/51

  32. yves said, on January 18, 2017 at 4:50 pm

    Hello
    How can we add validator UniqueObject?

    • samsonasik said, on January 18, 2017 at 5:32 pm

      I never use it, you probably find this: http://www.aronkerr.com/2013/11/zf2-form-collection-validation-unique.html

    • yves said, on January 25, 2017 at 5:40 pm

      I don’t know if it’s a good idea, but i extend AnnotationBuilder, to attach my own ElementAnnotationsListener
      and now it for doctrine validator it will object_repository find in metadata, inject fields find in inputSpec, and inject objectManager, set in constructor, like AnnotationBuilder from doctrine, it’s work now, but what do you think?


Leave a reply to samsonasik Cancel reply