views:

70

answers:

1

I need to create a few custom form elements (with custom view helpers) in my Zend Framework application. The problem is that they are each so similar. I want to create a base view helper class that each of these can extend and an abstract function that I will require is implemented.

Solution:

So if my Picker element was the abstract class and ContactPicker and OrganizationPicker were the extending classes...

The form element:

class My_Form_Element_ContactPicker extends My_Form_Element_Picker
{
    /**
     * Default form view helper to use for rendering
     * @var string
     */
    public $helper = "contactPickerElement";
}

The view helper:

class My_View_Helper_ContactPickerElement extends My_View_Helper_PickerElement
{
    public function contactPickerElement($name, $value = null, $attribs = null)
    {
        // I don't need to do anything in this function.
        // I only need the parent to do all the work.
        return parent::pickerElement($name, $value, $attribs);
    }

    protected function myAbstractFunctionThatMustBeImplemented()
    {
        // This function will do all the work specific to this extending class.
        $model = new ContactModel();
        return $model->foobar;
    }
}

And here's the abstract view helper:

abstract class Evanta_View_Helper_PickerElement extends Zend_View_Helper_FormElement
{
   /**
    * This function would have been called automatically, but since it's being extended...
    * Any extending classes must remember to manually call this function 
    */
   public function modalPickerElement($name, $value = null, $attribs = null)
    {
        $html = 'My picker element HTML';
        return $html;
    }

    /**
     * This function must be implemented by any extending classes
     */
    abstract protected function myAbstractFunctionThatMustBeImplemented();
}
+3  A: 

Somewhere in your Bootstrap you're going to need to define where your form resources are going to go, I suggest using the autoloader:

$autoloader->addResourceType('default_form', 'forms/', 'Form');

My entire method for loading the autoloader looks like this

protected function _initAutoload()
{
    $autoloader = new Zend_Application_Module_Autoloader(array(
            'namespace' => 'Default_',
            'basePath'  => $this->_root,
        ));

    // Here a define a resource named 'default_form', this can be anything,
    // 2nd param is the path relative to my application folder,
    // and 3rd param is the prefix for the classes inside that folder
    $autoloader->addResourceType('default_form', 'forms/', 'Form');

    Zend_Loader_Autoloader::getInstance()->setFallbackAutoloader(true);

    return $autoloader;
}

You can then create a folder inside this forms folder called Element and then a file called Default_Form_Element_Picker.php and define the class, you can override functions like isValid(), setValues(), getValue(), loadDefaultDecorators() and the __construct()

Default_Form_Element_Picker extends Zend_Form_Element_Xhtml {

}        

You can the extend this class to make your other form elements, by creating files with the names Default_Form_Element_ContactPicker.php and Default_Form_Element_OrganizationPicker.php

Default_Form_Element_ContactPicker extends Default_Form_Element_Picker {

}

Default_Form_Element_OrganizationPicker extends Default_Form_Element_Picker {

}

You could also add a class for creating forms here too, call it Default_Form_A.php

Default_Form_A extends Zend_Form {

    public function __construct()
    {
        // create form elements here suing Zend_Form_Element and your new Custom Elements
    }
}

File structure

 application 
 |--forms   
 |----Default_Form_A.php
 |----Element
 |------ Default_Form_Element_Picker.php
 |------ Default_Form_Element_ContactPicker.php
 |------ Default_Form_Element_OrganizationPicker.php
jakenoble
Very informed answer, good stuff. For the question asker, you can see some already made custom zend form elements here http://github.com/balupton/balphp/tree/master/lib/Bal/Form/Element/ and their view helpers here http://github.com/balupton/balphp/tree/master/lib/Bal/View/Helper/
balupton
Make a slight edit to correctly put files for elements in the `Element` folder and actual form building classes in the `forms` folder
jakenoble
Thanks for your answer. I'm sure it will be helpful to someone getting started. However, I already know how to create the Element. What I don't understand is how to create an abstract ViewHelper, or one that I can extend, since a ViewHelper's constructor is a function of the name of ViewHelper. For example, my abstract will have a function called `pickerElement($name, $value, $attribs)`, but when I extend it, that function becomes `contactPickerElement`. Do I call `parent::pickerElement()`?
Andrew
Nevermind. Figured it out. Stupid question. I marked yours as the correct answer, even though it didn't exactly answer my question.
Andrew
Thanks Andrew!!
jakenoble