Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Disregard Inputs, Acquire Zend_Form

Disregard Inputs, Acquire Zend_Form

Presented at the first-annual Lone Star PHP conference in 2011

Daniel Cousineau

June 11, 2011
Tweet

More Decks by Daniel Cousineau

Other Decks in Programming

Transcript

  1. Zend_Acl Zend_Amf Zend_Application Zend_Auth Zend_Barcode Zend_Cache Zend_Captcha Zend_Cloud Zend_CodeGenerator Zend_Config

    Zend_Config_Writer Zend_Console_Getopt Zend_Controller Zend_Currency Zend_Date Zend_Db Zend_Debug Zend_Dojo Zend_Dom Zend_Exception Zend_Feed Zend_File Zend_Filter Zend_Form Zend_Gdata Zend_Http Zend_InfoCard Zend_Json Zend_Layout Zend_Ldap Zend_Loader Zend_Locale Zend_Log Zend_Mail Zend_Markup Zend_Measure Zend_Memory Zend_Mime Zend_Navigation Zend_Oauth Zend_OpenId Zend_Paginator Zend_Pdf Zend_ProgressBar Zend_Queue Zend_Reflection Zend_Registry Zend_Rest Zend_Search_Lucene Zend_Serializer Zend_Server Zend_Service Zend_Session Zend_Soap Zend_Tag Zend_Test Zend_Text Zend_TimeSync Zend_Tool Zend_Tool_Framework Zend_Tool_Project Zend_Translate Zend_Uri Zend_Validate Zend_Version Zend_View Zend_Wildfire Zend_XmlRpc ZendX_Console_Process_Unix ZendX_JQuery
  2. Zend_Acl Zend_Amf Zend_Application Zend_Auth Zend_Barcode Zend_Cache Zend_Captcha Zend_Cloud Zend_CodeGenerator Zend_Config

    Zend_Config_Writer Zend_Console_Getopt Zend_Controller Zend_Currency Zend_Date Zend_Db Zend_Debug Zend_Dojo Zend_Dom Zend_Exception Zend_Feed Zend_File Zend_Filter Zend_Form Zend_Gdata Zend_Http Zend_InfoCard Zend_Json Zend_Layout Zend_Ldap Zend_Loader Zend_Locale Zend_Log Zend_Mail Zend_Markup Zend_Measure Zend_Memory Zend_Mime Zend_Navigation Zend_Oauth Zend_OpenId Zend_Paginator Zend_Pdf Zend_ProgressBar Zend_Queue Zend_Reflection Zend_Registry Zend_Rest Zend_Search_Lucene Zend_Serializer Zend_Server Zend_Service Zend_Session Zend_Soap Zend_Tag Zend_Test Zend_Text Zend_TimeSync Zend_Tool Zend_Tool_Framework Zend_Tool_Project Zend_Translate Zend_Uri Zend_Validate Zend_Version Zend_View Zend_Wildfire Zend_XmlRpc ZendX_Console_Process_Unix ZendX_JQuery
  3. 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, ));
  4. 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>
  5. 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 }
  6. 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(), ), ));
  7. 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(), ), ));
  8. Extend Zend_Form Object class 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', )); } }
  9. 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
  10. Decorator Pattern 2 “levels” of decorators Form-Level Element-Level Form level

    decorator “FormElements” loops through each element and triggers their render
  11. 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
  12. $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
  13. 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
  14. Extend Zend_Form_Element Override loadDefaultDecorators() Usually copy original, but replace ViewHelper

    with custom decorator Add flags and features to your hearts content
  15. 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
  16. 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
  17. 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')); } } }
  18. Custom Decorator class 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; } } }
  19. Custom Element class 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) {} //... }
  20. Custom Element class 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; } //... }
  21. Custom Element class 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()); } } //... }
  22. Custom Decorator class 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; } } }
  23. 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
  24. Use Prefix Paths Or Not Either directly reference the custom

    classes throughout your entire project, or don’t Don’t jump back and forth