Helper.php 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. <?php
  2. /**
  3. * Lithium: the most rad php framework
  4. *
  5. * @copyright Copyright 2013, Union of RAD (http://union-of-rad.org)
  6. * @license http://opensource.org/licenses/bsd-license.php The BSD License
  7. */
  8. namespace lithium\template;
  9. use lithium\util\String;
  10. /**
  11. * Abstract class for template helpers to extend.
  12. * Supplies the basic functionality of _render and _options,
  13. * as well as escaping.
  14. *
  15. */
  16. abstract class Helper extends \lithium\core\Object {
  17. /**
  18. * Maps helper method names to content types as defined by the `Media` class, where key are
  19. * method names, and values are the content type that the method name outputs a link to.
  20. *
  21. * @var array
  22. */
  23. public $contentMap = array();
  24. /**
  25. * Holds string templates which will be merged into the rendering context.
  26. *
  27. * @var array
  28. */
  29. protected $_strings = array();
  30. /**
  31. * The Renderer object this Helper is bound to.
  32. *
  33. * @var lithium\template\view\Renderer
  34. * @see lithium\template\view\Renderer
  35. */
  36. protected $_context = null;
  37. /**
  38. * This property can be overwritten with any class dependencies a helper subclass has.
  39. *
  40. * @var array
  41. */
  42. protected $_classes = array();
  43. /**
  44. * Auto configuration properties.
  45. *
  46. * @var array
  47. */
  48. protected $_autoConfig = array('classes' => 'merge', 'context');
  49. /**
  50. * List of minimized HTML attributes.
  51. *
  52. * @var array
  53. */
  54. protected $_minimized = array(
  55. 'compact', 'checked', 'declare', 'readonly', 'disabled', 'selected', 'defer', 'ismap',
  56. 'nohref', 'noshade', 'nowrap', 'multiple', 'noresize', 'async', 'autofocus'
  57. );
  58. public function __construct(array $config = array()) {
  59. $defaults = array('handlers' => array(), 'context' => null);
  60. parent::__construct($config + $defaults);
  61. }
  62. /**
  63. * Imports local string definitions into rendering context.
  64. *
  65. * @return void
  66. */
  67. protected function _init() {
  68. parent::_init();
  69. if (!$this->_context) {
  70. return;
  71. }
  72. $this->_context->strings($this->_strings);
  73. if ($this->_config['handlers']) {
  74. $this->_context->handlers($this->_config['handlers']);
  75. }
  76. }
  77. /**
  78. * Escapes values according to the output type of the rendering context. Helpers that output to
  79. * non-HTML/XML contexts should override this method accordingly.
  80. *
  81. * @param string $value
  82. * @param mixed $method
  83. * @param array $options
  84. * @return mixed
  85. */
  86. public function escape($value, $method = null, array $options = array()) {
  87. $defaults = array('escape' => true);
  88. $options += $defaults;
  89. if ($options['escape'] === false) {
  90. return $value;
  91. }
  92. if (is_array($value)) {
  93. return array_map(array($this, __FUNCTION__), $value);
  94. }
  95. return htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
  96. }
  97. /**
  98. * Takes the defaults and current options, merges them and returns options which have
  99. * the default keys removed and full set of options as the scope.
  100. *
  101. * @param array $defaults
  102. * @param array $scope the complete set of options
  103. * @return array $scope, $options
  104. */
  105. protected function _options(array $defaults, array $scope) {
  106. $scope += $defaults;
  107. $options = array_diff_key($scope, $defaults);
  108. return array($scope, $options);
  109. }
  110. /**
  111. * Render a string template after applying context filters
  112. * Use examples in the Html::link() method:
  113. * `return $this->_render(__METHOD__, 'link', compact('title', 'url', 'options'), $scope);`
  114. *
  115. * @param string $method name of method that is calling the render (for context filters)
  116. * @param string $string template key (in Helper::_strings) to render
  117. * @param array $params associated array of template inserts {:key} will be replaced by value
  118. * @param array $options Available options:
  119. * - `'handlers'` _array_: Before inserting `$params` inside the string template,
  120. * `$this->_context`'s handlers are applied to each value of `$params` according
  121. * to the key (e.g `$params['url']`, which is processed by the `'url'` handler
  122. * via `$this->_context->applyHandler()`).
  123. * The `'handlers'` option allow to set custom mapping beetween `$params`'s key and
  124. * `$this->_context`'s handlers. e.g. the following handler:
  125. * `'handlers' => array('url' => 'path')` will make `$params['url']` to be
  126. * processed by the `'path'` handler instead of the `'url'` one.
  127. * @return string Rendered HTML
  128. */
  129. protected function _render($method, $string, $params, array $options = array()) {
  130. $strings = $this->_strings;
  131. if ($this->_context) {
  132. foreach ($params as $key => $value) {
  133. $handler = isset($options['handlers'][$key]) ? $options['handlers'][$key] : $key;
  134. $params[$key] = $this->_context->applyHandler(
  135. $this, $method, $handler, $value, $options
  136. );
  137. }
  138. $strings = $this->_context->strings();
  139. }
  140. return String::insert(isset($strings[$string]) ? $strings[$string] : $string, $params);
  141. }
  142. /**
  143. * Convert a set of options to HTML attributes
  144. *
  145. * @param array $params
  146. * @param string $method
  147. * @param array $options
  148. * @return string
  149. */
  150. protected function _attributes($params, $method = null, array $options = array()) {
  151. $defaults = array('escape' => true, 'prepend' => ' ', 'append' => '');
  152. $options += $defaults;
  153. $result = array();
  154. if (!is_array($params)) {
  155. return !$params ? '' : $options['prepend'] . $params;
  156. }
  157. foreach ($params as $key => $value) {
  158. if ($next = $this->_attribute($key, $value, $options)) {
  159. $result[] = $next;
  160. }
  161. }
  162. return $result ? $options['prepend'] . implode(' ', $result) . $options['append'] : '';
  163. }
  164. /**
  165. * Convert a key/value pair to a valid HTML attribute.
  166. *
  167. * @param string $key The key name of the HTML attribute.
  168. * @param mixed $value The HTML attribute value.
  169. * @param array $options The options used when converting the key/value pair to attributes:
  170. * - `'escape'` _boolean_: Indicates whether `$key` and `$value` should be
  171. * HTML-escaped. Defaults to `true`.
  172. * - `'format'` _string_: The format string. Defaults to `'%s="%s"'`.
  173. * @return string Returns an HTML attribute/value pair, in the form of `'$key="$value"'`.
  174. */
  175. protected function _attribute($key, $value, array $options = array()) {
  176. $defaults = array('escape' => true, 'format' => '%s="%s"');
  177. $options += $defaults;
  178. if (in_array($key, $this->_minimized)) {
  179. $isMini = ($value == 1 || $value === true || $value == $key);
  180. if (!($value = $isMini ? $key : $value)) {
  181. return null;
  182. }
  183. }
  184. $value = (string) $value;
  185. if ($options['escape']) {
  186. return sprintf($options['format'], $this->escape($key), $this->escape($value));
  187. }
  188. return sprintf($options['format'], $key, $value);
  189. }
  190. }
  191. ?>