Welcome to Abdul Malik Ikhsan's Blog

Zend Framework 2 : Extending Zend\Form to add Select, Multicheckbox, Email,Date, Textarea, and Radio element

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

By extending Zend\Form, we can add elements into form on the fly instead of manually instantiate the element(s).
For example, we want a form like this :

I will show you the way to do that. In Zend Framework 2, it’s very easy.


Let’s code :

namespace SampleModule\Form;
use Zend\Form\Form;

class SampleForm extends Form
{
    public function __construct($name = null)
    {
        parent::__construct("Sample Form");
        
        $this->setAttribute('method', 'post');
        
        $this->add(array(
            'name' => 'id',
            'attributes' => array(
                'type'  => 'hidden',
            ),
        ));
        
        $this->add(array(
            'name' => 'name',
            'attributes' => array(
                'type'  => 'text',
            ),
            'options' => array(
                'label' => 'Name',
            ),
        ));
        
        $this->add(array(
            'type' => 'Zend\Form\Element\Select',
            'name' => 'gender',
            'options' => array(
                'label' => 'Gender',
                'value_options' => array(
                    '1' => 'Select your gender',
                    '2' => 'Female',
                    '3' => 'Male'
                ),
            ),
            'attributes' => array(
                'value' => '1' //set selected to '1'
            )
        ));
        
        $this->add(array(
            'type' => 'Zend\Form\Element\MultiCheckbox',
            'name' => 'hobby',
            'options' => array(
                'label' => 'Please choose one/more of the hobbies',
                'value_options' => array(
                    '1' =>'Cooking',
                    '2'=>'Writing',
                    '3'=>'Others'
                ),
            ),
            'attributes' => array(
                'value' => '1' //set checked to '1'
            )
        ));
        
        $this->add(array(
            'type' => 'Zend\Form\Element\Email',
            'name' => 'email',
            'options' => array(
                'label' => 'Email'
            ),
            'attributes' => array(
                'placeholder' => 'you@domain.com'
            )
        ));
 
        $this->add(array(
            'type' => 'Zend\Form\Element\Date',
            'name' => 'birth',
            'options' => array(
                'label' => 'Birth'
            )
        ));
        
        $this->add(array(
            'name' => 'address',
            'attributes'=>array(
                'type'=>'textarea'  
            ),
            'options' => array(
                'label' => 'Address',
            ),
        ));
        
        $this->add(array(
            'type' => 'Zend\Form\Element\Radio',
            'name' => 'direction',
            'options' => array(
                'label' => 'Please choose one of the directions',
                'value_options' => array(
                    '1' => 'Programming',
                    '2' => 'Design',
                ),
            ),
            'attributes' => array(
                'value' => '1' //set checked to '1'
            )
        ));
        
        $this->add(array(
            'name' => 'submit',
            'attributes' => array(
                'type'  => 'submit',
                'value' => 'Go',
                'id' => 'submitbutton',
            ),
        ));
    }
    
    //IF YOU WILL WORK WITH DATABASE 
    //AND NEED bind() FORM FOR EDIT DATA, YOU NEED OVERRIDE
    //populateValues() FUNC LIKE THIS
    public function populateValues($data)
    {   
        foreach($data as $key=>$row)
        {
           if (is_array(@json_decode($row))){
                $data[$key] =   new \ArrayObject(\Zend\Json\Json::decode($row), \ArrayObject::ARRAY_AS_PROPS);
           }
        } 
        
        parent::populateValues($data);
    }
}

And remember, if you work with database, beside override populateValues() func in Form Class, don’t forget to encode array of hobby[] in Table Class by :

//common code to describe namespace, use here...

class SampleTable extends AbstractTableGateway
{
    protected $table = 'sampletable';
    public function __construct(Adapter $adapter){ /* common code here */ }
    
    public function saveSample(Sample $sample)
    {
        $data = array(
            'name' => $sample->name,
            'gender' => $sample->gender,
            'hobby' => \Zend\Json\Json::encode($sample->hobby),
            'email'   => $sample->email,
            'birth' => $sample->birth,
            'address' => $sample->address,
            'direction' => $sample->direction
        );
        $id = (int)$sample->id;
        if ($id == 0) {
            $this->insert($data);
        } else {
            if ($this->getSampleById($id)) {
                
                $this->update($data, array('id' => $id));
            
            } else {
                throw new \Exception('Form id does not exist');
            }
        }
    }
}

before save/update-ing the row, and value will be like : [1,2,3] etc.

Next step,add filter and validator. They should be in other class.

namespace SampleModule\Model;

use Zend\InputFilter\Factory as InputFactory;
use Zend\InputFilter\InputFilter;
use Zend\InputFilter\InputFilterAwareInterface;
use Zend\InputFilter\InputFilterInterface;

class Sample implements InputFilterAwareInterface
{
    public $id;
    public $name;
    public $gender;
    public $hobby;
    public $email;
    public $birth;
    public $address;
    public $direction;
    
    protected $inputFilter;

    public function exchangeArray($data)
    {
        $this->id        = (isset($data['id'])) ? $data['id'] : null;
        $this->name      = (isset($data['name'])) ? $data['name'] : null;
        $this->gender    = (isset($data['gender'])) ? $data['gender'] : null;
        $this->hobby     = (isset($data['hobby'])) ? $data['hobby'] : null;
        $this->email     = (isset($data['email'])) ? $data['email'] : null;
        $this->birth     = (isset($data['birth'])) ? $data['birth'] : null;
        $this->address   = (isset($data['address'])) ? $data['address'] : null;
        $this->direction = (isset($data['direction'])) ? $data['direction'] : null;
    }
    
    public function getArrayCopy()
    {
        return get_object_vars($this);
    } 
    
    public function setInputFilter(InputFilterInterface $inputFilter)
    {
        throw new \Exception("Not used");
    }

