In Part 1, we are able to split the content into parts and apply decorators on them separately. This can be achieved by using the following classes. I guess the render method of each class pretty much sums up what they do so I will not explain further.
<?php
/**
* @see Zend_Form_Decorator_Abstract
*/
require_once 'Zend/Form/Decorator/Abstract.php';
/**
* This class will store the content into this instance during rendering. You
* can retrieve the stored content using the complementing class
* App_Form_Decorator_Retrieve. When adding several instances of this decorator,
* you will have to alias it. The alias given will be used as the name option of
* the App_Form_Decorator_Retrieve decorator.
*
* Accepts the following option:
* - clear: whether to clear the passed in content by returning an empty content.
*
* Add the following line to the init() function of the Zend_Form-extended class
* and use 'Store' to instantiate this decorator class.
*
* $this->addPrefixPath('App_Form_Decorator', 'App/Form/Decorator', Zend_Form::DECORATOR);
*
* @category App
* @package App_Form_Decorator
*/
class App_Form_Decorator_Store extends Zend_Form_Decorator_Abstract
{
/**
* @access protected
* @var boolean
*/
protected $_clear = null;
/**
* @access protected
* @var string
*/
protected $_content = null;
/**
* Specifies whether to clear the passed in content after it is stored in
* this instance.
*
* @param boolean $clear True if to clear the passed in content.
* @return App_Form_Decorator_Store For method chaining.
* @throws App_Form_Decorator_Exception If parameter is not valid.
*/
public function setClear($clear)
{
if (!is_bool($clear))
{
require_once 'App/Form/Decorator/Exception.php';
throw new App_Form_Decorator_Exception('Clear option is not defined');
}
$this->_clear = $clear;
return $this;
}
/**
* Returns whether to clear the passed in content after it is stored in
* this instance.
*
* @return boolean True if to clear the passed in content.
* @throws App_Form_Decorator_Exception If 'clear' option is not valid.
*/
public function getClear()
{
if (is_null($this->_clear))
{
if (!is_null($clear = $this->getOption('clear')))
{
$this->setClear($clear);
$this->removeOption('clear');
}
else
$this->setClear(true);
}
return $this->_clear;
}
/**
* Clears content stored in this instance.
*
* @return App_Form_Decorator_Store For method chaining.
*/
public function clearContent()
{
$this->_content = null;
return $this;
}
/**
* Returns content stored in this instance.
*
* @param boolean $clear True if to clear stored content in this instance.
* @return string Stored content.
*/
public function getContent($clear = false)
{
$content = $this->_content;
if (is_null($content))
$content = '';
elseif ($clear)
$this->clearContent();
return $content;
}
/**
* Store the passed in content for retrieval.
*
* @param string $content Passed in content to store.
* @return string Depending on the clear option, it is either empty content or as is.
*/
public function render($content)
{
// Store the passed in content to this instance.
$this->_content = $content;
// Clear or return content.
return ($this->getClear()) ? '' : $content;
}
}
<?php
/**
* @see Zend_Form_Decorator_Abstract
*/
require_once 'Zend/Form/Decorator/Abstract.php';
/**
* This class will retrieve the stored content from complementing class
* App_Form_Decorator_Store. When adding several instances of this decorator,
* you will have to alias it. The alias is purely used to ensure the instances
* will not overwrite each other. To retrieve the stored content, you will need
* to pass the alias used in instantiating the App_Form_Decorator_Store
* decorator to the 'name' option.
*
* Accepts the following options:
* - name: The alias used when creating the App_Form_Decorator_Store instance.
* - remove: Boolean value determining whether to remove the stored content
* after retrieval.
* - separator: string with which to separate passed in content and retrieved
* content.
* - placement: whether to append, prepend or replace with the retrieved
* content.
*
* Add the following line to the init() function of the Zend_Form-extended class
* and use 'Retrieve' to instantiate this decorator class.
*
* $this->addPrefixPath('App_Form_Decorator', 'App/Form/Decorator', Zend_Form::DECORATOR);
*
* @category App
* @package App_Form_Decorator
*/
class App_Form_Decorator_Retrieve extends Zend_Form_Decorator_Abstract
{
/**
* @access protected
* @var string
*/
protected $_name = null;
/**
* @access protected
* @var boolean
*/
protected $_remove = null;
/**
* Returns stored content from the App_Form_Decorator_Store instance.
*
* @param boolean $clear True if to clear stored content after retrieval.
* @return string Stored content.
* @throws App_Form_Decorator_Exception If wrong decorator instance is retrieved.
*/
protected function _getContent($clear)
{
$store = $this->getElement()->getDecorator($this->getName());
if (!$store instanceof App_Form_Decorator_Store)
{
require_once 'App/Form/Decorator/Exception.php';
throw new App_Form_Decorator_Exception('"' . $this->getName() . '" is not a App_Form_Decorator_Store decorator');
}
return $store->getContent($clear);
}
/**
* Specifies the name/alias of the element decorator to retrieve.
*
* @param string $name Name/alias of the element decorator to retrieve.
* @return App_Form_Decorator_Retrieve For method chaining.
* @throws App_Form_Decorator_Exception If parameter is not valid.
*/
public function setName($name)
{
if (!is_string($name))
{
require_once 'App/Form/Decorator/Exception.php';
throw new App_Form_Decorator_Exception('Element decorator name is not defined');
}
if (is_numeric($name))
{
require_once 'App/Form/Decorator/Exception.php';
throw new App_Form_Decorator_Exception('Element decorator name must be alphanumeric');
}
$this->_name = $name;
return $this;
}
/**
* Returns name/alias of the element decorator to retrieve.
*
* @return string Name/alias of the element decorator to retrieve.
* @throws App_Form_Decorator_Exception If 'name' option is not valid.
*/
public function getName()
{
if (is_null($this->_name))
{
if (is_null($name = $this->getOption('name')))
{
require_once 'App/Form/Decorator/Exception.php';
throw new App_Form_Decorator_Exception('Element decorator name is not defined in the options');
}
$this->setName($name);
$this->removeOption('name');
}
return $this->_name;
}
/**
* Specifies whether to remove the stored content in
* App_Form_Decorator_Store instance after retrieval.
*
* @param boolean $remove True if remove the stored content after retrieval.
* @return App_Form_Decorator_Store For method chaining.
* @throws App_Form_Decorator_Exception If parameter is not valid.
*/
public function setRemove($remove)
{
if (!is_bool($remove))
{
require_once 'App/Form/Decorator/Exception.php';
throw new App_Form_Decorator_Exception('Remove option is not defined');
}
$this->_remove = $remove;
return $this;
}
/**
* Returns whether to remove the stored content in
* App_Form_Decorator_Store instance after retrieval.
*
* @return boolean True if remove the stored content after retrieval.
* @throws App_Form_Decorator_Exception If 'remove' option is not valid.
*/
public function getRemove()
{
if (is_null($this->_remove))
{
if (!is_null($remove = $this->getOption('remove')))
{
$this->setRemove($remove);
$this->removeOption('remove');
}
else
$this->setRemove(true);
}
return $this->_remove;
}
/**
* Retrieves the stored content.
*
* @param string $content Passed in content.
* @return string Rendered content.
*/
public function render($content)
{
switch ($this->getPlacement())
{
case self::APPEND:
return $content . $this->getSeparator() . $this->_getContent($this->getRemove());
case self::PREPEND:
return $this->_getContent($this->getRemove()) . $this->getSeparator() . $content;
default:
return $this->_getContent($this->getRemove());
}
}
}
And finally, the App_Form_Decorator_Exception class for completeness.
<?php
/**
* @see Zend_Exception
*/
require_once 'Zend/Exception.php';
/**
* @category App
* @package App_Form_Decorator
*/
class App_Form_Decorator_Exception extends Zend_Exception
{
}
To use them, you just need to put these three classes into a folder App/Form/Decorator. You need to add this folder to the include_path similar to what you did for Zend library. Remember to enable autoloading using the Zend_Loader class. Other information can be found in the class remarks.
|
If there is any optimization or bug, please feel free to point them out so that I can update my copy as well. |
|
Oh… One more thing, you can also used the same concept to create decorator that does formatting, such as indentation, of the rendered content if you haven’t thought of that. |