StringTemplate.php 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * For full copyright and license information, please see the LICENSE.txt
  8. * Redistributions of files must retain the above copyright notice.
  9. *
  10. * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  11. * @link http://cakephp.org CakePHP(tm) Project
  12. * @since CakePHP(tm) v3.0
  13. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\View;
  16. use Cake\Configure\Engine\PhpConfig;
  17. use Cake\Core\Plugin;
  18. use Cake\Error;
  19. /**
  20. * Provides a interface for registering and inserting
  21. * content into simple logic-less string templates.
  22. *
  23. * Used by several helpers to provide simple flexible templates
  24. * for generating HTML and other content.
  25. */
  26. class StringTemplate {
  27. /**
  28. * List of attributes that can be made compact.
  29. *
  30. * @var array
  31. */
  32. protected $_compactAttributes = array(
  33. 'compact', 'checked', 'declare', 'readonly', 'disabled', 'selected',
  34. 'defer', 'ismap', 'nohref', 'noshade', 'nowrap', 'multiple', 'noresize',
  35. 'autoplay', 'controls', 'loop', 'muted', 'required', 'novalidate', 'formnovalidate'
  36. );
  37. /**
  38. * The templates this instance holds.
  39. *
  40. * @var array
  41. */
  42. protected $_templates = [
  43. 'attribute' => '{{name}}="{{value}}"',
  44. 'compactAttribute' => '{{name}}="{{value}}"',
  45. ];
  46. /**
  47. * Constructor.
  48. *
  49. * @param array $templates A set of templates to add.
  50. */
  51. public function __construct(array $templates = null) {
  52. if ($templates) {
  53. $this->add($templates);
  54. }
  55. }
  56. /**
  57. * Load a config file containing templates.
  58. *
  59. * Template files should define a `$config` variable containing
  60. * all the templates to load. Loaded templates will be merged with existing
  61. * templates.
  62. *
  63. * @param string $file The file to load
  64. * @return void
  65. */
  66. public function load($file) {
  67. list($plugin, $file) = pluginSplit($file);
  68. $path = APP . 'Config/';
  69. if ($plugin !== null) {
  70. $path = Plugin::path($plugin) . 'Config/';
  71. }
  72. $loader = new PhpConfig($path);
  73. $templates = $loader->read($file);
  74. $this->add($templates);
  75. }
  76. /**
  77. * Add one or more template strings.
  78. *
  79. * @param array $templates The templates to add.
  80. * @return void
  81. */
  82. public function add(array $templates) {
  83. $this->_templates = array_merge($this->_templates, $templates);
  84. }
  85. /**
  86. * Get one or all templates.
  87. *
  88. * @param string $name Leave null to get all templates, provide a name to get a single template.
  89. * @return string|array|null Either the template(s) or null
  90. */
  91. public function get($name = null) {
  92. if ($name === null) {
  93. return $this->_templates;
  94. }
  95. if (!isset($this->_templates[$name])) {
  96. return null;
  97. }
  98. return $this->_templates[$name];
  99. }
  100. /**
  101. * Remove the named template.
  102. *
  103. * @param string $name The template to remove.
  104. * @return void
  105. */
  106. public function remove($name) {
  107. unset($this->_templates[$name]);
  108. }
  109. /**
  110. * Format a template string with $data
  111. *
  112. * @param string $name The template name.
  113. * @param array $data The data to insert.
  114. * @return string
  115. */
  116. public function format($name, array $data) {
  117. $template = $this->get($name);
  118. if ($template === null) {
  119. return '';
  120. }
  121. $replace = [];
  122. $keys = array_keys($data);
  123. foreach ($keys as $key) {
  124. $replace['{{' . $key . '}}'] = $data[$key];
  125. }
  126. return strtr($template, $replace);
  127. }
  128. /**
  129. * Returns a space-delimited string with items of the $options array. If a key
  130. * of $options array happens to be one of those listed
  131. * in `StringTemplate::$_compactAttributes` and its value is one of:
  132. *
  133. * - '1' (string)
  134. * - 1 (integer)
  135. * - true (boolean)
  136. * - 'true' (string)
  137. *
  138. * Then the value will be reset to be identical with key's name.
  139. * If the value is not one of these 4, the parameter is not output.
  140. *
  141. * 'escape' is a special option in that it controls the conversion of
  142. * attributes to their html-entity encoded equivalents. Set to false to disable html-encoding.
  143. *
  144. * If value for any option key is set to `null` or `false`, that option will be excluded from output.
  145. *
  146. * This method uses the 'attribute' and 'compactAttribute' templates. Each of
  147. * these templates uses the `name` and `value` variables. You can modify these
  148. * templates to change how attributes are formatted.
  149. *
  150. * @param array $options Array of options.
  151. * @param null|array $exclude Array of options to be excluded, the options here will not be part of the return.
  152. * @return string Composed attributes.
  153. */
  154. public function formatAttributes($options, $exclude = null) {
  155. $insertBefore = ' ';
  156. $options = (array)$options + ['escape' => true];
  157. if (!is_array($exclude)) {
  158. $exclude = [];
  159. }
  160. $exclude = ['escape' => true] + array_flip($exclude);
  161. $escape = $options['escape'];
  162. $attributes = [];
  163. foreach ($options as $key => $value) {
  164. if (!isset($exclude[$key]) && $value !== false && $value !== null) {
  165. $attributes[] = $this->_formatAttribute($key, $value, $escape);
  166. }
  167. }
  168. $out = trim(implode(' ', $attributes));
  169. return $out ? $insertBefore . $out : '';
  170. }
  171. /**
  172. * Formats an individual attribute, and returns the string value of the composed attribute.
  173. * Works with minimized attributes that have the same value as their name such as 'disabled' and 'checked'
  174. *
  175. * @param string $key The name of the attribute to create
  176. * @param string $value The value of the attribute to create.
  177. * @param boolean $escape Define if the value must be escaped
  178. * @return string The composed attribute.
  179. */
  180. protected function _formatAttribute($key, $value, $escape = true) {
  181. if (is_array($value)) {
  182. $value = implode(' ', $value);
  183. }
  184. if (is_numeric($key)) {
  185. return $this->format('compactAttribute', [
  186. 'name' => $value,
  187. 'value' => $value
  188. ]);
  189. }
  190. $truthy = [1, '1', true, 'true', $key];
  191. $isMinimized = in_array($key, $this->_compactAttributes);
  192. if ($isMinimized && in_array($value, $truthy, true)) {
  193. return $this->format('compactAttribute', [
  194. 'name' => $key,
  195. 'value' => $key
  196. ]);
  197. }
  198. if ($isMinimized) {
  199. return '';
  200. }
  201. return $this->format('attribute', [
  202. 'name' => $key,
  203. 'value' => $escape ? h($value) : $value
  204. ]);
  205. }
  206. }