    public function getInputFilter()
    {
        if (!$this->inputFilter) {
            $inputFilter = new InputFilter();
            $factory     = new InputFactory();

            $inputFilter->add($factory->createInput(array(
                'name'     => 'id',
                'required' => true,
                'filters'  => array(
                    array('name' => 'Int'),
                ),
            )));

            $inputFilter->add($factory->createInput(array(
                'name'     => 'name',
                'required' => true,
                'filters'  => array(
                    array('name' => 'StripTags'),
                    array('name' => 'StringTrim'),
                ),
                'validators' => array(
                    array(
                        'name'    => 'StringLength',
                        'options' => array(
                            'encoding' => 'UTF-8',
                            'min'      => 5,
                            'max'      => 255,
                        ),
                    ),
                ),
            )));
            
            $inputFilter->add($factory->createInput(array(
                'name'     => 'gender',
                'validators' => array(
                    array(
                        'name'    => 'InArray',
                        'options' => array(
                            'haystack' => array(2,3),
                            'messages' => array(
                                'notInArray' => 'Please select your gender !'  
                            ),
                        ),
                    ),
                ),
            )));
            
            $inputFilter->add($factory->createInput(array(
                'name'     => 'hobby',
                'required' => true 
            )));
            
            
            $inputFilter->add($factory->createInput(array(
                'name'     => 'email',
                'validators' => array(
                    array(
                        'name'    => 'EmailAddress'
                    ),
                ),
            )));
            
            $inputFilter->add($factory->createInput(array(
                'name'     => 'birth',
                'validators' => array(
                    array(
                        'name'    => 'Between',
                        'options' => array(
                            'min' => '1970-01-01',
                            'max' => date('Y-m-d')
                        ),
                    ),
                ),
            ))); 
            
            $inputFilter->add($factory->createInput(array(
                'name'     => 'address',
                'required' => true,
                'filters'  => array(
                    array('name' => 'StripTags'),
                    array('name' => 'StringTrim'),
                ),
                'validators' => array(
                    array(
                        'name'    => 'StringLength',
                        'options' => array(
                            'encoding' => 'UTF-8',
                            'min'      => 5,
                            'max'      => 255,
                        ),
                    ),
                ),
            )));
            
            $inputFilter->add($factory->createInput(array(
                'name'     => 'direction',
                'required' => true  
            )));
             

            $this->inputFilter = $inputFilter;
        }

        return $this->inputFilter;
    }
}

Now, we can call it from controller :

namespace SampleModule\Controller;

use Zend\Mvc\Controller\AbstractActionController;
use SampleModule\Form\SampleForm;
use SampleModule\Model\Sample;
 
class TablesampleController extends AbstractActionController
{
    public function addAction()
    {
        $form  = new SampleForm();

        $request = $this->getRequest();
        if ($request->isPost()) {
            
            $sample = new Sample();
            $form->setInputFilter($sample->getInputFilter());
            $form->setData($request->getPost());

            if ($form->isValid()) {
                //SAVE TO DATABASE...
            }
        }
        
        return array(
            'form' => $form
        );
    }
}

In the view, we can call :

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

echo $this->form()->openTag($form);
echo $this->formRow($form->get('name'));
echo $this->formRow($form->get('gender'));
echo $this->formRow($form->get('hobby'));
echo $this->formRow($form->get('email'));
echo $this->formRow($form->get('birth'));
echo $this->formRow($form->get('address'));
echo $this->formRow($form->get('direction'));
echo $this->form()->closeTag();

OR, if we’re a lazy programmer, we can use like this :

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

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

Done !.

[UPDATE]
As Zend Framework version 2.0.2, for multicheckbox and radio, we must to call formElementErrors() in the view to show error if data form posted is not valid like this :

echo $this->formElementErrors($form->get('hobby')); //multicheckbox
echo $this->formElementErrors($form->get('direction')); //radio

[UPDATE] ( Zend Framework 2.0.3 )
The above code ( formElementErrors ) in multicheckbox and radio is unnecessary.

References :
1. http://stackoverflow.com/questions/12563181/zend-framework-2-standalone-forms
2. http://framework.zend.com/apidoc/2.0/classes/Zend.Form.Element.Select.html

136 Responses

