696 lines
17 KiB
PHP
696 lines
17 KiB
PHP
<?php
|
|
/**
|
|
* Zend Framework
|
|
*
|
|
* LICENSE
|
|
*
|
|
* This source file is subject to the new BSD license that is bundled
|
|
* with this package in the file LICENSE.txt.
|
|
* It is also available through the world-wide-web at this URL:
|
|
* http://framework.zend.com/license/new-bsd
|
|
* If you did not receive a copy of the license and are unable to
|
|
* obtain it through the world-wide-web, please send an email
|
|
* to license@zend.com so we can send you a copy immediately.
|
|
*
|
|
* @category Zend
|
|
* @package Zend_Markup
|
|
* @subpackage Renderer
|
|
* @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com)
|
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
|
* @version $Id$
|
|
*/
|
|
|
|
/**
|
|
* @see Zend_config
|
|
*/
|
|
/**
|
|
* @see Zend_Filter
|
|
*/
|
|
/**
|
|
* @see Zend_Markup_Renderer_TokenConverterInterface
|
|
*/
|
|
|
|
/**
|
|
* Defines the basic rendering functionality
|
|
*
|
|
* @category Zend
|
|
* @package Zend_Markup
|
|
* @subpackage Renderer
|
|
* @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com)
|
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
|
*/
|
|
abstract class Zend_Markup_Renderer_RendererAbstract
|
|
{
|
|
const TYPE_CALLBACK = 4;
|
|
const TYPE_REPLACE = 8;
|
|
const TYPE_ALIAS = 16;
|
|
|
|
/**
|
|
* Tag info
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $_markups = array();
|
|
|
|
/**
|
|
* Parser
|
|
*
|
|
* @var Zend_Markup_Parser_ParserInterface
|
|
*/
|
|
protected $_parser;
|
|
|
|
/**
|
|
* What filter to use
|
|
*
|
|
* @var bool
|
|
*/
|
|
protected $_filter;
|
|
|
|
/**
|
|
* Filter chain
|
|
*
|
|
* @var Zend_Filter
|
|
*/
|
|
protected $_defaultFilter;
|
|
|
|
/**
|
|
* The current group
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $_group;
|
|
|
|
/**
|
|
* Groups definition
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $_groups = array();
|
|
|
|
/**
|
|
* Plugin loader for tags
|
|
*
|
|
* @var Zend_Loader_PluginLoader
|
|
*/
|
|
protected $_pluginLoader;
|
|
|
|
/**
|
|
* The current token
|
|
*
|
|
* @var Zend_Markup_Token
|
|
*/
|
|
protected $_token;
|
|
|
|
/**
|
|
* Encoding
|
|
*
|
|
* @var string
|
|
*/
|
|
protected static $_encoding = 'UTF-8';
|
|
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* @param array|Zend_Config $options
|
|
*
|
|
* @return void
|
|
*/
|
|
public function __construct($options = array())
|
|
{
|
|
if ($options instanceof Zend_Config) {
|
|
$options = $options->toArray();
|
|
}
|
|
|
|
if (isset($options['encoding'])) {
|
|
$this->setEncoding($options['encoding']);
|
|
}
|
|
if (isset($options['parser'])) {
|
|
$this->setParser($options['parser']);
|
|
}
|
|
if (!isset($options['useDefaultFilters']) || ($options['useDefaultFilters'] === true)) {
|
|
$this->addDefaultFilters();
|
|
}
|
|
if (isset($options['defaultFilter'])) {
|
|
$this->addDefaultFilter($options['defaultFilter']);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set the parser
|
|
*
|
|
* @param Zend_Markup_Parser_ParserInterface $parser
|
|
* @return Zend_Markup_Renderer_RendererAbstract
|
|
*/
|
|
public function setParser(Zend_Markup_Parser_ParserInterface $parser)
|
|
{
|
|
$this->_parser = $parser;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Get the parser
|
|
*
|
|
* @return Zend_Markup_Parser_ParserInterface
|
|
*/
|
|
public function getParser()
|
|
{
|
|
return $this->_parser;
|
|
}
|
|
|
|
/**
|
|
* Get the plugin loader
|
|
*
|
|
* @return Zend_Loader_PluginLoader
|
|
*/
|
|
public function getPluginLoader()
|
|
{
|
|
return $this->_pluginLoader;
|
|
}
|
|
|
|
/**
|
|
* Set the renderer's encoding
|
|
*
|
|
* @param string $encoding
|
|
*
|
|
* @return void
|
|
*/
|
|
public static function setEncoding($encoding)
|
|
{
|
|
self::$_encoding = $encoding;
|
|
}
|
|
|
|
/**
|
|
* Get the renderer's encoding
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function getEncoding()
|
|
{
|
|
return self::$_encoding;
|
|
}
|
|
|
|
/**
|
|
* Add a new markup
|
|
*
|
|
* @param string $name
|
|
* @param string $type
|
|
* @param array $options
|
|
*
|
|
* @return Zend_Markup_Renderer_RendererAbstract
|
|
*/
|
|
public function addMarkup($name, $type, array $options)
|
|
{
|
|
if (!isset($options['group']) && ($type ^ self::TYPE_ALIAS)) {
|
|
throw new Zend_Markup_Renderer_Exception("There is no render group defined.");
|
|
}
|
|
|
|
// add the filter
|
|
if (isset($options['filter'])) {
|
|
if ($options['filter'] instanceof Zend_Filter_Interface) {
|
|
$filter = $options['filter'];
|
|
} elseif ($options['filter'] === true) {
|
|
$filter = $this->getDefaultFilter();
|
|
} else {
|
|
$filter = false;
|
|
}
|
|
} else {
|
|
$filter = $this->getDefaultFilter();
|
|
}
|
|
|
|
// check the type
|
|
if ($type & self::TYPE_CALLBACK) {
|
|
// add a callback tag
|
|
if (isset($options['callback'])) {
|
|
if (!($options['callback'] instanceof Zend_Markup_Renderer_TokenConverterInterface)) {
|
|
throw new Zend_Markup_Renderer_Exception("Not a valid tag callback.");
|
|
}
|
|
if (method_exists($options['callback'], 'setRenderer')) {
|
|
$options['callback']->setRenderer($this);
|
|
}
|
|
} else {
|
|
$options['callback'] = null;
|
|
}
|
|
|
|
$options['type'] = $type;
|
|
$options['filter'] = $filter;
|
|
|
|
$this->_markups[$name] = $options;
|
|
} elseif ($type & self::TYPE_ALIAS) {
|
|
// add an alias
|
|
if (empty($options['name'])) {
|
|
throw new Zend_Markup_Renderer_Exception(
|
|
'No alias was provided but tag was defined as such');
|
|
}
|
|
|
|
$this->_markups[$name] = array(
|
|
'type' => self::TYPE_ALIAS,
|
|
'name' => $options['name']
|
|
);
|
|
} else {
|
|
if ($type && array_key_exists('empty', $options) && $options['empty']) {
|
|
// add a single replace markup
|
|
$options['type'] = $type;
|
|
$options['filter'] = $filter;
|
|
|
|
$this->_markups[$name] = $options;
|
|
} else {
|
|
// add a replace markup
|
|
$options['type'] = $type;
|
|
$options['filter'] = $filter;
|
|
|
|
$this->_markups[$name] = $options;
|
|
}
|
|
}
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Remove a markup
|
|
*
|
|
* @param string $name
|
|
*
|
|
* @return void
|
|
*/
|
|
public function removeMarkup($name)
|
|
{
|
|
unset($this->_markups[$name]);
|
|
}
|
|
|
|
/**
|
|
* Remove the default tags
|
|
*
|
|
* @return void
|
|
*/
|
|
public function clearMarkups()
|
|
{
|
|
$this->_markups = array();
|
|
}
|
|
|
|
/**
|
|
* Render function
|
|
*
|
|
* @param Zend_Markup_TokenList|string $tokenList
|
|
* @return string
|
|
*/
|
|
public function render($value)
|
|
{
|
|
if ($value instanceof Zend_Markup_TokenList) {
|
|
$tokenList = $value;
|
|
} else {
|
|
$tokenList = $this->getParser()->parse($value);
|
|
}
|
|
|
|
$root = $tokenList->current();
|
|
|
|
$this->_filter = $this->getDefaultFilter();
|
|
|
|
return $this->_render($root);
|
|
}
|
|
|
|
/**
|
|
* Render a single token
|
|
*
|
|
* @param Zend_Markup_Token $token
|
|
* @return string
|
|
*/
|
|
protected function _render(Zend_Markup_Token $token)
|
|
{
|
|
$return = '';
|
|
|
|
$this->_token = $token;
|
|
|
|
// if this tag has children, execute them
|
|
if ($token->hasChildren()) {
|
|
foreach ($token->getChildren() as $child) {
|
|
$return .= $this->_execute($child);
|
|
}
|
|
}
|
|
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Get the group of a token
|
|
*
|
|
* @param Zend_Markup_Token $token
|
|
* @return string|bool
|
|
*/
|
|
protected function _getGroup(Zend_Markup_Token $token)
|
|
{
|
|
if (!isset($this->_markups[$token->getName()])) {
|
|
return false;
|
|
}
|
|
|
|
$tag = $this->_markups[$token->getName()];
|
|
|
|
// alias processing
|
|
while ($tag['type'] & self::TYPE_ALIAS) {
|
|
$tag = $this->_markups[$tag['name']];
|
|
}
|
|
|
|
return isset($tag['group']) ? $tag['group'] : false;
|
|
}
|
|
|
|
/**
|
|
* Execute the token
|
|
*
|
|
* @param Zend_Markup_Token $token
|
|
* @return string
|
|
*/
|
|
protected function _execute(Zend_Markup_Token $token)
|
|
{
|
|
// first return the normal text tags
|
|
if ($token->getType() == Zend_Markup_Token::TYPE_NONE) {
|
|
return $this->_filter($token->getTag());
|
|
}
|
|
|
|
// if the token doesn't have a notation, return the plain text
|
|
if (!isset($this->_markups[$token->getName()])) {
|
|
$oldToken = $this->_token;
|
|
$return = $this->_filter($token->getTag()) . $this->_render($token) . $token->getStopper();
|
|
$this->_token = $oldToken;
|
|
return $return;
|
|
}
|
|
|
|
$name = $this->_getMarkupName($token);
|
|
$markup = (!$name) ? false : $this->_markups[$name];
|
|
$empty = (is_array($markup) && array_key_exists('empty', $markup) && $markup['empty']);
|
|
|
|
// check if the tag has content
|
|
if (!$empty && !$token->hasChildren()) {
|
|
return '';
|
|
}
|
|
|
|
// check for the context
|
|
if (is_array($markup) && !in_array($markup['group'], $this->_groups[$this->_group])) {
|
|
$oldToken = $this->_token;
|
|
$return = $this->_filter($token->getTag()) . $this->_render($token) . $token->getStopper();
|
|
$this->_token = $oldToken;
|
|
return $return;
|
|
}
|
|
|
|
// check for the filter
|
|
if (!isset($markup['filter'])
|
|
|| (!($markup['filter'] instanceof Zend_Filter_Interface) && ($markup['filter'] !== false))) {
|
|
$this->_markups[$name]['filter'] = $this->getDefaultFilter();
|
|
}
|
|
|
|
// save old values to reset them after the work is done
|
|
$oldFilter = $this->_filter;
|
|
$oldGroup = $this->_group;
|
|
|
|
$return = '';
|
|
|
|
// set the filter and the group
|
|
$this->_filter = $this->getFilter($name);
|
|
|
|
if ($group = $this->_getGroup($token)) {
|
|
$this->_group = $group;
|
|
}
|
|
|
|
// callback
|
|
if (is_array($markup) && ($markup['type'] & self::TYPE_CALLBACK)) {
|
|
// load the callback if the tag doesn't exist
|
|
if (!($markup['callback'] instanceof Zend_Markup_Renderer_TokenConverterInterface)) {
|
|
$class = $this->getPluginLoader()->load($name);
|
|
|
|
$markup['callback'] = new $class;
|
|
|
|
if (!($markup['callback'] instanceof Zend_Markup_Renderer_TokenConverterInterface)) {
|
|
throw new Zend_Markup_Renderer_Exception("Callback for tag '$name' found, but it isn't valid.");
|
|
}
|
|
|
|
if (method_exists($markup['callback'], 'setRenderer')) {
|
|
$markup['callback']->setRenderer($this);
|
|
}
|
|
}
|
|
if ($markup['type'] && !$empty) {
|
|
$return = $markup['callback']->convert($token, $this->_render($token));
|
|
} else {
|
|
$return = $markup['callback']->convert($token, null);
|
|
}
|
|
} else {
|
|
// replace
|
|
if ($markup['type'] && !$empty) {
|
|
$return = $this->_executeReplace($token, $markup);
|
|
} else {
|
|
$return = $this->_executeSingleReplace($token, $markup);
|
|
}
|
|
}
|
|
|
|
// reset to the old values
|
|
$this->_filter = $oldFilter;
|
|
$this->_group = $oldGroup;
|
|
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Filter method
|
|
*
|
|
* @param string $value
|
|
*
|
|
* @return string
|
|
*/
|
|
protected function _filter($value)
|
|
{
|
|
if ($this->_filter instanceof Zend_Filter_Interface) {
|
|
return $this->_filter->filter($value);
|
|
}
|
|
return $value;
|
|
}
|
|
|
|
/**
|
|
* Get the markup name
|
|
*
|
|
* @param Zend_Markup_Token
|
|
*
|
|
* @return string
|
|
*/
|
|
protected function _getMarkupName(Zend_Markup_Token $token)
|
|
{
|
|
$name = $token->getName();
|
|
if (empty($name)) {
|
|
return false;
|
|
}
|
|
|
|
return $this->_resolveMarkupName($name);
|
|
}
|
|
|
|
/**
|
|
* Resolve aliases for a markup name
|
|
*
|
|
* @param string $name
|
|
*
|
|
* @return string
|
|
*/
|
|
protected function _resolveMarkupName($name)
|
|
{
|
|
while (($type = $this->_getMarkupType($name))
|
|
&& ($type & self::TYPE_ALIAS)
|
|
) {
|
|
$name = $this->_markups[$name]['name'];
|
|
}
|
|
|
|
return $name;
|
|
}
|
|
|
|
/**
|
|
* Retrieve markup type
|
|
*
|
|
* @param string $name
|
|
* @return false|int
|
|
*/
|
|
protected function _getMarkupType($name)
|
|
{
|
|
if (!isset($this->_markups[$name])) {
|
|
return false;
|
|
}
|
|
if (!isset($this->_markups[$name]['type'])) {
|
|
return false;
|
|
}
|
|
return $this->_markups[$name]['type'];
|
|
}
|
|
|
|
/**
|
|
* Execute a replace token
|
|
*
|
|
* @param Zend_Markup_Token $token
|
|
* @param array $tag
|
|
* @return string
|
|
*/
|
|
protected function _executeReplace(Zend_Markup_Token $token, $tag)
|
|
{
|
|
return $tag['start'] . $this->_render($token) . $tag['end'];
|
|
}
|
|
|
|
/**
|
|
* Execute a single replace token
|
|
*
|
|
* @param Zend_Markup_Token $token
|
|
* @param array $tag
|
|
* @return string
|
|
*/
|
|
protected function _executeSingleReplace(Zend_Markup_Token $token, $tag)
|
|
{
|
|
return $tag['replace'];
|
|
}
|
|
|
|
/**
|
|
* Get the default filter
|
|
*
|
|
* @return void
|
|
*/
|
|
public function getDefaultFilter()
|
|
{
|
|
if (null === $this->_defaultFilter) {
|
|
$this->addDefaultFilters();
|
|
}
|
|
|
|
return $this->_defaultFilter;
|
|
}
|
|
|
|
/**
|
|
* Add a default filter
|
|
*
|
|
* @param string $filter
|
|
*
|
|
* @return void
|
|
*/
|
|
public function addDefaultFilter(Zend_Filter_Interface $filter, $placement = Zend_Filter::CHAIN_APPEND)
|
|
{
|
|
if (!($this->_defaultFilter instanceof Zend_Filter)) {
|
|
$defaultFilter = new Zend_Filter();
|
|
$defaultFilter->addFilter($filter);
|
|
$this->_defaultFilter = $defaultFilter;
|
|
}
|
|
|
|
$this->_defaultFilter->addFilter($filter, $placement);
|
|
}
|
|
|
|
/**
|
|
* Set the default filter
|
|
*
|
|
* @param Zend_Filter_Interface $filter
|
|
*
|
|
* @return void
|
|
*/
|
|
public function setDefaultFilter(Zend_Filter_Interface $filter)
|
|
{
|
|
$this->_defaultFilter = $filter;
|
|
}
|
|
|
|
/**
|
|
* Get the filter for an existing markup
|
|
*
|
|
* @param string $markup
|
|
*
|
|
* @return Zend_Filter_Interface
|
|
*/
|
|
public function getFilter($markup)
|
|
{
|
|
$markup = $this->_resolveMarkupName($markup);
|
|
|
|
if (!isset($this->_markups[$markup]['filter'])
|
|
|| !($this->_markups[$markup]['filter'] instanceof Zend_Filter_Interface)
|
|
) {
|
|
if (isset($this->_markups[$markup]['filter']) && $this->_markups[$markup]['filter']) {
|
|
$this->_markups[$markup]['filter'] = $this->getDefaultFilter();
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return $this->_markups[$markup]['filter'];
|
|
}
|
|
|
|
/**
|
|
* Add a filter for an existing markup
|
|
*
|
|
* @param Zend_Filter_Interface $filter
|
|
* @param string $markup
|
|
* @param string $placement
|
|
*
|
|
* @return Zend_Markup_Renderer_RendererAbstract
|
|
*/
|
|
public function addFilter(Zend_Filter_Interface $filter, $markup, $placement = Zend_Filter::CHAIN_APPEND)
|
|
{
|
|
$markup = $this->_resolveMarkupName($markup);
|
|
|
|
$oldFilter = $this->getFilter($markup);
|
|
|
|
// if this filter is the default filter, clone it first
|
|
if ($oldFilter === $this->getDefaultFilter()) {
|
|
$oldFilter = clone $oldFilter;
|
|
}
|
|
|
|
if (!($oldFilter instanceof Zend_Filter)) {
|
|
$this->_markups[$markup]['filter'] = new Zend_Filter();
|
|
|
|
if ($oldFilter instanceof Zend_Filter_Interface) {
|
|
$this->_markups[$markup]['filter']->addFilter($oldFilter);
|
|
}
|
|
} else {
|
|
$this->_markups[$markup]['filter'] = $oldFilter;
|
|
}
|
|
|
|
$this->_markups[$markup]['filter']->addFilter($filter, $placement);
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Set the filter for an existing
|
|
*
|
|
* @param Zend_Filter_Interface $filter
|
|
* @param string $markup
|
|
*
|
|
* @return Zend_Markup_Renderer_RendererAbstract
|
|
*/
|
|
public function setFilter(Zend_Filter_Interface $filter, $markup)
|
|
{
|
|
$markup = $this->_resolveMarkupName($markup);
|
|
|
|
$this->_markups[$markup]['filter'] = $filter;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Add a render group
|
|
*
|
|
* @param string $name
|
|
* @param array $allowedInside
|
|
* @param array $allowsInside
|
|
*
|
|
* @return void
|
|
*/
|
|
public function addGroup($name, array $allowedInside = array(), array $allowsInside = array())
|
|
{
|
|
$this->_groups[$name] = $allowsInside;
|
|
|
|
foreach ($allowedInside as $group) {
|
|
$this->_groups[$group][] = $name;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get group definitions
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getGroups()
|
|
{
|
|
return $this->_groups;
|
|
}
|
|
|
|
/**
|
|
* Set the default filters
|
|
*
|
|
* @return void
|
|
*/
|
|
abstract public function addDefaultFilters();
|
|
|
|
}
|