Ben ondertussen stuk verder gekomen. Hier onder het resultaat.
De magie zit in de setDefaults, isValid en getValues.
Er is een kleine workaround met een prefix voor mijn elementen in de subforms. Deze workaround zorgt er voor dat er geen velden met dezelfde naam voorkomen.
De volgende stap is een Jqueryscript wat een "template subform" kan kopiëren en de attributen wijzigt, zodat je dynamisch subforms kunt toevoegen en kunt verwijderen.
<?php
class Money_Form_Invoice extends Form_Base
{
public function init()
{
$this->setMethod('post')
->setName('invoice')
->setDecorators($this->formDecorators);
$this->addElement('hidden', 'invoice_id', array(
'required' => false,
'decorators' => $this->hiddenDecorator
));
$this->addElement('hidden', 'year', array(
'required' => false,
'decorators' => $this->hiddenDecorator
));
$this->addElement('hidden','serial_code',array(
'required' => true ,
'decorators'=> $this->hiddenDecorator,
));
$this->addElement('text', 'ordernumber', array(
'label' => 'Werkorder',
'maxlength' => 45,
'size' => 15,
'decorators' => $this->elementDecorator,
'required' => true,
'validators' => array(
array('NotEmpty', false, array('messages' => array( 'isEmpty' => 'Dit veld is verplicht')))
),
'filters' => array('stringTrim', 'stripTags'),
));
$this->addElement('text', 'number', array(
'label' => 'Factuur nummer',
'maxlength' => 15,
'size' => 15,
'decorators' => $this->elementDecorator,
'required' => true,
'validators' => array(
array('NotEmpty', false, array('messages' => array( 'isEmpty' => 'Dit veld is verplicht')))
),
'value' => date('W'),
'filters' => array('stringTrim', 'stripTags'),
));
$this->addElement('select', 'status', array(
'label' => 'Status',
'decorators' => $this->elementDecorator,
'required' => true,
'multiOptions' => array(
'0' => 'Onbetaald',
'1' => 'Betaald',
),
'filters' => array('stringTrim', 'stripTags'),
));
$this->addElement('text', 'week', array(
'label' => 'Weeknummer',
'maxlength' => 5,
'size' => 5,
'decorators' => $this->elementDecorator,
'required' => true,
'validators' => array(
array('NotEmpty', false, array('messages' => array( 'isEmpty' => 'Dit veld is verplicht')))
),
'value' => date('W'),
'filters' => array('stringTrim', 'stripTags'),
));
$this->addElement('select', 'company_id', array(
'label' => 'Bedrijf',
'multiOptions' => array(0=>'',1=>'Bedrijf A',2=>'Bedrijf B'),
'decorators' => $this->elementDecorator,
'description' => '',
'filters' => array('stringTrim', 'stripTags'),
));
$this->addElement('select', 'rate', array(
'label' => 'Tarief',
'multiOptions' => Model_Rate::getRatesSelect() ,
'decorators' => $this->elementDecorator,
'description' => '',
'filters' => array('stringTrim', 'stripTags'),
));
$this->addElement('select', 'road_pricing', array(
'label' => 'Reistarief',
'multiOptions' => array('0.19'=>'€0,19','0.30'=>'€0,30') ,
'decorators' => $this->elementDecorator,
'description' => '',
'filters' => array('stringTrim', 'stripTags'),
));
$this->addElement('textarea', 'description', array(
'label' => 'omschrijving',
'class' => 'newLine',
'rows' => 10,
'cols' => 25,
'decorators' => $this->elementDecoratorNewLine,
'description' => 'korte omschrijving van factuur. Wordt gebruikt in overzichten',
'required' => true,
'validators' => array(
array('NotEmpty', false, array('messages' => array( 'isEmpty' => 'Dit veld is verplicht')))
),
'filters' => array('stringTrim', 'stripTags'),
));
$this->addElement('button', 'submit', array(
'label' => 'Opslaan',
'class'=> 'button',
'ignore' => true,
'type' => 'submit',
'decorators' => $this->buttonDecorator,
));
$this->addSubForm(new Zend_Form_SubForm,'lines');
$this->addSubForm(new Zend_Form_SubForm,'new');
$this->addElement('button', 'submit', array(
'label' => 'Opslaan',
'class'=> 'button',
'ignore' => true,
'type' => 'submit',
'order'=>1002,
'decorators' => $this->buttonDecorator,
));
}
public function isValid($data){
$subForm = $this->getSubForm('new');
if(isset($data['new'])){
$data['new']= array();
}
foreach($data as $idx => $line){
$prefixIdx = $idx.'__';
$newSubForm = new Money_Form_SubInvoiceLine(array('prefix'=>$prefixIdx));
$subForm->addSubForm($newSubForm, $idx);
}
return parent::setDefaults($data);
}
public function setDefaults($defaults)
{
$subForm = $this->getSubForm('lines');
$subForm->clearSubForms();
foreach($defaults['lines'] as $idx => $line){
if($idx == 0) $idx =1;
$prefixIdx = $idx.'__';
$subFormLine = new Money_Form_SubInvoiceLine(array('prefix'=>$prefixIdx));
foreach($line as $name => $value){
$subFormLine->setDefault($prefixIdx.$name, $value);
}
$subForm->addSubForm($subFormLine,(string) $idx );
unset($defaults[$idx]);
}
unset($defaults['lines']);
return parent::setDefaults($defaults);
}
public function getValues(){
$values = parent::getValues(true);
$lines = array();
foreach($values['lines'] as $idx => $line ){
if($idx == 0) $idx =1;
foreach($line as $name => $value){
$key = preg_replace('/[0-9]__/','',$name);
$lines[$idx][$key] = $value;
}
}
$values['lines'] = $lines;
return $values;
}
}
<?php
Class Money_Form_SubInvoiceLine extends Form_SubBase
{
protected $_prefix = '';
public function setPrefix($prefix = null){
$this->_prefix = $prefix;
}
public function init(){
$this->addElement('hidden', $this->_prefix.'invoice_id', array(
'required' => false,
'decorators' => $this->hiddenDecorator
));
$this->addElement('hidden', $this->_prefix.'invoice_line_id', array(
'required' => false,
'decorators' => $this->hiddenDecorator
));
$this->addElement('text', $this->_prefix.'description', array(
'label' => 'omschrijving',
'maxlength' => 250,
'size' => 10,
'decorators' => $this->elementDecorator,
'description' => 'korte omschrijving',
'required' => true,
'validators' => array(
array('NotEmpty', false, array('messages' => array( 'isEmpty' => 'Dit veld is verplicht')))
),
'filters' => array('stringTrim', 'stripTags'),
));
$this->addElement('text', $this->_prefix.'hours', array(
'label' => 'Uren',
'maxlength' => 100,
'size' => 4,
'decorators' => $this->elementDecorator,
'required' => true,
'validators' => array(
array('NotEmpty', false, array('messages' => array( 'isEmpty' => 'Dit veld is verplicht')))
),
'filters' => array('stringTrim', 'stripTags'),
));
$this->addElement('text', $this->_prefix.'travel_klm', array(
'label' => 'Kilometers',
'maxlength' => 100,
'size' => 4,
'decorators' => $this->elementDecorator,
'required' => false,
'filters' => array('stringTrim', 'stripTags'),
));
$this->addElement('text', $this->_prefix.'price_klm', array(
'label' => 'Klm prijs',
'maxlength' => 100,
'size' => 4,
'decorators' => $this->elementDecorator,
'required' => false,
'filters' => array('stringTrim', 'stripTags'),
));
$this->addElement('select', $this->_prefix.'rate', array(
'label' => 'Tarief',
'multiOptions' => Model_Rate::getRatesSelect() ,
'decorators' => $this->elementDecorator,
'description' => '',
'filters' => array('stringTrim', 'stripTags'),
));
$this->addElement('select', $this->_prefix.'cost_percentage', array(
'label' => 'Toeslag',
'multiOptions' => array('100'=>'Geen','110'=>'110%','150'=>'150%','200'=>'200%'),
'decorators' => $this->elementDecorator,
'description' => '',
'filters' => array('stringTrim', 'stripTags'),
));
}
}