Disregard Inputs
Acquire Zend_Form
Daniel CousineauInteractive Software Engineer @ RAPP@dcousineauhttp://dcousineau.com/[email protected]
Zend_AclZend_AmfZend_ApplicationZend_AuthZend_BarcodeZend_CacheZend_CaptchaZend_CloudZend_CodeGeneratorZend_ConfigZend_Config_WriterZend_Console_GetoptZend_ControllerZend_CurrencyZend_DateZend_DbZend_DebugZend_DojoZend_DomZend_ExceptionZend_FeedZend_FileZend_FilterZend_Form
Zend_GdataZend_HttpZend_InfoCardZend_JsonZend_LayoutZend_LdapZend_LoaderZend_LocaleZend_LogZend_MailZend_MarkupZend_MeasureZend_MemoryZend_MimeZend_NavigationZend_OauthZend_OpenIdZend_PaginatorZend_PdfZend_ProgressBarZend_QueueZend_ReflectionZend_RegistryZend_Rest
Zend_Search_LuceneZend_SerializerZend_ServerZend_ServiceZend_SessionZend_SoapZend_TagZend_TestZend_TextZend_TimeSyncZend_ToolZend_Tool_FrameworkZend_Tool_ProjectZend_TranslateZend_UriZend_ValidateZend_VersionZend_ViewZend_WildfireZend_XmlRpcZendX_Console_Process_UnixZendX_JQuery
Zend_AclZend_AmfZend_ApplicationZend_AuthZend_BarcodeZend_CacheZend_CaptchaZend_CloudZend_CodeGeneratorZend_ConfigZend_Config_WriterZend_Console_GetoptZend_ControllerZend_CurrencyZend_DateZend_DbZend_DebugZend_DojoZend_DomZend_ExceptionZend_FeedZend_FileZend_FilterZend_Form
Zend_GdataZend_HttpZend_InfoCardZend_JsonZend_LayoutZend_LdapZend_LoaderZend_LocaleZend_LogZend_MailZend_MarkupZend_MeasureZend_MemoryZend_MimeZend_NavigationZend_OauthZend_OpenIdZend_PaginatorZend_PdfZend_ProgressBarZend_QueueZend_ReflectionZend_RegistryZend_Rest
Zend_Search_LuceneZend_SerializerZend_ServerZend_ServiceZend_SessionZend_SoapZend_TagZend_TestZend_TextZend_TimeSyncZend_ToolZend_Tool_FrameworkZend_Tool_ProjectZend_TranslateZend_UriZend_ValidateZend_VersionZend_ViewZend_WildfireZend_XmlRpcZendX_Console_Process_UnixZendX_JQuery
http://snipsnsnailsandpuppydogtails.blogspot.com/2010/05/introducing-captain-jack-sparrow-and.html
I CAN HAZ
HAI WERLD!?!
Zend_Form
$form = new Zend_Form();
$form->setAction('/path/to/action') ->setMethod('post') ->setAttrib('id', 'FORMID');
Render Form
<form id="FORMID" enctype="application/x-www-form-urlencoded" action="/path/to/action" method="post"> <dl class="zend_form"></dl></form>
<?php print $form; ?>
$output = $form->render();
Add Elements
$element = new Zend_Form_Element_Text('hello');$element->setLabel('Oh Hai Werld!') ->setRequired(true);
$form->addElement($element, 'hello');
$form->addElement('text', 'hello', array( 'label' => 'Oh Hai Werld!', 'required' => true,));
Add Elements
<dl> <dt id="hello-label"> <label for="hello" class="required"> Oh Hai Werld! </label> </dt> <dd id="hello-element"> <input type="text" name="hello" id="hello" value=""> </dd></dl>
Zend_Form_Element_ButtonZend_Form_Element_CaptchaZend_Form_Element_CheckboxZend_Form_Element_FileZend_Form_Element_HiddenZend_Form_Element_HashZend_Form_Element_ImageZend_Form_Element_MultiCheckboxZend_Form_Element_MultiselectZend_Form_Element_RadioZend_Form_Element_ResetZend_Form_Element_SelectZend_Form_Element_SubmitZend_Form_Element_TextZend_Form_Element_Textarea
Handle Input
if (!empty($_POST) && $form->isValid($_POST)) { $values = $form->getValues(); //FORM IS VALID}
if ($this->getRequest()->isPost() && $form->isValid($this->getRequest()->getParams())) { $values = $form->getValues(); //FORM IS VALID}
Add Validation
$form->addElement('text', 'hello', array( 'label' => 'Oh Hai Werld!', 'validators' => array( 'Alnum' //@see Zend_Validate_Alnum ),));
$form->addElement('text', 'hello', array( 'label' => 'Oh Hai Werld!', 'validators' => array( new Zend_Validate_Alnum(), ),));
Add Filters
$form->addElement('text', 'hello', array( 'label' => 'Oh Hai Werld!', 'filters' => array( 'StringTrim' //@see Zend_Filter_StringTrim ),));
$form->addElement('text', 'hello', array( 'label' => 'Oh Hai Werld!', 'filters' => array( new Zend_Filter_StringTrim(), ),));
COOL BEST PRACTICES BRO
Extend Zend_Form Objectclass Namespace_Form_HelloWorld extends Zend_Form { public function init() { /* Form Elements & Other Definitions Here ... */ $this->addElement('text', 'hello', array( 'label' => 'Oh Hai Werld!', 'required' => true, 'validators' => array( 'Alnum', ), )); $this->addElement('submit', 'submit', array( 'label' => 'I Can Haz Submit', )); }}
Extend Zend_Form Object
$form = new Namespace_Form_HelloWorld();
$form = new Zend_Form();
Store Forms By Module
STYLING
Decorator Pattern
BASICALLY: Wrappers for rendering
Element has list of decorators
Render Decorator n
Send output to Decorator n+1
Repeat until no more decorators
Decorator Pattern
2 “levels” of decorators
Form-Level
Element-Level
Form level decorator “FormElements” loops through each element and triggers their render
ELEMENT
...
ELEMENT
DECORATEDECORATE
DECORATE
FormElements DECORATOR
ELEMENT
Default Form Decorators$this->addDecorator('FormElements') ->addDecorator('HtmlTag', array( 'tag' => 'dl', 'class' => 'zend_form') ) ->addDecorator('Form');
<form>
<dl class=”zend_form”>
Loop & Render Form Elements
$this->addDecorator('ViewHelper') ->addDecorator('Errors') ->addDecorator('Description', array('tag' => 'p', 'class' => 'description')) ->addDecorator('HtmlTag', array( 'tag' => 'dd', 'id' => array('callback' => $getId) )) ->addDecorator('Label', array('tag' => 'dt'));
<dt>LABEL</dt>
Default Element Decorators
<dd id=”...”>
<p class=”description”></p>
<ul><li>ERRORS</li></ul>
RENDER ELEMENT
PLEASE EXPLAIN TO ME
HOW BEST PRACTICES FITS WITH PHILOSORAPTOR
Integrate Early
If you’re using custom decorators, set the prefix paths EARLY. Constructor OR first few lines of init()
Optionally have an application-wide parent Form class that all other forms extend
Here you can do common things like set the prefix paths
Use render() Sparingly
Overriding Zend_Form::render() is tempting
Useful for bulk-altering element decorators
Just be very judicial
CUSTOM ELEMENTS
Extend Zend_Form_Element
Override loadDefaultDecorators()
Usually copy original, but replace ViewHelper with custom decorator
Add flags and features to your hearts content
Create Decorator
Override render()
Use an existing render from, say, HtmlTag, as a starting point
Use array notation on any sub-fields
e.g. “fullyQualifiedName[foo]”, etc
Handle/Validate Input
Override setValue() and getValue()
setValue() will receive the value from $_FORM (including sub-arrays, etc)
Override isValid() with caution:
isValid() calls setValue()
Possibly create custom Zend_Validate_ and attach in the custom element
Using
$form->getPluginLoader(Zend_Form::DECORATOR) ->addPrefixPath('Namespace_Form_Decorator', '/path/to/decorators'); $form->getPluginLoader(Zend_Form::ELEMENT) ->addPrefixPath('Namespace_Form_Element', 'path/to/elements');
Basic Example
Custom Element
class Namespace_Form_Element_Markup extends Zend_Form_Element_Xhtml{ public function isValid($value, $context = null) { return true; } public function loadDefaultDecorators() { if ($this->loadDefaultDecoratorsIsDisabled()) { return; } $decorators = $this->getDecorators(); if (empty($decorators)) { $this->addDecorator(new Namespace_Form_Decorator_Markup()) ->addDecorator('HtmlTag', array('tag' => 'dd')); } }}
Custom Decoratorclass Namespace_Form_Decorator_Markup extends Zend_Form_Decorator_Abstract { public function render($content) { $element = $this->getElement(); if (!$element instanceof Namespace_Form_Element_Markup) return $content; $name = $element->getName(); $separator = $this->getSeparator(); $placement = $this->getPlacement();
$markup = '<div id="' . $name . '" class="markup">' . $element->getValue() . '</div>';
switch ($placement) { case self::PREPEND: return $markup . $separator . $content; case self::APPEND: default: return $content . $separator . $markup; } }}
Complex Example
Custom Elementclass Namespace_Form_Element_Date extends Zend_Form_Element_Xhtml { const DEFAULT_DATE_FORMAT = '%year%-%month%-%day%'; //... public function loadDefaultDecorators(){ if ($this->loadDefaultDecoratorsIsDisabled()) return; $this->addDecorator(new Namespace_Form_Decorator_Date()) ->addDecorator('Errors') ->addDecorator('Description', array('tag' => 'p', 'class' => 'description')) ->addDecorator('HtmlTag', array( 'tag' => 'dd', 'id' => $this->getName() . '-element') ) ->addDecorator('Label', array('tag' => 'dt')); } public function getDateFormat() {} public function setDateFormat($dateFormat) {} //...}
Custom Elementclass Namespace_Form_Element_Date extends Zend_Form_Element_Xhtml { //... public function setValue($value) { if (is_array($value)) { $year = !empty($value['year']) ? $value['year'] : null; $month = !empty($value['month']) ? $value['month'] : null; $day = !empty($value['day']) ? $value['day'] : 1; if ($year && $month) { $date = new DateTime(); $date->setDate((int)$year, (int)$month, (int) $day); $date->setTime(0, 0, 0); $this->setAutoInsertNotEmptyValidator(false); $this->_value = $date; } } else { $this->_value = $value; }
return $this; } //...}
Custom Elementclass Namespace_Form_Element_Date extends Zend_Form_Element_Xhtml { //... public function getValue() { switch ($this->getReturnType()) { case self::RETURN_TYPE_ARRAY: if ($this->_value === null) return array('year' => null, 'month' => null, 'day' => null);
$date = array( 'year' => date('Y', $this->_value->getTimestamp()), 'month' => date('m', $this->_value->getTimestamp()), 'day' => date('d', $this->_value->getTimestamp()) ); array_walk_recursive($date, array($this, '_filterValue')); return $date; default: throw new Zend_Form_Element_Exception('Unknown return type: ' . $this->getReturnType()); } } //...}
Custom Decoratorclass Namespace_Form_Decorator_Date extends Zend_Form_Decorator_Abstract { const DEFAULT_DISPLAY_FORMAT = '%year% / %month% / %day%'; //... public function render($content) { $element = $this->getElement(); if (!$element instanceof Form\Element\Date) return $content;
$view = $element->getView(); if (!$view instanceof Zend_View_Interface) throw new Zend_Form_Decorator_Exception('View object is required'); //... $markup = str_replace( array('%year%', '%month%', '%day%'), array( $view->formSelect($name . '[year]', $year, $params, $years), $view->formSelect($name . '[month]', $month, $params, $months), $view->formSelect($name . '[day]', $day, $params, $days), ), $this->displayFormat );
switch ($this->getPlacement()) { case self::PREPEND: return $markup . $this->getSeparator() . $content; case self::APPEND: default: return $content . $this->getSeparator() . $markup; } }}
Y U NO USE THEM!?
BEST PRACTICES
Mimic Namespace
Mimic Zend_Form’s name spacing
Namespace_Form_Decorator_ ↔
Zend_Form_Decorator_
If you aren’t already, mimic Zend’s structure (PEAR style)
Namespace_Form_Decorator_Date → Namespace/Form/Decorator/Date.php
Use Prefix Paths Or Not
Either directly reference the custom classes throughout your entire project, or don’t
Don’t jump back and forth