Couple of suggestions:
First of all - Use the init()
function instead of constructors to add your elements when you are subclassing the form. The init() function happens after the parameters you pass to the class are set.
Second - Instead of subclassing your form - you can just set an "option" to enable the admin stuff:
class My_Record_Form extends Zend_Form {
protected $_record = null;
public function setRecord($record) {
$this->_record = $record;
}
public function getRecord() {
if ($this->_record === null || (!$this->_record instanceOf My_Record)) {
throw new Exception("Record not set - or not the right type");
}
return $this->_record;
}
protected $_admin = false;
public function setAdmin($admin) {
$this->_admin = $admin;
}
public function getAdmin() { return $this->_admin; }
public function init() {
$record = $this->getRecord();
$this->addElement(......);
$this->addElement(......);
$this->addElement(......);
if ($this->getAdmin()) {
$this->addElement(.....);
}
$this->setDefaults($record->toArray());
}
public function process(array $data) {
if ($this->isValid($data)) {
$record = $this->getRecord();
if (isset($this->delete) && $this->delete->getValue()) {
// delete button was clicked
$record->delete();
return true;
}
$record->setFromArray($this->getValues());
$record->save();
return true;
}
}
}
Then in your controller you can do something like:
$form = new My_Record_Form(array(
'record'=>$record,
'admin'=>My_Auth::getInstance()->hasPermission($record, 'admin')
));
There is nothing "wrong" with making a My_Record_Admin_Form that handles the admin stuff as well - but I found this method keeps all the "record form" code in one single place, and a bit easier to maintain.
To answer section 2: The edit forms in my code are returned from a function of the model: $record->getEditForm()
The controller code ends up looking a little like this:
protected $_domain = null;
protected function _getDomain($allowNew = false)
{
if ($this->_domain)
{
return $this->view->domain = $this->_domain;
} else {
$id = $this->_request->getParam('id');
if (($id == 'new' || $id=='') && $allowNew)
{
MW_Auth::getInstance()->requirePrivilege($this->_table, 'create');
$domain = $this->_table->createRow();
} else {
$domain = $this->_table->find($id)->current();
if (!$domain) throw new MW_Controller_404Exception('Domain not found');
}
return $this->view->domain = $this->_domain = $domain;
}
}
public function editAction()
{
$domain = $this->_getDomain(true);
MW_Auth::getInstance()->requirePrivilege($domain,'edit');
$form = $domain->getEditForm();
if ($this->_request->isPost() && $form->process($this->_request->getPost()))
{
if ($form->delete && $form->delete->getValue())
{
return $this->_redirect($this->view->url(array(
'controller'=>'domain',
'action'=>'index',
), null, true));
} else {
return $this->_redirect($this->view->url(array(
'controller'=>'domain',
'action'=>'view',
'id'=>$form->getDomain()->id,
), null, true));
}
}
$this->view->form = $form;
}
So - the actual id of the record is passed in the URI /domain/edit/id/10 for instance. If you were to put multiple of these forms on a page - you should make sure to set the "action" attribute of the form to point to an action specific to that form.