Working with complex decorators in Zend Framework
Introduction
Zend Framework — a wonderful system. This opinion I have formed on the long closer "communication" with this system. And it is remarkable not because of any special abilities provided by the programmer, and due to the fact that this system is an amazing way invites the programmer to own the improvement for it, the programmer, the benefit of offering simple and at the same time a strong Foundation for your own development.
While working on a project using Zend Framework, I decided to try to make maximum use of its capabilities, and immediately drew attention to the Zend_Form component (I deliberately call Zend_Form component, not a class, because Zend_Form component consists of class Zend_Form and a set of related classes and interfaces). In the documentation it is written quite simply: "Zend_Form simplifies form creation and managing your web applications." In General this is true, but without preparation you sweat it to the Oldies before you will be able to create and render one more or less complex form. Conceptual form in Zend Framework consists of:
-
the
- elements the
- decorators the
- filters the
- validators
Decorator — it is the whole layout, which is logically connected with the form element (surrounds it), but is not part of it. Simply put, decorator — design of a form element.
In this article, I will prove the necessity of existence of group of designer, and publish their code. Too lazy to read the fruit of getmanstva the author can directly go to the code.
the
So what's the problem?
Work with decorators so far, in my opinion, the most difficult and laborious part of the work on the implementation of the forms. In the examples in the documentation, everything is great, except for one thing — it's all very simple, I would even say primitive examples.
But as soon as you want to display something like this
then the problems begin. The main problem is that the repository decorators in Zend_Form component has a one-tier structure, that is, you cannot create nested decorators, you cannot create a decorator for the decorator, etc.
For example, the above portion of the form is encoded with the following code:
As we can see in the element tree, there are two independent branches: a cell of a table frame directly to the form element (input) and the cell frame label (label). The trouble is that the label is not a form element (it is also a decorator). Therefore, in order to create such a structure needs to get right with dirty hacks:
the - $this->setElementDecorators(array(
'ViewHelper'
array('decorator' => array('br' => 'HtmlTag') 'options' => array('tag' => 'span' 'placement' = > Zend_Form_Decorator_Abstract::APPEND)),
array('decorator' => array('tdOpen' => 'HtmlTag') 'options' => array('tag' => 'td' 'openOnly' => true 'placement' = > Zend_Form_Decorator_Abstract::PREPEND)),
array('decorator' => array('tdClose' => 'HtmlTag') 'options' => array('tag' => 'td' 'closeOnly' => true 'placement' = > Zend_Form_Decorator_Abstract::APPEND)),
array('decorator' => array('label' => 'Label') 'options' => array('separator' => '*')),
'Errors'
array('decorator' => array('mainCell' => 'HtmlTag') 'options' => array('tag' => 'td' 'class' => 'tregleft')),
the
- ));
the
- $usernameFieldLabel = $this->user_name- > getDecorator('label');
the - $defaultSeparator = $usernameFieldLabel->getOption('separator');
the - $usernameFieldLabel->setOption('separator', $defaultSeparator.'
Login can contain only Latin letters and underscore "_".');
* This source code was highlighted with Source Code Highlighter.
Among the shortcomings:
-
the
- manually inlining the closing and opening td tags the
- using the options separator not on purpose
the
the Solution
Googling, I do not normally have found and decided to write your own decorator group.
Here's what happened:
<?php
the
- require_once 'Zend/Form/Decorator/Abstract.php';
class Zend_Form_Decorator_GroupDecorator extends Zend_Form_Decorator_Abstract {
the
- /**
* Items (decorators) to group
* @var array
the
- */
protected $_items = null;
the
- /**
* Temporary form decorators to perform operations
* @var Zend_Form_Element
the
- */
private $_temporaryDecoratorsContainer = null;
the
- /**
* Constructor
*
* @param array|Zend_Config $options
* @return void
the
- */
public function __construct($options = null) {
the
- parent::__construct($options);
the - $this->_temporaryDecoratorsContainer = new Zend_Form_Element('_temporaryDecoratorsContainer', array('DisableLoadDefaultDecorators' => true));
the - $this->getItems();
the - }
the
- /**
* Set items to use
*
* @param array $items
* @return Zend_Form_Decorator_GroupDecorator
the
- */
public function setItems($items) {
the
- $this->_items = $this->_temporaryDecoratorsContainer->clearDecorators()->addDecorators($items)->getDecorators();
return $this;
the
- }
the
- /**
* Get the tag
*
* If no items is registered, either via setItems() or as an option, uses empty array.
*
* @return array
the
- */
public function getItems() {
if (null === $this->_items) {
if (null === ($items = $this->getOption('items'))) {
the
- $this->setItems(array());
the - } else {
the - $this->setItems($items);
the - $this->removeOption('items');
the - }
the - }
return $this->_items;
the
- }
public function addDecorator($decorator, $options = null) {
the
- $this->_temporaryDecoratorsContainer- > addDecorator($decorator, $options);
return $this;
the
- }
public function clearDecorators() {
the
- $this->_temporaryDecoratorsContainer- > clearDecorators();
the - $this->_items = array();
the - }
public function getDecorator($index = null) {
if (null === $index) {
return $this->_items;
if (is_numeric($index)) {
the
- $_items = array_values($this->_items);
return ($index < count($_items))?$_items[$index]:null;
the
- }
if (is_string($index)) {
return (array_key_exists($index, $this->_items))?$this->_items[$index]:null;
the
- }
return null;
the
- }
public insertDecoratorBefore function($index, $decorator, $options = null) {
the
- $_decoratorsToAdd = $this->_temporaryDecoratorsContainer->clearDecorators()->addDecorator($decorator, $options)- > getDecorators();
if (is_string($index)) {
the
- $index = array_search($index, array_keys($this->_items));
the - }
if (false !== $index) {
the
- $first = ($index > 0)?array_slice($this->_items, 0, $index, true):array();
the - $last = ($index < count($this->_items))?array_slice($this->_items, $index, null true):array();
the - $this->_items = array_merge($first, (array)$_decoratorsToAdd, $last);
the - }
return $this;
the
- }
the
- /**
* Render content wrapped in a group of decorators
*
* @param string $content
* @return string
the
- */
public function render($content) {
the
- $placement = $this->getPlacement();
the - $items = $this->getItems();
the - $_content = ";
foreach ($items as $_decorator) {
if ($_decorator instanceOf Zend_Form_Decorator_Interface) {
the
- $_decorator- > setElement($this->getElement());
the - $_content = $_decorator->render($_content);
the - }
else {
the
- require_once 'Zend/Form/Decorator/Exception.php';
throw new Zend_Form_Decorator_Exception('Invalid decorator '.$_decorator.' provided; must be string or Zend_Form_Decorator_Interface');
the
- }
the - }
switch ($placement) {
case self::APPEND:
return $content . $_content;
break;
case self::PREPEND:
return $_content . $content;
break;
default:
return $_content.$content.$_content;
break;
the
- }
the - }
the - }
the - ?>
* This source code was highlighted with Source Code Highlighter.
This decorator can:
-
the
- to Create and display decorators arbitrary nesting, and this means that whatever the complexity the
- to perform operations on the decorators (add, delete, insert) on the fly, thereby allowing you to edit group set default
<?php
class Form_MemberRegister extends Zend_Form {
public function init() {
the
- $this->setDisableLoadDefaultDecorators(true);
the
- $this->addDecorator('FormElements')
the - - > addDecorator(array('table' => 'HtmlTag'), array('tag' => 'table' 'class' => 'treg'))
the - - > addDecorator('Form');
the
- $this->addElement('text' 'user_name', array('label' => 'Login'));
the - $this->addElement('password' 'password2', array('label' => 'Repeat password:'));
the - $this->addElement('text' 'email', array('label' => 'E-mail'));
the
- $this->setElementDecorators(array(
array('decorator' => array('labelGroup' => 'GroupDecorator') 'options' => array('items' => array(
array('decorator' => 'Text' 'options' => array('text' => '*')),
array('decorator' => array('span' => 'HtmlTag') 'options' => array('tag' => 'span' 'class' => 'red')),
array('decorator' => 'Label''options' => array('placement' = > Zend_Form_Decorator_Abstract::PREPEND)),
array('decorator' => array('labelCell' => 'HtmlTag') 'options' => array('tag' => 'td' 'class' => 'tregleft'))
the
- ))),
array('decorator' => array('elementGroup' => 'GroupDecorator') 'options' => array('items' => array(
'ViewHelper'
array('decorator' => array('elementCell' => 'HtmlTag') 'options' => array('tag' => 'td'))
the
- )) 'placement' = > Zend_Form_Decorator_Abstract::APPEND),
array('decorator' => array('mainRowClose' => 'HtmlTag') 'options' => array('tag' => 'tr'))
the
- ));
the
- /**
* @var Zend_Form_Decorator_GroupDecorator
the
- */
the - $usernameFieldLabel = $this->user_name- > getDecorator('labelGroup');
the - $usernameFieldLabel->insertDecoratorBefore('labelCell', array('usernameNotes' => $this->_getNotesDecorator($this->user_name, 'the Username can only consist of Latin letters and underscore "_".')));
the
- /**
* @var Zend_Form_Decorator_GroupDecorator
the
- */
the - $emailFieldDecorator = $this->email->getDecorator('elementGroup');
the - $emailFieldDecorator->insertDecoratorBefore('elementCell', array('emailNotes' => $this->_getNotesDecorator($this->email, 'Enter only existing and working e-mail. At this address You will be sent a link to confirm your registration.')));
the - }
protected _getNotesDecorator function($element, $notesText = ") {
the
- $_d = new Zend_Form_Decorator_GroupDecorator(array('items' => array(
array('decorator' => array('notesText' => 'Text') 'options' => array('text' => $notesText)),
array('decorator' => array('notesTag' => 'HtmlTag') 'options' => array('tag' => 'small')),
array(
'decorator' => array('br' => 'HtmlTag'),
'options' => array('tag' => 'br' 'openOnly' => true 'placement' = > Zend_Form_Decorator_Abstract::PREPEND)
the
- )
the - )));
return $_d- > setElement($element);
the
- }
the - }
the - ?>
* This source code was highlighted with Source Code Highlighter.
If there is another, more elegant solution, of the problem, let me know — I will sprinkle his ashes on his head :)
PS: For opponents of table layout I want to note that this is a post about programming, I'm not a coder — I just had to map a given pattern.
Comments
Post a Comment