Subscribe to comments with RSS.

  1. okeowoaderemi said, on October 1, 2012 at 11:58 pm

    How About using Ajax with Zend Forms,nice article by the way and also is this the end of Decorators

  2. samsonasik said, on October 2, 2012 at 6:15 am

    I hope i can blog about using zend\form with ajax soon, thanks for the comment 😉

  3. John said, on October 5, 2012 at 8:22 pm

    Very nice example. But what if I wanted to background-color the form and display the labels in white, assuming background-color was dark. What would be the best way to do this?

  4. samsonasik said, on October 5, 2012 at 11:52 pm

    First, prepare your css id/class, for example :

    .withcolor{
    color:red;
    }
    #sampleform{
    background-color:blue;
    }

    Then, You can create CUSTOM form view helper, for ex :

    namespace SampleModule\View\Helper;
    
    use Zend\Form\ElementInterface;
    use Zend\Form\View\Helper\FormLabel as ParentLabel;
    
    class FormLabel extends ParentLabel
    {
        public function __invoke(ElementInterface $element, $labelContent = null, $position = null)
        {
            if (!$element) {
                return $this;
            }
    
            $openTag = '<label class="withcolor">';
            $label   = '';
            if ($labelContent === null || $position !== null) {
                $label = $element->getLabel();
                if (empty($label)) {
                    throw new Exception\DomainException(sprintf(
                        '%s expects either label content as the second argument, ' .
                        'or that the element provided has a label attribute; neither found',
                        __METHOD__
                    ));
                }
    
                if (null !== ($translator = $this->getTranslator())) {
                    $label = $translator->translate(
                        $label, $this->getTranslatorTextDomain()
                    );
                }
            }
    
            if ($label && $labelContent) {
                switch ($position) {
                    case self::APPEND:
                        $labelContent .= $label;
                        break;
                    case self::PREPEND:
                    default:
                        $labelContent = $label . $labelContent;
                        break;
                }
            }
    
            if ($label && null === $labelContent) {
                $labelContent = $label;
            }
    
            return $openTag . $labelContent . $this->closeTag();
        }
    }
    

    And…, register in module.config.php

        'view_helpers' => array(
            'invokables' => array(
                  'formlabel' => 'SampleModule\View\Helper\FormLabel',
            ),
        ),
    

    Last but not least, for Form background, you can add id or class into form by :

            $this->setAttribute('id', 'sampleform');
    

    In the view :

    echo $this->formLabel($form->get('name')); 
    echo $this->formElement($form->get('name'));
    

    for echo-ing label and element manually
    instead of

     echo $this->formRow($form->get('name'); 
    

    for automatically 😉

    • abc said, on August 28, 2014 at 8:17 am

      Thanks for tutorial.

  5. Cường said, on October 9, 2012 at 6:21 am

    thanks for tutorial.
    Can you blog other tutorial about select element which load from database.
    Thank you ^^

  6. samsonasik said, on October 9, 2012 at 12:51 pm

    You’re welcome. It’s easy, just populate array of rows into array, and add to the value_options of the select element. I hope i can blog soon.

  7. sds said, on October 22, 2012 at 11:06 pm

    Thank you very much for all your tutorials. It’s really very useful for me.
    As per your advice in last comment i succeeded to load select elements from DATABASE.

    // this is in Model
    public function fetchLookup($table,$name)
    {
    $sql = new Sql($this->adapter);
    $select = $sql->select($table);
    $statement = $sql->prepareStatementForSqlObject($select);
    $rowset = $statement->execute();
    $myArray = array();
    $myArray[”] = ”;
    foreach($rowset as $key => $value)
    {
    $myArray[$value[‘id’]] = $value[$name];
    }
    // \Zend\Debug\Debug::dump($myArray);
    return $myArray;
    }

    // I am calling this model from controller like the below code
    $form = new ProformaForm();
    $form->get(‘Customers’)
    ->setOptions(
    array(
    ‘value_options’ => $this->getLookupTable()->fetchLookup(‘Lkp.Customers’,’CustomerName’)
    )
    );

    I don’t know is this professional way to achieve this!?

    But by using this option, i can able to call only from controller. I have to call the function during ADD and EDIT Actions(so there is a code redundancy). Is there any way to /* load select elements from DATABASE*/ during form creation. Please advise me.

    • samsonasik said, on October 23, 2012 at 12:57 am

      You can pass a ServiceManager into form that registered by factories, that can call dbadapter and do Sql operation(s). Call form in controller by serviceLocator.

      • sds said, on October 23, 2012 at 3:17 am

        Thanks for your prompt response. Let me try.

      • Musafar said, on January 10, 2013 at 1:31 pm

        newbie here…. Can you blog it please??? 😀

  8. samsonasik said, on October 23, 2012 at 10:55 am

    You’re welcome 😉

  9. Macks said, on October 25, 2012 at 11:15 pm

    Hi, Great tutorial, but I have a question:
    Can be separated into another file, “filter Class” of the “model class”.
    For example:
    # SampleModule \ Model \ Sample
    SampleModule namespace \ Model;
    Class Sample {
    public $ id;
    public $ name;

    }

    # SampleModule \ Form \ SampleFilterForm
    Class Sample implements Sample {class InputFilterAwareInterface
    ….

    getInputFilter public function () {
    if ($ this-> inputFilter) {
    $ inputFilter InputFilter = new ();
    InputFactory $ factory = new ();

    $ inputFilter-> add ($ factory-> createInput (array (
    ‘name’ => ‘id’,
    ‘required’ => true,
    ‘filters’ => array (
    array (‘name’ => ‘Int’),
    )
    )));

    }

    Do you think this is possible without using the services?

    Greetings and sorry for my English 🙂

    • Macks said, on October 25, 2012 at 11:20 pm

      Sorry, filter class name is “Class SampleFilterForm implements InputFilterAwareInterface”

      • samsonasik said, on October 26, 2012 at 12:27 am

        model layer can contain business logic and data access logic, as long as it’s a business logic or data access logic, you can define as your desire.

  10. dimuthu said, on November 5, 2012 at 9:59 am

    Hi samsonasik,
    Thanks for the great tutorial.can you send me some sample code for populate drop down list with the database?
    TQs

  11. mludewig said, on November 19, 2012 at 5:53 am

    Hey samsonasik,
    Very good tutorials, i re-code the most of them locally for better understanding 🙂 But there is a big problem during sending MultiCheckbox Data via AJAX. I build a MultiCheckbox element and subit via normal Framework Post. This works perfect. But try to send via AJAX, the form is not valid if the last checkbox in the list isn’t checked. I tested lots of posibillities, but only if the last echeckbox is checked, the form is valid. I can’t found the solution for the problem. Perhaps the problem is in the name of the Input element. the last array is evertime empty (only an idea):

    RED

    BLUE

    But Sending via Framework POST works. Hope you can help me with this little problem.

    best regards and very good work with your blog 🙂

    mludewig

  12. samsonasik said, on November 19, 2012 at 2:53 pm

    i think it’s your javascript problem. before send, please not submit, but check if the checkbox values are getted.

    • mludewig said, on November 20, 2012 at 4:53 am

      ohhh yes, U R right 🙂 the javascript don’t submit the checkbox array if last element is not selected … strange, but i think so solution is near. Thanks for your hint.

  13. Mohamed said, on November 23, 2012 at 4:34 am

    I have to thanks you I need to add some help for people if you r using fieldset you have to override the populateValues within fieldset the same way

    I was just thinking how this can been handeled within database table search
    if I need to search the json encoded code if u have any vision please share

    ———-
    one more thing do u know Arabic ?

    • samsonasik said, on November 23, 2012 at 11:40 am

      You can encode the array of chekbox search.

      $hobby = array('1','3');
      $where = \Zend\Json\Json::encode($hobby);
       
      $resultSet = $this->select(function (Select $select) use ($where){
          $select->columns(array('id', 'name', 'gender'));
          $select->where(array('hobby'=>$where));
          $select->order(array('id asc'));  
      });
      

      I know a little English. I don’t know arabic language.

      • Mohamed said, on November 26, 2012 at 8:19 am

        thanx

        but what about orwhere
        say:
        select * where hoppy in(1,2,3,4)

        i think if the field will be used in query condition it should be separated to another table

        if u have an idea to do the above query please let me know

      • samsonasik said, on November 26, 2012 at 4:06 pm

        i think you should use separate table ( master, transaction, detail, etc) to do that. for full sql example, clone this : https://github.com/ralphschindler/Zend_Db-Examples

  14. ori said, on November 26, 2012 at 2:53 pm

    Hey Abdul,

    I have similar elements with the same name & label attribute. How would I change the attributes without needing to create another element with hard coded attributes in controller?

    I have the following

    In Controller;
    $name = new Element(‘name’);
    $name->setLabel(‘First name’);
    $name->setAttributes(array(
    ‘type’ => ‘text’
    ));

    $form->add($name);

    In View:
    First Name
    formRow($form->get(‘name’)); ?>

    Last Name
    formRow($form->get(‘name’)); ?>

    Thanks

    • samsonasik said, on November 26, 2012 at 4:09 pm

      I don’t understand what you mean. but you can change the attribute via :

      $form->get('elementname')->setAttribute(array('attrname'=>'attrvalue'));
      
  15. Ori said, on November 26, 2012 at 5:09 pm

    You did cause you answered my question. However this is what worked for me $form->get(‘elementname’)->setAttribute(‘attrname’,’attrvalue’);

    Thank You

  16. ron said, on December 21, 2012 at 5:08 pm

    I have a problem with dynamic changed select box options via ajax. (Category Tree). I get the error “The input was not found in the haystack.” This appears propably, because the options are not the same ones as they should be in the validator. So how can i deactivate the validiator for the Selectbox. I tried ‘inarrayvalidator’ => false but it does not seem to work.

    can someone help me out?
    thanks

    • samsonasik said, on December 22, 2012 at 10:48 pm

      don’t try to deactive the default validator. re-values the select options values before setData.

      $form->get('state_id')
                       ->setOptions(
                        array('value_options'=> $Newstatecollection)) ;
      
  17. Chris said, on January 16, 2013 at 6:49 am

    \Zend\Validator\Between does not validate dates. Between only does string validation. Trying to use this method with another format like ‘m/d/Y’ will not correctly limit the date.

  18. piasek said, on January 29, 2013 at 5:45 pm

    Hi man
    I have a question to you? I want to create a form N-photos (where N could be any number). I want to be able to add description to any number of photos that are already in my database. I want also be able to select which photos are at the moment active on web-page or one that i could delete. But i don’t wanna be able to add or select each time only one photo. I would like add some description, active or delete any number of photos and update those data only once sending those information to database.
    So my question is how in this case i should prepare my Model and Form files, since each time number of photos is different? What would you suggest?

  19. Mohammad Nomaan Patel said, on March 5, 2013 at 12:28 pm

    Assalamualaikum, first of all thanks to you for providing such a good tutorial for a newbie in Zend Framework.
    I am having a doubt with haystack. I want to pass database entries into haystack. I am not getting how to do it…
    So it would be nice to if you give some guidelines regarding it…

    I am waiting for your reply….

    • samsonasik said, on March 5, 2013 at 1:54 pm

      for easy setup, you can add function to set Data to the value_options like this :

      public function setData($data) 
      {
          $this->datavalueoptions = $data;
      }
      

      so, you can pass the data via factories :

      'factories'=>array(
           'yourform' => function($sm) {
                 $form = new \YourModule\Form\YourForm();
                 $form->setData($sm->get('YourTableModel')->getData());
      
                 return $form;         
          },
      ),
      
      • Mohammad Nomaan Patel said, on March 5, 2013 at 2:27 pm

        Thanks for your reply,

        I have done the above steps but getting exception error ‘haystack option is mandatory’.

        Regards.

      • samsonasik said, on March 5, 2013 at 4:18 pm

        your datavalue should be pass into ‘value_options’ key.
        for example :

        foreach($this->datavalueoptions as $row)
         {
                    $datavalueoptions[$row->country_id] = $row->country_name;
          }
        
         $this->add(array(
                    'type' => 'Zend\Form\Element\Select',
                    'name' => 'country_id',
                    'options' => array(
                        'label' => 'Country :',
                        'value_options' => $datavalueoptions
                    ),
                    'attributes' => array(
                        'class'    => 'country'
                    ),
                ));
        

        make sure your $datavalueoptions is array like :

        array(
               '0' => 'Indonesia', 
              '1' => 'Japan'
        )
        

        to make sure, you should print_r the data that you get.

      • thiagoferri said, on May 22, 2013 at 3:11 am

        I tried to do that in FORM, to made a Dynamic SELECT with database values. But it first load FORM INPUT on CONTRUCT, after that it load values.

        I can’t load that dyanmica value in form, can you help ?

  20. Mohammad Nomaan Patel said, on March 5, 2013 at 5:42 pm

    Thanks it work’s…..

  21. vinu said, on March 7, 2013 at 7:28 pm

    Hi

    I want to make seprate module admin login and logout so currently my folder name is manager i want to login with username and password i need suggestion. please suggest.

    How to work with aith library for admin login

    thank s
    vinu

    • samsonasik said, on March 8, 2013 at 1:53 am

      while your app authenticate the username/login, your app should check the role who logged in, and pass to what he can do with the role. if his role is admin, he will be passed to admin module, etc.

  22. vian said, on March 11, 2013 at 8:02 am

    samsonik,saya ada masalah mengenai “Zend\Form\Element\Date” yang tampil hanya sebagai textbox biasa bukan date, mohon bantuannya. terima kasih

    • samsonasik said, on March 11, 2013 at 4:27 pm

      coba pakai chrome browser atau opera.

      • vian said, on March 11, 2013 at 5:28 pm

        thanks berhasil. sebelumnya sudah coba pakai firefox dan IE tdk berhasil, tidak terpikir klo hanya karena browser

      • samsonasik said, on March 11, 2013 at 8:06 pm

        sip

      • vian said, on March 15, 2013 at 7:39 pm

        samsonasik jika masalah sebelumnya pada date element, sy menemui hal yg sama untuk datetime element. sebagai informasi element “date” yg berhasil dirender oleh browser hanya berupa textbox dengan masked “mm/dd/yyyy” bukan datepicker, apakah memang seperti itu. thx

      • samsonasik said, on March 17, 2013 at 1:14 am

        biasanya sih tergantung browser sih, heuheu. coba buat custom element aja kalau ribet 😀

  23. Mario said, on March 28, 2013 at 5:57 am

    Hi,

    Great post again! Could you please tell us in short manner what is the difference or advantage to use a class implementing InputFilterAwareInterface or a class extending InputFilter? I saw a Rob Allen’s webinar about Zend Form, in there Rob uses InputFilter derived class.

    Thank you!

    • samsonasik said, on March 30, 2013 at 3:07 am

      akrabat make it model and filters separated. you can choose what you like.

      • Mario said, on March 30, 2013 at 3:10 am

        Perfect, thank you!

      • samsonasik said, on March 30, 2013 at 3:27 am

        you’re welcome 😉

  24. Emf said, on April 30, 2013 at 6:36 am

    Salam,
    How do you get the last insert id for student in the saveStudent your model?

      • Emf said, on April 30, 2013 at 3:20 pm

        sorry but it returns me an exception :

        Invalid magic property access in Zend\Db\TableGateway\AbstractTableGateway::__get()

        in the model constuctor I put just this :

        public function __construct(Adapter $adapter)
        {
        $this->adapter = $adapter;
        $this->initialize();
        }

        in the namespace section I put just this :

        use Zend\Db\TableGateway\AbstractTableGateway;
        use Zend\Db\Adapter\Adapter;
        use Zend\Db\Adapter\AdapterInterface;
        use Zend\Db\Adapter\Driver\DriverInterface;
        use Zend\Db\ResultSet\ResultSet;
        use Front\Model\NewStudent; //this is the student class with form annotations

        I Wonder if I forgot something else.

        thnx.

      • samsonasik said, on April 30, 2013 at 3:44 pm

        if you extends AbstractTableGateway, so you can just call via $this directly

        $this->lastInsertValue;
        

        or if you call via instantiated model, you can call $this->instantiatedModel->lastInsertValue, for ex :

        $this->getAlbumTable()->lastInsertValue;
        

        read the latest doc : http://zf2.readthedocs.org/ there is a better way using tableGateway instead of extends AbstractTableGateway.

      • Joe Nilson said, on June 7, 2013 at 7:42 pm

        Hi samsonasik, i’m using postgres and the lastinsertvalue dont work in zf 2.1.4 is a pdo bug or is a zf2 bug?.

        i use:

        
        use Zend\Db\Adapter\Adapter;
        use Zend\Db\TableGateway\AbstractTableGateway;
        use Zend\Db\TableGateway\Feature;
        use Zend\Db\Sql\TableIdentifier;
        use Zend\Db\Sql\Select;
        
        class UsersTable extends AbstractTableGateway {
        
        	protected $table_name = 'users';
        	protected $schema_name = 'app';
        
        	public function __construct(Adapter $adapter) {
        		$this->table = new TableIdentifier($this->table_name, $this->schema_name);
        		$this->adapter = new Feature\FeatureSet();
        		$this->adapter->addFeature(new Feature\SequenceFeature('id','system.users_id_seq'));
        		$this->adapter = $adapter;
        	}
        
        public function save(Users $user)
        	{
        		$data = array(
                    'username' => $user->getUsername(),
                    'password' => $user->getPassword(),
        		    'salt' => $user->getSalt(),
                    'realname' => $user->getRealname(),
        		    'role' => $user->getRole(),
        		    'date_created' => $user->getDate_created(),
        		);
        		
        		$id = (int) $user->id;
        		if ($id == 0) {
        			$this->insert($data); //if i do a print_r of this i get 1 i suposse that is the number of records
        			//return $this->getLastInsertValue(); //gives null
        			//return $this->lastInsertValue; //gives null
        			//return $this->adapter->getDriver()->getLastGeneratedValue(); //gives null
        		} elseif ($this->getUserById($id)) {
        			$this->update(
        					$data,
        					array('id' => $id,)
        			);
        			return $id;
        		} else {
        			throw new \Exception('id object does not exist');
        		}
        	}
        

        I have search for the documentation but i dont see nothing with postgres, can you give me some help or what i’m forgetting.

        thanks for your patience and help.

        Joe

      • samsonasik said, on June 8, 2013 at 2:15 am

        try latest zf2 master.

      • joenilson said, on June 8, 2013 at 2:37 am

        I do this workaround in the save function:

        Add in the begin of the class

        protected $sequence_name = 'system.users_id_seq';
        

        And in the insert statement do:

        if (!$this->insert($data))
                        return false;
                    return $this->adapter->getDriver()->getLastGeneratedValue($this->sequence_name);
        

        I found in the zf2 bugtrack that postgres need the sequence name to get the currval, instead it i update de zf2 to the 2.2.0 stable release but i cant make the $this->getLastGeneratedValue($this->sequence_name) works.

        Thanks for your blog is very useful to me. 🙂

      • samsonasik said, on June 8, 2013 at 3:53 am

        if you found an issue, then you should submit that at https://github.com/zendframework/zf2/issues

  25. Emf said, on April 30, 2013 at 4:56 pm

    It works now, I found a little var spelling error in my code 😉

    Thanks a lot,

  26. Rocco said, on May 17, 2013 at 10:18 pm

    Hi!
    When I submit my form for adding values, my url is of this type “http://www.mydomain.com/album/add/ID.
    If my form is not valid (ex. empty field) refreshing page I lost ID in the url.
    Do you help me?

    • Rocco said, on May 17, 2013 at 10:47 pm

      Stupid bug. Solved:

      $form->setAttribute(‘action’, $this->url(
      ‘album’,
      array(
      ‘action’ => ‘add-album’,
      ‘id’ => $this->id,
      )));

  27. Mohammad Nomaan said, on May 28, 2013 at 6:13 pm

    Hi Samsonasik,

    I am appending row to a table dynamically. But my problem is that I am unable to change the attributes. Is there a way to change the attributes of zend form elements using jquery.

    Any help would be appriciated..
    Thanks in advance

  28. Dj. Coban said, on June 3, 2013 at 2:04 am

    hi, is there a way to get this work in the main layout.phtml view?
    e.g. “Form” in a sidebar and content&error in echo $this->content;

  29. Dj. Coban said, on June 3, 2013 at 5:50 am

    you are great, thank you so much… 😀

  30. zack said, on June 10, 2013 at 4:14 pm

    Hello samsonasik, How can I get action/controller name in Form class/ InputFilter Class.
    Sometimes I have change InputFilter/Form depend on action (example: in edit action i want ‘upload_image’ field become ‘require’ => false).
    Thanks u very much !!!

    • samsonasik said, on June 10, 2013 at 9:40 pm

      set form __construct($parameter) with getFormElementConfig() at Module.php

      public function getFormElementConfig()
          {
              return array(
                  'factories' => array(
                      'Application\Form\FormName' => function($sm) {
                          
                          $parameter =  $sm->getServiceLocator()->get('Router')
                              ->match($sm->getServiceLocator()->get('Request'))
                              ->getParam('controller');
                              
                          $form = new \Application\Form\FormName($parameter);
                          return $form;
                      },
                  ),
              );
          }
      

      and try to call at controller :

      $form = $this->getServiceLocator()->get('FormElementManager')->get('Application\Form\FormName');
      
      • zack said, on June 11, 2013 at 8:18 am

        Thanks u for reply. So, do you have other way to do it. Can I attach in event so every form can call it without using service for each form.
        Thanks !

      • samsonasik said, on June 11, 2013 at 11:02 am

        Of course, create a form that implement EventManagerAwareInterface.

        namespace MyModule\Form;
        
        use Zend\Form\Form;
        use Zend\EventManager\EventManager;
        use Zend\EventManager\EventManagerAwareInterface;
        use Zend\EventManager\EventManagerInterface;
        
        class MyForm extends Form
            implements EventManagerAwareInterface
        {
            protected $events;
        
            public function __construct($name = null)
            {
                $this->getEventManager()->trigger('initForm', $this);
                
                parent::__construct('album');
                //other thing here...
            }
            
            public function setEventManager(EventManagerInterface $events)
            {
                $this->events = $events;
                return $this;
            }
            
            public function getEventManager()
            {
                if (!$this->events) {
                    $this->setEventManager(new EventManager(__CLASS__));
                }
                return $this->events;
            }
        }
        

        And attach at Module::onBootstrap like the following :

        namespace MyModule;
        
        use Zend\Mvc\MvcEvent;
        
        class Module
        {
            public function onBootstrap(MvcEvent $e)
            {
                $sm = $e->getApplication()->getServiceManager();
                $parameter =  $sm->get('Router')
                                ->match($sm->get('Request'))
                                ->getParam('controller');
                                
                $e->getApplication()
                  ->getEventManager()
                  ->getSharedManager()
                  ->attach('MyModule\Form\MyForm', 'initForm', function(Event $event)
                                    use ($parameter) {
                    $form  = $event->getTarget();
                    $form->setAttribute('action', $parameter);
                });
            }
            
            public function getConfig() { /* common code here */ }
            public function getAutoloaderConfig() { /* common code here */ }
        }
        
  31. zack said, on June 11, 2013 at 2:10 pm

    Oh, thanks for your help.

  32. Aniruddh said, on June 21, 2013 at 6:11 pm

    foreach($this->datavalueoptions as $row)
    {
    $datavalueoptions[$row->id] = $row->artist;
    }
    $this->add(array(
    ‘type’ => ‘Zend\Form\Element\Select’,
    ‘name’ => ‘artist’,
    ‘options’ => array(
    ‘label’ => ‘Artist::’,
    ‘value_options’ => $datavalueoptions
    ),
    ‘attributes’ => array(
    ‘value’ => ‘Artist’ //set selected to ‘1’
    )
    ));

    i used this code for dropdown but this code can give me blank values how can i get values from database..

  33. kalelc said, on July 23, 2013 at 6:01 am

    hello..when sending data:

    “haystack option is mandatory”

    mi form is:

    $this->add(array(
    ‘type’ => ‘Select’,
    ‘name’ => ‘documentType_id’,
    ‘options’ => array(
    ‘label’ => ‘Tipo de Documento:’,
    ‘disable_inarray_validator’ => true,
    ’empty_option’ => “seleccione un documento”,
    ‘value_options’ => $this->getOptionsDocumentType(),
    ),
    ));
    model is:

    $inputFilter->add($factory->createInput(array(
    ‘name’ => ‘documentType_id’,
    ‘required’ => true,
    ‘validators’ => array(
    array(
    ‘name’ => ‘NotEmpty’,
    ‘options’ => array(
    ‘messages’ => array(
    \Zend\Validator\NotEmpty::IS_EMPTY => ‘el campo no debe estar vacio’
    ),
    ),
    ),
    array(
    ‘name’ => ‘InArray’,
    ‘options’ => array(
    ‘messages’ => array(
    \Zend\Validator\InArray::NOT_IN_ARRAY => ‘el campo no debe estar vacio’,

    ),
    ),
    ),
    ),
    )));

  34. Michael said, on August 7, 2013 at 8:33 am

    Hello samsonasik, have a nice day.
    I am working with zf2 validator Zend Db\NoRecordExists and i have a question, may you help me.
    $inputFilter->add($factory->createInput(array(
    ‘name’ => ‘display_name’,
    ‘required’ => true,
    ‘filters’ => array(
    array(‘name’ => ‘StripTags’),
    array(‘name’ => ‘StringTrim’),
    ),
    ‘validators’ => array(
    array(
    ‘name’ => ‘StringLength’,
    ‘options’ => array(
    ‘encoding’ => ‘UTF-8’,
    ‘min’ => 1,
    ‘max’ => 255,
    ),
    ),
    array(
    ‘name’ => ‘Db\NoRecordExists’,
    ‘options’ => array(
    ‘table’ => ‘user’,
    ‘field’ => ‘display_name’,
    ‘adapter’ => $this->dbAdapter,

    ),
    ),
    ),
    )));

    And i want to set EXCLUDE for this validator from CONTROLLER, i know we can set in in the form filter but i want to set from controller, and i do it like this:

    $displayNameExclude = $formFilter->getInputFilter()->get(‘display_name’)->getValidatorChain()->getValidators();

    $displayNameExclude[1][‘instance’]->setExclude(array(‘field’=>’id’,’value’=>$user_id));

    I don’t think it’s a good way to do it, do you have any way to do it, Thanks !!!

  35. kalelc said, on August 8, 2013 at 9:49 pm

    hello..in you example is:

    array(
    ‘name’ => ‘Db\NoRecordExists’,
    ‘options’ => array(
    ‘table’ => ‘user’,
    ‘field’ => ‘display_name’,
    ‘exclude’ => ‘michael’, #value to exclude
    ‘adapter’ => $this->dbAdapter,

    ),

    if you are using filters, the best way to do this is by using the model

    I hope that helps you

  36. bhuvanesh said, on September 10, 2013 at 10:19 pm

    Can you blog other tutorial about select element which load from database….

  37. Ragunathan said, on September 24, 2013 at 6:39 pm

    I Want To Validate given date is valid are not..please give me the input filter coding for date

  38. vasu said, on October 1, 2013 at 2:22 pm

    IN select option if country is USA and in next select option usa states alone can display ,,,all should be load from database

    any idea

    • samsonasik said, on October 1, 2013 at 2:36 pm

      it javascript, not ZF specific how to :). Add event onchange on your first select and send request via ajax, while get response, fill to the next select.

      • vasu said, on October 1, 2013 at 2:41 pm

        can u blog that tutorial…if possible

      • samsonasik said, on October 1, 2013 at 2:51 pm

        oh man, you SHOULD NOT rely on me. I just blog if I interest, and you not pay for that :p. take effort to learn from the basic, google before ask, there are plenty of examples on google that maybe not ZF specific, but can be applied as references to fullfill your need. you are a programmer, you can’t always ask, programmer just need a clues for they problem. if you ask again something like this, I will mark you as spam.

  39. kamlesh said, on October 10, 2013 at 2:33 pm

    Hello samsonasik

    i have form element like this
    $this->add(array(
    ‘type’ => ‘Zend\Form\Element\Select’,
    ‘name’ => ‘group_user_ids’,
    ‘attributes’ => array(
    ‘id’ => ‘group_user_ids’,
    ‘class’ => ‘styled’,
    ‘multiple’ => ‘multiple’,
    ),
    ‘options’ => array(
    #’label’ => ‘Author’,
    ’empty_option’ => ‘Please select User’,
    ‘value_options’ => $this->getOptionsForUserSelect(),
    )
    ));

    when i tried to set data
    $form->setData($request->getPost());
    it is showing warning like this

    Warning: Zend\Filter\StripTags::filter expects parameter to be scalar, “array” given; cannot filter in D:\XAMPP\htdocs\zendapp\vendor\zendframework\zendframework\library\Zend\Filter\StripTags.php on line 190

    i want to store multiple user using either comma separated or json encode and while edit it should decode json or comma separated ad finally show selected option.

  40. Isaac said, on November 22, 2013 at 1:24 am

    Hi ! how can i add an attribute to a label when i do a instance of a text input??

    $this->add(array(
    ‘name’ => ‘nomEstatus’,
    ‘options’ => array(
    ‘label’ => ‘ Nombre del Estatus: ‘,

    ¿The attibutes here?

    ),
    ‘type’ => ‘Text’,
    ‘attributes’ => array(
    ‘id’ => ‘nomEstatus’,
    ‘placeholder’=>’Nombre del estatus’,
    ),
    ));

  41. unity said, on November 27, 2013 at 7:23 pm

    Hey i saw your post here its very helpful but I want to do one on chained/dependent selects..here is a question I posted on stackoverflow http://stackoverflow.com/questions/20212746/zend-forms-working-with-ajax-javascript-onchnge

    Thanks in advance

  42. Antonio Capelantonio said, on December 5, 2013 at 11:15 pm

    Hi! My Zend\Form\Element\Select is populate with data from database, but if my data has an accented words, the word does not appear. I added this code:
    ‘driver_options’ => array(
    PDO::MYSQL_ATTR_INIT_COMMAND => ‘SET NAMES \’UTF8\”
    ),
    but still does not work.
    Can you help me please? Thank you

  43. Azhar said, on January 30, 2014 at 11:57 am

    I want to bind a drop down field with a variable which has a value from the database???
    please reply me

  44. Azhar said, on January 30, 2014 at 1:37 pm

    i have already created a form using factories but i bind all the fields by using ArrayObject but it is not bind the select field and i have value in variable but it is not bind the value of the variable to the select field

  45. Pd said, on July 3, 2014 at 1:19 pm

    The usage of formElementErrors for showing error messages for checkbox was really helpful…Thanks

  46. Welington said, on August 13, 2014 at 10:57 am

    Can I extract only one checkbox from Multicheckbox element? I mean, can I renderize “Cooking”, “Writing”, “Others” separately or I have to create checkboxes with different names in order to do that? I have a form with 70 checkboxes and I had to display them in columns so I was wondering what should I do.

    • samsonasik said, on August 14, 2014 at 12:21 am

      you can grab the values of multicheckbox by :

                              $countCheckboxTags = count($group_form->get('multicheckboxelementname')->getValueOptions());
                              $valueOptions = $group_form->get('multicheckboxelementname')->getValueOptions();
      

      from that, you can manage the view.

  47. tshering said, on September 25, 2014 at 12:34 pm

    Hi, thank you so much for your tutorial, it is very nice. But if i want to edit the form, how can i get drop down list options in my edit page.

    Thank You

  48. LA'ercio said, on October 16, 2014 at 7:59 am

    haven’t found any documentation for setting field attributes to for a form collection. I can set the value of a single input field .

    • samsonasik said, on October 17, 2014 at 6:54 am

      $form->get(‘fieldname’)->setAttributes(array(
      ‘attributename’ => ‘attributevalue’,
      ));

      • Laercio said, on November 5, 2014 at 8:15 pm

        Thank samsonasik

  49. Laercio said, on November 5, 2014 at 8:22 pm

    samsonasik, how can I save a multi checkbox field in controller?
    thanks

    • samsonasik said, on November 7, 2014 at 7:55 pm

      please read the post properly. anyway, you can extract the post data after $form->isValid() by $form->getData(); and do debugging in there.

  50. Ashim said, on December 30, 2014 at 1:15 pm

    Hi samsonasik, I am always getting the error “The input was not found in the haystack” when I have select a language from a drop down. My code I am giving here to understand better.

    in my controller

    function singleAction(){

    —-
    —-
    $language = array();
    $languages = $this->getManageTable()->getLanguage();

    foreach($languages as $lang){
    $language[”] = ‘Select Language’;
    $language[$lang[‘id_language’]] = $lang[‘name’];
    }

    —-
    —-
    return new ViewModel(array(
    ‘form’ => $form,
    ‘language’ => $language,
    ));
    }

    in manageForm.php —–

    // Language Input
    $language = new Element\Select(‘language’);
    $language->setAttributes(array(
    ‘id’ => ‘language’,
    ‘class’ => ‘form-control’,
    ));
    $this->add($language);

    $language = new InputFilter\Input(‘language’);
    $language->setRequired(false);
    //$language->removeValidator(“NotEmpty”); // not working giving error
    // $language->setAllowEmptysetRegisterInArrayValidator(false); // not working giving error
    //$language->setErrorMessage(‘Please select language’);
    $inputFilter->add($language);

    In my View i called like below ——-

    Language
    formSelect($form->get(‘language’)->setValueOptions($language)); ?>

    now when I submit without selecting value from drop-down working fine but if I select some language and submit, giving error like “The input was not found in the haystack”, I checked my language data I am getting in post but if ($form->isValid()) {—-} is giving error. How can I resolve this, I checked lot of linked but not getting my solution. Please help me.

    • samsonasik said, on December 30, 2014 at 9:00 pm

      if your options changed during onchange, basically, you need to re-set the value options during post data before setData and isValid like this :

      // options dependency changed, re-set collection of values
      $form->get('language')->setValueOptions($newValue);
      $form->setData($request->getPost());
      $form->isValid();
      
      • Ashim said, on December 31, 2014 at 7:26 pm

        Thank you

  51. Andr said, on February 8, 2015 at 7:35 pm

    Hi samsonasik and all. May you help me?. I have a fieldset with a select, but when I call it from view, the viewhelper wrapping my select in label tags, why it happening? Or how can I avoid it?
    like a
    ddd

    but must be like this :

    dddd

    What I doing wrong?

    • samsonasik said, on February 9, 2015 at 10:02 am

      just call :

      echo $this->formElement($form->get('elname'));
      

      directly or create your custom helper for your need.

      • Andr said, on February 9, 2015 at 1:01 pm

        Thanks for you reply.

        I meant that if I call a formElement “select” without a fieldset, viewhelper render correct html tags.
        open-label-tag …. close-label-tag
        open-select-tag ……options….close-select-tag

        but if I calling the fieldset, it render select wrapped into label tags
        open-label-tag
        open-select-tag ……options….close-select-tag
        close-label-tag

        What is a different between fieldset and a regular element in a form?

        formElement and formCollection show the same result.

      • samsonasik said, on February 9, 2015 at 1:16 pm

        not sure if it’s a big deal, but you could call label manually via :

        echo $this->formLabel($form->get('fieldname'));
        
      • Andr said, on February 9, 2015 at 1:45 pm

        code of the form and fieldset
        http://pastebin.com/nhiKTr7w

  52. Andr said, on February 9, 2015 at 1:23 pm

    In this case, I had an error
    _invoke expects either label content as the second argument, or that the element……

    I guess because it fieldset

  53. super8dragon said, on August 26, 2015 at 10:11 am

    Your entries is still helpful.
    Thank you.

  54. weikian said, on September 14, 2015 at 2:33 pm

    Nice tutorial. Well I have one question, how to create multi-page form if using your current tutorial example. I will appreciate very much if u can reply. 🙂

    • samsonasik said, on September 14, 2015 at 2:46 pm

      depends, if multi form you mean is front-end with js interaction, just set the view interaction with js, if it is a backend set session data per-next submit, then you can use zend\session.

      • weikian said, on September 26, 2015 at 6:19 pm

        Thanks for reply. Right now i have two forms named form1 and form2 . I not sure how to put logic in the Controller like if the user submit form1 with no errors or clear the validation, the user can proceed to next form. I’m sure i can do it with js and jquery. I’m not sure is there another way can do with zf2. So far i don’t see any examples how to do the multi step form with zf2. Appreciate it very much if u have some idea.

      • samsonasik said, on September 26, 2015 at 6:40 pm

        zf2 means php means server side, so nothing to do with javascript. the way to go for that is using session.

  55. Ahmad said, on October 10, 2015 at 9:49 am

    Hi , just a quick question. Why my checkbox is displayed in one line and your one is separated ? Do u dod something on the CSS ?

    • samsonasik said, on October 10, 2015 at 11:43 am

      we may have different style, yes, do with CSS for your need!

  56. Hamza Chekroun said, on October 11, 2016 at 3:30 am

    call to a member populateValues($data);


Leave a reply to Mohammad Nomaan Cancel reply