Search code examples
zend-formzend-framework2zend-db

Save data from a form collection


I have been following http://framework.zend.com/manual/2.1/en/modules/zend.form.collections.html and it works great with validation and so on.

When the form is valid the guide just runs a var_dump on the entity and it looks something like this:

object(Application\Entity\Product)[622]
  protected 'name' => string 'Chair' (length=5)
  protected 'price' => string '25' (length=2)
  protected 'categories' =>
    array (size=2)
      0 =>
        object(Application\Entity\Category)[615]
          protected 'name' => string 'Armchair' (length=8)
      1 =>
        object(App1ication\Entity\Category)[621]
          protected 'name' => string 'Office' (length=6)

The categories can be more then 2 or just 1. How to save a normal form to a database table I understand and have no problem with. But here we have data for two different tables. I guess I could manually read the categories in my controller and fill them in to a model and save them row by row. But that doesn't feel like the best way of doing it.

How do I get the data from the entity to a model or my database? Can it be done without Doctrine?


Solution

  • You have two choices: getData() or bind().

    bind() is the "automatic" way - you bind an entity to your form object which has a property on that entity which matches the name of your collection. Then, when the form's isValid() method is called, the binding mechanism will pass the values from the collection's elements to the matching property on the entity.

    Alternatively, you can use getData() on the collection object and then do whatever you need to.

    Once you have an entity, to save it, consider using ZfcBase as that does the hard work for you.

    This is a simple example mapper:

    namespace MyModule\Mapper;
    
    use ZfcBase\Mapper\AbstractDbMapper;
    use Zend\Stdlib\Hydrator\ArraySerializable;
    use MyModule\Entity\MyEntity;
    
    class MyMapper extends AbstractDbMapper
    {
        protected $tableName  = 'my_table';
    
        public function __construct()
        {
            $this->setHydrator(new ArraySerializable());
            $this->setEntityPrototype(new MyEntity());
        }
    
        public function save(MyEntity $entity)
        {
            if (!$entity->getId()) {
                $result = $this->insert($entity);
                $entity->setId($result->getGeneratedValue());
            } else {
                $where = 'id = ' . (int)$entity->getId();
                $this->update($entity, $where);
            }
        }
    
        public function fetchAll($choiceGroupId)
        {
            $select = $this->getSelect($this->tableName);
            return $this->select($select);
        }
    
        public function loadById($id)
        {
            $select = $this->getSelect($this->tableName)
                           ->where(array('id' => (int)$id));
    
            return $this->select($select)->current();
        }        
    }
    

    This mapper is using the ArraySerializable hydrator, so your entity object (MyEntity in the example) must implement the methods getArrayCopy() and populate(). getArrayCopy() returns an array of data to be saved and populate() is used to fill the entity from an array of data from database.