File indexing completed on 2025-03-02 05:29:35
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_Markup 0017 * @subpackage Renderer 0018 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0019 * @license http://framework.zend.com/license/new-bsd New BSD License 0020 * @version $Id$ 0021 */ 0022 0023 /** 0024 * @see Zend_config 0025 */ 0026 // require_once 'Zend/Config.php'; 0027 /** 0028 * @see Zend_Filter 0029 */ 0030 // require_once 'Zend/Filter.php'; 0031 /** 0032 * @see Zend_Markup_Renderer_TokenConverterInterface 0033 */ 0034 // require_once 'Zend/Markup/Renderer/TokenConverterInterface.php'; 0035 0036 /** 0037 * Defines the basic rendering functionality 0038 * 0039 * @category Zend 0040 * @package Zend_Markup 0041 * @subpackage Renderer 0042 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0043 * @license http://framework.zend.com/license/new-bsd New BSD License 0044 */ 0045 abstract class Zend_Markup_Renderer_RendererAbstract 0046 { 0047 const TYPE_CALLBACK = 4; 0048 const TYPE_REPLACE = 8; 0049 const TYPE_ALIAS = 16; 0050 0051 /** 0052 * Tag info 0053 * 0054 * @var array 0055 */ 0056 protected $_markups = array(); 0057 0058 /** 0059 * Parser 0060 * 0061 * @var Zend_Markup_Parser_ParserInterface 0062 */ 0063 protected $_parser; 0064 0065 /** 0066 * What filter to use 0067 * 0068 * @var bool 0069 */ 0070 protected $_filter; 0071 0072 /** 0073 * Filter chain 0074 * 0075 * @var Zend_Filter 0076 */ 0077 protected $_defaultFilter; 0078 0079 /** 0080 * The current group 0081 * 0082 * @var string 0083 */ 0084 protected $_group; 0085 0086 /** 0087 * Groups definition 0088 * 0089 * @var array 0090 */ 0091 protected $_groups = array(); 0092 0093 /** 0094 * Plugin loader for tags 0095 * 0096 * @var Zend_Loader_PluginLoader 0097 */ 0098 protected $_pluginLoader; 0099 0100 /** 0101 * The current token 0102 * 0103 * @var Zend_Markup_Token 0104 */ 0105 protected $_token; 0106 0107 /** 0108 * Encoding 0109 * 0110 * @var string 0111 */ 0112 protected static $_encoding = 'UTF-8'; 0113 0114 0115 /** 0116 * Constructor 0117 * 0118 * @param array|Zend_Config $options 0119 * 0120 * @return void 0121 */ 0122 public function __construct($options = array()) 0123 { 0124 if ($options instanceof Zend_Config) { 0125 $options = $options->toArray(); 0126 } 0127 0128 if (isset($options['encoding'])) { 0129 $this->setEncoding($options['encoding']); 0130 } 0131 if (isset($options['parser'])) { 0132 $this->setParser($options['parser']); 0133 } 0134 if (!isset($options['useDefaultFilters']) || ($options['useDefaultFilters'] === true)) { 0135 $this->addDefaultFilters(); 0136 } 0137 if (isset($options['defaultFilter'])) { 0138 $this->addDefaultFilter($options['defaultFilter']); 0139 } 0140 } 0141 0142 /** 0143 * Set the parser 0144 * 0145 * @param Zend_Markup_Parser_ParserInterface $parser 0146 * @return Zend_Markup_Renderer_RendererAbstract 0147 */ 0148 public function setParser(Zend_Markup_Parser_ParserInterface $parser) 0149 { 0150 $this->_parser = $parser; 0151 return $this; 0152 } 0153 0154 /** 0155 * Get the parser 0156 * 0157 * @return Zend_Markup_Parser_ParserInterface 0158 */ 0159 public function getParser() 0160 { 0161 return $this->_parser; 0162 } 0163 0164 /** 0165 * Get the plugin loader 0166 * 0167 * @return Zend_Loader_PluginLoader 0168 */ 0169 public function getPluginLoader() 0170 { 0171 return $this->_pluginLoader; 0172 } 0173 0174 /** 0175 * Set the renderer's encoding 0176 * 0177 * @param string $encoding 0178 * 0179 * @return void 0180 */ 0181 public static function setEncoding($encoding) 0182 { 0183 self::$_encoding = $encoding; 0184 } 0185 0186 /** 0187 * Get the renderer's encoding 0188 * 0189 * @return string 0190 */ 0191 public static function getEncoding() 0192 { 0193 return self::$_encoding; 0194 } 0195 0196 /** 0197 * Add a new markup 0198 * 0199 * @param string $name 0200 * @param string $type 0201 * @param array $options 0202 * 0203 * @return Zend_Markup_Renderer_RendererAbstract 0204 */ 0205 public function addMarkup($name, $type, array $options) 0206 { 0207 if (!isset($options['group']) && ($type ^ self::TYPE_ALIAS)) { 0208 // require_once 'Zend/Markup/Renderer/Exception.php'; 0209 throw new Zend_Markup_Renderer_Exception("There is no render group defined."); 0210 } 0211 0212 // add the filter 0213 if (isset($options['filter'])) { 0214 if ($options['filter'] instanceof Zend_Filter_Interface) { 0215 $filter = $options['filter']; 0216 } elseif ($options['filter'] === true) { 0217 $filter = $this->getDefaultFilter(); 0218 } else { 0219 $filter = false; 0220 } 0221 } else { 0222 $filter = $this->getDefaultFilter(); 0223 } 0224 0225 // check the type 0226 if ($type & self::TYPE_CALLBACK) { 0227 // add a callback tag 0228 if (isset($options['callback'])) { 0229 if (!($options['callback'] instanceof Zend_Markup_Renderer_TokenConverterInterface)) { 0230 // require_once 'Zend/Markup/Renderer/Exception.php'; 0231 throw new Zend_Markup_Renderer_Exception("Not a valid tag callback."); 0232 } 0233 if (method_exists($options['callback'], 'setRenderer')) { 0234 $options['callback']->setRenderer($this); 0235 } 0236 } else { 0237 $options['callback'] = null; 0238 } 0239 0240 $options['type'] = $type; 0241 $options['filter'] = $filter; 0242 0243 $this->_markups[$name] = $options; 0244 } elseif ($type & self::TYPE_ALIAS) { 0245 // add an alias 0246 if (empty($options['name'])) { 0247 // require_once 'Zend/Markup/Renderer/Exception.php'; 0248 throw new Zend_Markup_Renderer_Exception( 0249 'No alias was provided but tag was defined as such'); 0250 } 0251 0252 $this->_markups[$name] = array( 0253 'type' => self::TYPE_ALIAS, 0254 'name' => $options['name'] 0255 ); 0256 } else { 0257 if ($type && array_key_exists('empty', $options) && $options['empty']) { 0258 // add a single replace markup 0259 $options['type'] = $type; 0260 $options['filter'] = $filter; 0261 0262 $this->_markups[$name] = $options; 0263 } else { 0264 // add a replace markup 0265 $options['type'] = $type; 0266 $options['filter'] = $filter; 0267 0268 $this->_markups[$name] = $options; 0269 } 0270 } 0271 return $this; 0272 } 0273 0274 /** 0275 * Remove a markup 0276 * 0277 * @param string $name 0278 * 0279 * @return void 0280 */ 0281 public function removeMarkup($name) 0282 { 0283 unset($this->_markups[$name]); 0284 } 0285 0286 /** 0287 * Remove the default tags 0288 * 0289 * @return void 0290 */ 0291 public function clearMarkups() 0292 { 0293 $this->_markups = array(); 0294 } 0295 0296 /** 0297 * Render function 0298 * 0299 * @param Zend_Markup_TokenList|string $tokenList 0300 * @return string 0301 */ 0302 public function render($value) 0303 { 0304 if ($value instanceof Zend_Markup_TokenList) { 0305 $tokenList = $value; 0306 } else { 0307 $tokenList = $this->getParser()->parse($value); 0308 } 0309 0310 $root = $tokenList->current(); 0311 0312 $this->_filter = $this->getDefaultFilter(); 0313 0314 return $this->_render($root); 0315 } 0316 0317 /** 0318 * Render a single token 0319 * 0320 * @param Zend_Markup_Token $token 0321 * @return string 0322 */ 0323 protected function _render(Zend_Markup_Token $token) 0324 { 0325 $return = ''; 0326 0327 $this->_token = $token; 0328 0329 // if this tag has children, execute them 0330 if ($token->hasChildren()) { 0331 foreach ($token->getChildren() as $child) { 0332 $return .= $this->_execute($child); 0333 } 0334 } 0335 0336 return $return; 0337 } 0338 0339 /** 0340 * Get the group of a token 0341 * 0342 * @param Zend_Markup_Token $token 0343 * @return string|bool 0344 */ 0345 protected function _getGroup(Zend_Markup_Token $token) 0346 { 0347 if (!isset($this->_markups[$token->getName()])) { 0348 return false; 0349 } 0350 0351 $tag = $this->_markups[$token->getName()]; 0352 0353 // alias processing 0354 while ($tag['type'] & self::TYPE_ALIAS) { 0355 $tag = $this->_markups[$tag['name']]; 0356 } 0357 0358 return isset($tag['group']) ? $tag['group'] : false; 0359 } 0360 0361 /** 0362 * Execute the token 0363 * 0364 * @param Zend_Markup_Token $token 0365 * @return string 0366 */ 0367 protected function _execute(Zend_Markup_Token $token) 0368 { 0369 // first return the normal text tags 0370 if ($token->getType() == Zend_Markup_Token::TYPE_NONE) { 0371 return $this->_filter($token->getTag()); 0372 } 0373 0374 // if the token doesn't have a notation, return the plain text 0375 if (!isset($this->_markups[$token->getName()])) { 0376 $oldToken = $this->_token; 0377 $return = $this->_filter($token->getTag()) . $this->_render($token) . $token->getStopper(); 0378 $this->_token = $oldToken; 0379 return $return; 0380 } 0381 0382 $name = $this->_getMarkupName($token); 0383 $markup = (!$name) ? false : $this->_markups[$name]; 0384 $empty = (is_array($markup) && array_key_exists('empty', $markup) && $markup['empty']); 0385 0386 // check if the tag has content 0387 if (!$empty && !$token->hasChildren()) { 0388 return ''; 0389 } 0390 0391 // check for the context 0392 if (is_array($markup) && !in_array($markup['group'], $this->_groups[$this->_group])) { 0393 $oldToken = $this->_token; 0394 $return = $this->_filter($token->getTag()) . $this->_render($token) . $token->getStopper(); 0395 $this->_token = $oldToken; 0396 return $return; 0397 } 0398 0399 // check for the filter 0400 if (!isset($markup['filter']) 0401 || (!($markup['filter'] instanceof Zend_Filter_Interface) && ($markup['filter'] !== false))) { 0402 $this->_markups[$name]['filter'] = $this->getDefaultFilter(); 0403 } 0404 0405 // save old values to reset them after the work is done 0406 $oldFilter = $this->_filter; 0407 $oldGroup = $this->_group; 0408 0409 $return = ''; 0410 0411 // set the filter and the group 0412 $this->_filter = $this->getFilter($name); 0413 0414 if ($group = $this->_getGroup($token)) { 0415 $this->_group = $group; 0416 } 0417 0418 // callback 0419 if (is_array($markup) && ($markup['type'] & self::TYPE_CALLBACK)) { 0420 // load the callback if the tag doesn't exist 0421 if (!($markup['callback'] instanceof Zend_Markup_Renderer_TokenConverterInterface)) { 0422 $class = $this->getPluginLoader()->load($name); 0423 0424 $markup['callback'] = new $class; 0425 0426 if (!($markup['callback'] instanceof Zend_Markup_Renderer_TokenConverterInterface)) { 0427 // require_once 'Zend/Markup/Renderer/Exception.php'; 0428 throw new Zend_Markup_Renderer_Exception("Callback for tag '$name' found, but it isn't valid."); 0429 } 0430 0431 if (method_exists($markup['callback'], 'setRenderer')) { 0432 $markup['callback']->setRenderer($this); 0433 } 0434 } 0435 if ($markup['type'] && !$empty) { 0436 $return = $markup['callback']->convert($token, $this->_render($token)); 0437 } else { 0438 $return = $markup['callback']->convert($token, null); 0439 } 0440 } else { 0441 // replace 0442 if ($markup['type'] && !$empty) { 0443 $return = $this->_executeReplace($token, $markup); 0444 } else { 0445 $return = $this->_executeSingleReplace($token, $markup); 0446 } 0447 } 0448 0449 // reset to the old values 0450 $this->_filter = $oldFilter; 0451 $this->_group = $oldGroup; 0452 0453 return $return; 0454 } 0455 0456 /** 0457 * Filter method 0458 * 0459 * @param string $value 0460 * 0461 * @return string 0462 */ 0463 protected function _filter($value) 0464 { 0465 if ($this->_filter instanceof Zend_Filter_Interface) { 0466 return $this->_filter->filter($value); 0467 } 0468 return $value; 0469 } 0470 0471 /** 0472 * Get the markup name 0473 * 0474 * @param Zend_Markup_Token 0475 * 0476 * @return string 0477 */ 0478 protected function _getMarkupName(Zend_Markup_Token $token) 0479 { 0480 $name = $token->getName(); 0481 if (empty($name)) { 0482 return false; 0483 } 0484 0485 return $this->_resolveMarkupName($name); 0486 } 0487 0488 /** 0489 * Resolve aliases for a markup name 0490 * 0491 * @param string $name 0492 * 0493 * @return string 0494 */ 0495 protected function _resolveMarkupName($name) 0496 { 0497 while (($type = $this->_getMarkupType($name)) 0498 && ($type & self::TYPE_ALIAS) 0499 ) { 0500 $name = $this->_markups[$name]['name']; 0501 } 0502 0503 return $name; 0504 } 0505 0506 /** 0507 * Retrieve markup type 0508 * 0509 * @param string $name 0510 * @return false|int 0511 */ 0512 protected function _getMarkupType($name) 0513 { 0514 if (!isset($this->_markups[$name])) { 0515 return false; 0516 } 0517 if (!isset($this->_markups[$name]['type'])) { 0518 return false; 0519 } 0520 return $this->_markups[$name]['type']; 0521 } 0522 0523 /** 0524 * Execute a replace token 0525 * 0526 * @param Zend_Markup_Token $token 0527 * @param array $tag 0528 * @return string 0529 */ 0530 protected function _executeReplace(Zend_Markup_Token $token, $tag) 0531 { 0532 return $tag['start'] . $this->_render($token) . $tag['end']; 0533 } 0534 0535 /** 0536 * Execute a single replace token 0537 * 0538 * @param Zend_Markup_Token $token 0539 * @param array $tag 0540 * @return string 0541 */ 0542 protected function _executeSingleReplace(Zend_Markup_Token $token, $tag) 0543 { 0544 return $tag['replace']; 0545 } 0546 0547 /** 0548 * Get the default filter 0549 * 0550 * @return void 0551 */ 0552 public function getDefaultFilter() 0553 { 0554 if (null === $this->_defaultFilter) { 0555 $this->addDefaultFilters(); 0556 } 0557 0558 return $this->_defaultFilter; 0559 } 0560 0561 /** 0562 * Add a default filter 0563 * 0564 * @param string $filter 0565 * 0566 * @return void 0567 */ 0568 public function addDefaultFilter(Zend_Filter_Interface $filter, $placement = Zend_Filter::CHAIN_APPEND) 0569 { 0570 if (!($this->_defaultFilter instanceof Zend_Filter)) { 0571 $defaultFilter = new Zend_Filter(); 0572 $defaultFilter->addFilter($filter); 0573 $this->_defaultFilter = $defaultFilter; 0574 } 0575 0576 $this->_defaultFilter->addFilter($filter, $placement); 0577 } 0578 0579 /** 0580 * Set the default filter 0581 * 0582 * @param Zend_Filter_Interface $filter 0583 * 0584 * @return void 0585 */ 0586 public function setDefaultFilter(Zend_Filter_Interface $filter) 0587 { 0588 $this->_defaultFilter = $filter; 0589 } 0590 0591 /** 0592 * Get the filter for an existing markup 0593 * 0594 * @param string $markup 0595 * 0596 * @return Zend_Filter_Interface 0597 */ 0598 public function getFilter($markup) 0599 { 0600 $markup = $this->_resolveMarkupName($markup); 0601 0602 if (!isset($this->_markups[$markup]['filter']) 0603 || !($this->_markups[$markup]['filter'] instanceof Zend_Filter_Interface) 0604 ) { 0605 if (isset($this->_markups[$markup]['filter']) && $this->_markups[$markup]['filter']) { 0606 $this->_markups[$markup]['filter'] = $this->getDefaultFilter(); 0607 } else { 0608 return false; 0609 } 0610 } 0611 0612 return $this->_markups[$markup]['filter']; 0613 } 0614 0615 /** 0616 * Add a filter for an existing markup 0617 * 0618 * @param Zend_Filter_Interface $filter 0619 * @param string $markup 0620 * @param string $placement 0621 * 0622 * @return Zend_Markup_Renderer_RendererAbstract 0623 */ 0624 public function addFilter(Zend_Filter_Interface $filter, $markup, $placement = Zend_Filter::CHAIN_APPEND) 0625 { 0626 $markup = $this->_resolveMarkupName($markup); 0627 0628 $oldFilter = $this->getFilter($markup); 0629 0630 // if this filter is the default filter, clone it first 0631 if ($oldFilter === $this->getDefaultFilter()) { 0632 $oldFilter = clone $oldFilter; 0633 } 0634 0635 if (!($oldFilter instanceof Zend_Filter)) { 0636 $this->_markups[$markup]['filter'] = new Zend_Filter(); 0637 0638 if ($oldFilter instanceof Zend_Filter_Interface) { 0639 $this->_markups[$markup]['filter']->addFilter($oldFilter); 0640 } 0641 } else { 0642 $this->_markups[$markup]['filter'] = $oldFilter; 0643 } 0644 0645 $this->_markups[$markup]['filter']->addFilter($filter, $placement); 0646 0647 return $this; 0648 } 0649 0650 /** 0651 * Set the filter for an existing 0652 * 0653 * @param Zend_Filter_Interface $filter 0654 * @param string $markup 0655 * 0656 * @return Zend_Markup_Renderer_RendererAbstract 0657 */ 0658 public function setFilter(Zend_Filter_Interface $filter, $markup) 0659 { 0660 $markup = $this->_resolveMarkupName($markup); 0661 0662 $this->_markups[$markup]['filter'] = $filter; 0663 0664 return $this; 0665 } 0666 0667 /** 0668 * Add a render group 0669 * 0670 * @param string $name 0671 * @param array $allowedInside 0672 * @param array $allowsInside 0673 * 0674 * @return void 0675 */ 0676 public function addGroup($name, array $allowedInside = array(), array $allowsInside = array()) 0677 { 0678 $this->_groups[$name] = $allowsInside; 0679 0680 foreach ($allowedInside as $group) { 0681 $this->_groups[$group][] = $name; 0682 } 0683 } 0684 0685 /** 0686 * Get group definitions 0687 * 0688 * @return array 0689 */ 0690 public function getGroups() 0691 { 0692 return $this->_groups; 0693 } 0694 0695 /** 0696 * Set the default filters 0697 * 0698 * @return void 0699 */ 0700 abstract public function addDefaultFilters(); 0701 0702 }