StringTemplate.php 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  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 an 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. $loader = new PhpConfig(APP . 'Config/');
  68. $templates = $loader->read($file);
  69. $this->add($templates);
  70. }
  71. /**
  72. * Add one or more template strings.
  73. *
  74. * @param array $templates The templates to add.
  75. * @return void
  76. */
  77. public function add(array $templates) {
  78. $this->_templates = array_merge($this->_templates, $templates);
  79. }
  80. /**
  81. * Get one or all templates.
  82. *
  83. * @param string $name Leave null to get all templates, provide a name to get a single template.
  84. * @return string|array|null Either the template(s) or null
  85. */
  86. public function get($name = null) {
  87. if ($name === null) {
  88. return $this->_templates;
  89. }
  90. if (!isset($this->_templates[$name])) {
  91. return null;
  92. }
  93. return $this->_templates[$name];
  94. }
  95. /**
  96. * Remove the named template.
  97. *
  98. * @param string $name The template to remove.
  99. * @return void
  100. */
  101. public function remove($name) {
  102. unset($this->_templates[$name]);
  103. }
  104. /**
  105. * Format a template string with $data
  106. *
  107. * @param string $name The template name.
  108. * @param array $data The data to insert.
  109. * @return string
  110. */
  111. public function format($name, array $data) {
  112. $template = $this->get($name);
  113. if ($template === null) {
  114. return '';
  115. }
  116. $replace = [];
  117. $keys = array_keys($data);
  118. foreach ($keys as $key) {
  119. $replace['{{' . $key . '}}'] = $data[$key];
  120. }
  121. return strtr($template, $replace);
  122. }
  123. /**
  124. * Returns a space-delimited string with items of the $options array. If a key
  125. * of $options array happens to be one of those listed
  126. * in `StringTemplate::$_compactAttributes` and its value is one of:
  127. *
  128. * - '1' (string)
  129. * - 1 (integer)
  130. * - true (boolean)
  131. * - 'true' (string)
  132. *
  133. * Then the value will be reset to be identical with key's name.
  134. * If the value is not one of these 4, the parameter is not output.
  135. *
  136. * 'escape' is a special option in that it controls the conversion of
  137. * attributes to their html-entity encoded equivalents. Set to false to disable html-encoding.
  138. *
  139. * If value for any option key is set to `null` or `false`, that option will be excluded from output.
  140. *
  141. * This method uses the 'attribute' and 'compactAttribute' templates. Each of
  142. * these templates uses the `name` and `value` variables. You can modify these
  143. * templates to change how attributes are formatted.
  144. *
  145. * @param array $options Array of options.
  146. * @param null|array $exclude Array of options to be excluded, the options here will not be part of the return.
  147. * @return string Composed attributes.
  148. */
  149. public function formatAttributes($options, $exclude = null) {
  150. $insertBefore = ' ';
  151. $options = (array)$options + ['escape' => true];
  152. if (!is_array($exclude)) {
  153. $exclude = [];
  154. }
  155. $exclude = ['escape' => true, 'idPrefix' => true] + array_flip($exclude);
  156. $escape = $options['escape'];
  157. $attributes = [];
  158. foreach ($options as $key => $value) {
  159. if (!isset($exclude[$key]) && $value !== false && $value !== null) {
  160. $attributes[] = $this->_formatAttribute($key, $value, $escape);
  161. }
  162. }
  163. $out = trim(implode(' ', $attributes));
  164. return $out ? $insertBefore . $out : '';
  165. }
  166. /**
  167. * Formats an individual attribute, and returns the string value of the composed attribute.
  168. * Works with minimized attributes that have the same value as their name such as 'disabled' and 'checked'
  169. *
  170. * @param string $key The name of the attribute to create
  171. * @param string $value The value of the attribute to create.
  172. * @param boolean $escape Define if the value must be escaped
  173. * @return string The composed attribute.
  174. */
  175. protected function _formatAttribute($key, $value, $escape = true) {
  176. if (is_array($value)) {
  177. $value = implode(' ', $value);
  178. }
  179. if (is_numeric($key)) {
  180. return $this->format('compactAttribute', [
  181. 'name' => $value,
  182. 'value' => $value
  183. ]);
  184. }
  185. $truthy = [1, '1', true, 'true', $key];
  186. $isMinimized = in_array($key, $this->_compactAttributes);
  187. if ($isMinimized && in_array($value, $truthy, true)) {
  188. return $this->format('compactAttribute', [
  189. 'name' => $key,
  190. 'value' => $key
  191. ]);
  192. }
  193. if ($isMinimized) {
  194. return '';
  195. }
  196. return $this->format('attribute', [
  197. 'name' => $key,
  198. 'value' => $escape ? h($value) : $value
  199. ]);
  200. }
  201. }