PageRenderTime 47ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/src/View/StringTemplate.php

https://github.com/ceeram/cakephp
PHP | 294 lines | 139 code | 21 blank | 134 comment | 14 complexity | 30b40104d850ff187b3082b6efc097be MD5 | raw file
  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 3.0.0
  13. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\View;
  16. use Cake\Core\Configure\Engine\PhpConfig;
  17. use Cake\Core\InstanceConfigTrait;
  18. /**
  19. * Provides an interface for registering and inserting
  20. * content into simple logic-less string templates.
  21. *
  22. * Used by several helpers to provide simple flexible templates
  23. * for generating HTML and other content.
  24. */
  25. class StringTemplate
  26. {
  27. use InstanceConfigTrait {
  28. config as get;
  29. }
  30. /**
  31. * List of attributes that can be made compact.
  32. *
  33. * @var array
  34. */
  35. protected $_compactAttributes = [
  36. 'compact' => true,
  37. 'checked' => true,
  38. 'declare' => true,
  39. 'readonly' => true,
  40. 'disabled' => true,
  41. 'selected' => true,
  42. 'defer' => true,
  43. 'ismap' => true,
  44. 'nohref' => true,
  45. 'noshade' => true,
  46. 'nowrap' => true,
  47. 'multiple' => true,
  48. 'noresize' => true,
  49. 'autoplay' => true,
  50. 'controls' => true,
  51. 'loop' => true,
  52. 'muted' => true,
  53. 'required' => true,
  54. 'novalidate' => true,
  55. 'formnovalidate' => true,
  56. ];
  57. /**
  58. * The default templates this instance holds.
  59. *
  60. * @var array
  61. */
  62. protected $_defaultConfig = [
  63. ];
  64. /**
  65. * A stack of template sets that have been stashed temporarily.
  66. *
  67. * @var array
  68. */
  69. protected $_configStack = [];
  70. /**
  71. * Contains the list of compiled templates
  72. *
  73. * @var array
  74. */
  75. protected $_compiled = [];
  76. /**
  77. * Constructor.
  78. *
  79. * @param array $config A set of templates to add.
  80. */
  81. public function __construct(array $config = [])
  82. {
  83. $this->add($config);
  84. }
  85. /**
  86. * Push the current templates into the template stack.
  87. *
  88. * @return void
  89. */
  90. public function push()
  91. {
  92. $this->_configStack[] = [
  93. $this->_config,
  94. $this->_compiled
  95. ];
  96. }
  97. /**
  98. * Restore the most recently pushed set of templates.
  99. *
  100. * @return void
  101. */
  102. public function pop()
  103. {
  104. if (empty($this->_configStack)) {
  105. return;
  106. }
  107. list($this->_config, $this->_compiled) = array_pop($this->_configStack);
  108. }
  109. /**
  110. * Registers a list of templates by name
  111. *
  112. * ### Example:
  113. *
  114. * ```
  115. * $templater->add([
  116. * 'link' => '<a href="{{url}}">{{title}}</a>'
  117. * 'button' => '<button>{{text}}</button>'
  118. * ]);
  119. * ```
  120. *
  121. * @param array $templates An associative list of named templates.
  122. * @return $this
  123. */
  124. public function add(array $templates)
  125. {
  126. $this->config($templates);
  127. $this->_compileTemplates(array_keys($templates));
  128. return $this;
  129. }
  130. /**
  131. * Compile templates into a more efficient printf() compatible format.
  132. *
  133. * @param array $templates The template names to compile. If empty all templates will be compiled.
  134. * @return void
  135. */
  136. protected function _compileTemplates(array $templates = [])
  137. {
  138. if (empty($templates)) {
  139. $templates = array_keys($this->_config);
  140. }
  141. foreach ($templates as $name) {
  142. $template = $this->get($name);
  143. if ($template === null) {
  144. $this->_compiled[$name] = [null, null];
  145. }
  146. preg_match_all('#\{\{(\w+)\}\}#', $template, $matches);
  147. $this->_compiled[$name] = [
  148. str_replace($matches[0], '%s', $template),
  149. $matches[1]
  150. ];
  151. }
  152. }
  153. /**
  154. * Load a config file containing templates.
  155. *
  156. * Template files should define a `$config` variable containing
  157. * all the templates to load. Loaded templates will be merged with existing
  158. * templates.
  159. *
  160. * @param string $file The file to load
  161. * @return void
  162. */
  163. public function load($file)
  164. {
  165. $loader = new PhpConfig();
  166. $templates = $loader->read($file);
  167. $this->add($templates);
  168. }
  169. /**
  170. * Remove the named template.
  171. *
  172. * @param string $name The template to remove.
  173. * @return void
  174. */
  175. public function remove($name)
  176. {
  177. $this->config($name, null);
  178. unset($this->_compiled[$name]);
  179. }
  180. /**
  181. * Format a template string with $data
  182. *
  183. * @param string $name The template name.
  184. * @param array $data The data to insert.
  185. * @return string
  186. */
  187. public function format($name, array $data)
  188. {
  189. if (!isset($this->_compiled[$name])) {
  190. return '';
  191. }
  192. list($template, $placeholders) = $this->_compiled[$name];
  193. if ($template === null) {
  194. return '';
  195. }
  196. $replace = [];
  197. foreach ($placeholders as $placeholder) {
  198. $replace[] = isset($data[$placeholder]) ? $data[$placeholder] : null;
  199. }
  200. return vsprintf($template, $replace);
  201. }
  202. /**
  203. * Returns a space-delimited string with items of the $options array. If a key
  204. * of $options array happens to be one of those listed
  205. * in `StringTemplate::$_compactAttributes` and its value is one of:
  206. *
  207. * - '1' (string)
  208. * - 1 (integer)
  209. * - true (boolean)
  210. * - 'true' (string)
  211. *
  212. * Then the value will be reset to be identical with key's name.
  213. * If the value is not one of these 4, the parameter is not output.
  214. *
  215. * 'escape' is a special option in that it controls the conversion of
  216. * attributes to their HTML-entity encoded equivalents. Set to false to disable HTML-encoding.
  217. *
  218. * If value for any option key is set to `null` or `false`, that option will be excluded from output.
  219. *
  220. * This method uses the 'attribute' and 'compactAttribute' templates. Each of
  221. * these templates uses the `name` and `value` variables. You can modify these
  222. * templates to change how attributes are formatted.
  223. *
  224. * @param array|null $options Array of options.
  225. * @param array|null $exclude Array of options to be excluded, the options here will not be part of the return.
  226. * @return string Composed attributes.
  227. */
  228. public function formatAttributes($options, $exclude = null)
  229. {
  230. $insertBefore = ' ';
  231. $options = (array)$options + ['escape' => true];
  232. if (!is_array($exclude)) {
  233. $exclude = [];
  234. }
  235. $exclude = ['escape' => true, 'idPrefix' => true] + array_flip($exclude);
  236. $escape = $options['escape'];
  237. $attributes = [];
  238. foreach ($options as $key => $value) {
  239. if (!isset($exclude[$key]) && $value !== false && $value !== null) {
  240. $attributes[] = $this->_formatAttribute($key, $value, $escape);
  241. }
  242. }
  243. $out = trim(implode(' ', $attributes));
  244. return $out ? $insertBefore . $out : '';
  245. }
  246. /**
  247. * Formats an individual attribute, and returns the string value of the composed attribute.
  248. * Works with minimized attributes that have the same value as their name such as 'disabled' and 'checked'
  249. *
  250. * @param string $key The name of the attribute to create
  251. * @param string|array $value The value of the attribute to create.
  252. * @param bool $escape Define if the value must be escaped
  253. * @return string The composed attribute.
  254. */
  255. protected function _formatAttribute($key, $value, $escape = true)
  256. {
  257. if (is_array($value)) {
  258. $value = implode(' ', $value);
  259. }
  260. if (is_numeric($key)) {
  261. return "$value=\"$value\"";
  262. }
  263. $truthy = [1, '1', true, 'true', $key];
  264. $isMinimized = isset($this->_compactAttributes[$key]);
  265. if ($isMinimized && in_array($value, $truthy, true)) {
  266. return "$key=\"$key\"";
  267. }
  268. if ($isMinimized) {
  269. return '';
  270. }
  271. return $key . '="' . ($escape ? h($value) : $value) . '"';
  272. }
  273. }