PageRenderTime 96ms CodeModel.GetById 8ms RepoModel.GetById 0ms app.codeStats 0ms

/web/vendor/latte/latte/src/Latte/Runtime/FilterExecutor.php

https://gitlab.com/adam.kvita/MI-VMM-SIFT
PHP | 190 lines | 140 code | 22 blank | 28 comment | 18 complexity | abc914fe3c25dbc5f8e94abd37316b9f MD5 | raw file
  1. <?php
  2. /**
  3. * This file is part of the Latte (https://latte.nette.org)
  4. * Copyright (c) 2008 David Grudl (https://davidgrudl.com)
  5. */
  6. namespace Latte\Runtime;
  7. use Latte\Engine;
  8. use Latte\Helpers;
  9. /**
  10. * Filter executor.
  11. * @internal
  12. */
  13. class FilterExecutor
  14. {
  15. /** @var array */
  16. private $_dynamic = [];
  17. /** @var array [name => [callback, FilterInfo aware] */
  18. private $_static = [
  19. 'breaklines' => ['Latte\Runtime\Filters::breaklines', FALSE],
  20. 'bytes' => ['Latte\Runtime\Filters::bytes', FALSE],
  21. 'capitalize' => ['Latte\Runtime\Filters::capitalize', FALSE],
  22. 'datastream' => ['Latte\Runtime\Filters::dataStream', FALSE],
  23. 'date' => ['Latte\Runtime\Filters::date', FALSE],
  24. 'escapecss' => ['Latte\Runtime\Filters::escapeCss', FALSE],
  25. 'escapehtml' => ['Latte\Runtime\Filters::escapeHtml', FALSE],
  26. 'escapehtmlcomment' => ['Latte\Runtime\Filters::escapeHtmlComment', FALSE],
  27. 'escapeical' => ['Latte\Runtime\Filters::escapeICal', FALSE],
  28. 'escapejs' => ['Latte\Runtime\Filters::escapeJs', FALSE],
  29. 'escapeurl' => ['rawurlencode', FALSE],
  30. 'escapexml' => ['Latte\Runtime\Filters::escapeXml', FALSE],
  31. 'firstupper' => ['Latte\Runtime\Filters::firstUpper', FALSE],
  32. 'checkurl' => ['Latte\Runtime\Filters::safeUrl', FALSE],
  33. 'implode' => ['implode', FALSE],
  34. 'indent' => ['Latte\Runtime\Filters::indent', TRUE],
  35. 'length' => ['Latte\Runtime\Filters::length', FALSE],
  36. 'lower' => ['Latte\Runtime\Filters::lower', FALSE],
  37. 'nl2br' => ['Latte\Runtime\Filters::nl2br', FALSE],
  38. 'number' => ['number_format', FALSE],
  39. 'repeat' => ['Latte\Runtime\Filters::repeat', TRUE],
  40. 'replace' => ['Latte\Runtime\Filters::replace', TRUE],
  41. 'replacere' => ['Latte\Runtime\Filters::replaceRe', FALSE],
  42. 'safeurl' => ['Latte\Runtime\Filters::safeUrl', FALSE],
  43. 'strip' => ['Latte\Runtime\Filters::strip', TRUE],
  44. 'striphtml' => ['Latte\Runtime\Filters::stripHtml', TRUE],
  45. 'striptags' => ['Latte\Runtime\Filters::stripTags', TRUE],
  46. 'substr' => ['Latte\Runtime\Filters::substring', FALSE],
  47. 'trim' => ['Latte\Runtime\Filters::trim', FALSE],
  48. 'truncate' => ['Latte\Runtime\Filters::truncate', FALSE],
  49. 'upper' => ['Latte\Runtime\Filters::upper', FALSE],
  50. ];
  51. /**
  52. * Registers run-time filter.
  53. * @param string|NULL
  54. * @param callable
  55. * @return self
  56. */
  57. public function add($name, $callback)
  58. {
  59. if ($name == NULL) { // intentionally ==
  60. array_unshift($this->_dynamic, $callback);
  61. } else {
  62. $name = strtolower($name);
  63. $this->_static[$name] = [$callback, NULL];
  64. unset($this->$name);
  65. }
  66. return $this;
  67. }
  68. /**
  69. * Returns all run-time filters.
  70. * @return string[]
  71. */
  72. public function getAll()
  73. {
  74. return array_combine($tmp = array_keys($this->_static), $tmp);
  75. }
  76. /**
  77. * Returns filter for classic calling.
  78. * @return callable
  79. */
  80. public function __get($name)
  81. {
  82. $lname = strtolower($name);
  83. if (isset($this->$lname)) { // case mismatch
  84. return $this->$lname;
  85. } elseif (isset($this->_static[$lname])) {
  86. list($callback, $aware) = $this->prepareFilter($lname);
  87. if ($aware) { // FilterInfo aware filter
  88. return $this->$lname = function ($arg) use ($callback) {
  89. $args = func_get_args();
  90. array_unshift($args, $info = new FilterInfo);
  91. if ($arg instanceof IHtmlString) {
  92. $args[1] = $arg->__toString();
  93. $info->contentType = Engine::CONTENT_HTML;
  94. }
  95. $res = call_user_func_array($callback, $args);
  96. return $info->contentType === Engine::CONTENT_HTML
  97. ? new Html($res)
  98. : $res;
  99. };
  100. } else { // classic filter
  101. return $this->$lname = $callback;
  102. }
  103. }
  104. return $this->$lname = function ($arg) use ($lname, $name) { // dynamic filter
  105. $args = func_get_args();
  106. array_unshift($args, $lname);
  107. foreach ($this->_dynamic as $filter) {
  108. $res = call_user_func_array(Helpers::checkCallback($filter), $args);
  109. if ($res !== NULL) {
  110. return $res;
  111. } elseif (isset($this->_static[$lname])) { // dynamic converted to classic
  112. $this->$name = Helpers::checkCallback($this->_static[$lname][0]);
  113. return call_user_func_array($this->$name, func_get_args());
  114. }
  115. }
  116. $hint = ($t = Helpers::getSuggestion(array_keys($this->_static), $name)) ? ", did you mean '$t'?" : '.';
  117. throw new \LogicException("Filter '$name' is not defined$hint");
  118. };
  119. }
  120. /**
  121. * Calls filter with FilterInfo.
  122. * @return mixed
  123. */
  124. public function filterContent($name, FilterInfo $info, $arg)
  125. {
  126. $lname = strtolower($name);
  127. $args = func_get_args();
  128. array_shift($args);
  129. if (!isset($this->_static[$lname])) {
  130. $hint = ($t = Helpers::getSuggestion(array_keys($this->_static), $name)) ? ", did you mean '$t'?" : '.';
  131. throw new \LogicException("Filter |$name is not defined$hint");
  132. }
  133. list($callback, $aware) = $this->prepareFilter($lname);
  134. if ($aware) { // FilterInfo aware filter
  135. return call_user_func_array($callback, $args);
  136. } else { // classic filter
  137. array_shift($args);
  138. if ($info->contentType !== Engine::CONTENT_TEXT) {
  139. trigger_error("Filter |$name is called with incompatible content type " . strtoupper($info->contentType)
  140. . ($info->contentType === Engine::CONTENT_HTML ? ', try to prepend |stripHtml.' : '.'), E_USER_WARNING);
  141. }
  142. $res = call_user_func_array($this->$name, $args);
  143. if ($res instanceof IHtmlString) {
  144. trigger_error("Filter |$name should be changed to content-aware filter.");
  145. $info->contentType = Engine::CONTENT_HTML;
  146. $res = $res->__toString();
  147. }
  148. return $res;
  149. }
  150. }
  151. private function prepareFilter($name)
  152. {
  153. if (!isset($this->_static[$name][1])) {
  154. $callback = Helpers::checkCallback($this->_static[$name][0]);
  155. if (is_string($callback) && strpos($callback, '::')) {
  156. $callback = explode('::', $callback);
  157. } elseif (is_object($callback)) {
  158. $callback = [$callback, '__invoke'];
  159. }
  160. $ref = is_array($callback)
  161. ? new \ReflectionMethod($callback[0], $callback[1])
  162. : new \ReflectionFunction($callback);
  163. $this->_static[$name][1] = ($tmp = $ref->getParameters())
  164. && $tmp[0]->getClass() && $tmp[0]->getClass()->getName() === 'Latte\Runtime\FilterInfo';
  165. }
  166. return $this->_static[$name];
  167. }
  168. }