PageRenderTime 49ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Templating/Twig/Extension/Definition/OptionsDefinition.php

https://gitlab.com/src-run/mantle-bundle
PHP | 297 lines | 132 code | 39 blank | 126 comment | 6 complexity | 6782cdc5fe22325d7782f7b310d85c24 MD5 | raw file
  1. <?php
  2. /*
  3. * This file is part of the Scribe Mantle Bundle.
  4. *
  5. * (c) Scribe Inc. <source@scribe.software>
  6. *
  7. * For the full copyright and license information, please view the LICENSE.md
  8. * file that was distributed with this source code.
  9. */
  10. namespace Scribe\MantleBundle\Templating\Twig\Extension\Options;
  11. /**
  12. * Class OptionsDefinition.
  13. */
  14. abstract class OptionsDefinition implements OptionsDefinitionInterface
  15. {
  16. /**
  17. * Options that are globally applied to all filters and functions for this extension.
  18. *
  19. * @var array[]
  20. */
  21. private $optionCollection = [];
  22. /**
  23. * @param array $optionCollection
  24. */
  25. public function __construct(array $optionCollection = [])
  26. {
  27. if (is_iterable_not_empty($optionCollection)) {
  28. $this->setOptionCollection($optionCollection);
  29. }
  30. }
  31. /**
  32. * @return $this
  33. */
  34. public function clearOptions()
  35. {
  36. $this->optionCollection = [];
  37. return $this;
  38. }
  39. /**
  40. * @param array $option
  41. *
  42. * @return $this
  43. */
  44. public function setOption($option)
  45. {
  46. return $this->setOptionCollection([$option]);
  47. }
  48. /**
  49. * @param array[] $optionCollection
  50. *
  51. * @return $this
  52. */
  53. public function setOptionCollection(array ...$optionCollection)
  54. {
  55. return $this
  56. ->clearOptions()
  57. ->stackOptions($optionCollection);
  58. }
  59. /**
  60. * @param array $option
  61. *
  62. * @return $this
  63. */
  64. public function addOption($option)
  65. {
  66. return $this->addOptionCollection([$option]);
  67. }
  68. /**
  69. * @param array[] $optionCollection
  70. *
  71. * @return $this
  72. */
  73. public function addOptionCollection(array ...$optionCollection)
  74. {
  75. return $this->stackOptions($optionCollection);
  76. }
  77. /**
  78. * @return $this
  79. */
  80. public function enableOptionNeedsEnv()
  81. {
  82. $this->addOptionCollection(['needs_environment' => true]);
  83. return $this;
  84. }
  85. /**
  86. * Sets the option that allows for HTML to be returned from the extension function.
  87. *
  88. * @return $this
  89. */
  90. public function enableOptionHtmlSafe()
  91. {
  92. $this->addOptionCollection(['is_safe' => ['html']]);
  93. return $this;
  94. }
  95. /**
  96. * @param array $optionCollection
  97. *
  98. * @return $this
  99. */
  100. protected function stackOptions(array $optionCollection)
  101. {
  102. foreach ($optionCollection as $option) {
  103. if (isEmptyIterable($option)) {
  104. continue;
  105. }
  106. $this->optionCollection[(string) key($option)] = current($option);
  107. }
  108. return $this;
  109. }
  110. /**
  111. * @param string $type
  112. * @param string $name
  113. *
  114. * @return array|\array[]
  115. */
  116. private function resolvedOptions($type, $name)
  117. {
  118. $optionCollection = $this->optionCollection;
  119. $typeOptionCollectionName = $type.self::PROPERTY_PART_OPTION;
  120. if (array_key_exists($name, $this->functionCallableCollection)) {
  121. $optionCollection = array_merge(
  122. $optionCollection,
  123. $this->{$typeOptionCollectionName}[$name]
  124. );
  125. }
  126. return $optionCollection;
  127. }
  128. /**
  129. * Add a Twig function to this extension.
  130. *
  131. * @param string $name
  132. * @param callable $method
  133. * @param array $optionCollection
  134. *
  135. * @return $this
  136. */
  137. public function addFunction($name, callable $method, array $optionCollection = [])
  138. {
  139. return $this
  140. ->stackCallable(__FUNCTION__, $name, $method, $optionCollection);
  141. }
  142. /**
  143. * Add a Twig filter to this extension.
  144. *
  145. * @param string $name
  146. * @param callable $method
  147. * @param array $optionCollection
  148. *
  149. * @return $this
  150. */
  151. public function addFilter($name, callable $method, array $optionCollection = [])
  152. {
  153. return $this
  154. ->stackCallable(__FUNCTION__, $name, $method, $optionCollection);
  155. }
  156. /**
  157. * Internal common implementation for {@see addFunction()} and {@see addFilter()}.
  158. *
  159. * @param string $type
  160. * @param string $name
  161. * @param callable $method
  162. * @param array $optionCollection
  163. *
  164. * @return $this
  165. */
  166. private function stackCallable($type, $name, callable $method, array $optionCollection)
  167. {
  168. $this
  169. ->validateName($name)
  170. ->validateType($type);
  171. $optionVariableString = $type.self::PROPERTY_PART_OPTION;
  172. $methodVariableString = $type.self::PROPERTY_PART_METHOD;
  173. $this->{$optionVariableString}[$name] = $optionCollection;
  174. $this->{$methodVariableString}[$name] = $method;
  175. return $this;
  176. }
  177. /**
  178. * Validate and get the proper call type.
  179. *
  180. * @param mixed $type
  181. *
  182. * @return $this
  183. */
  184. private function validateType(&$type)
  185. {
  186. $this->validateName($type);
  187. $type = strtolower(substr($type, 3));
  188. return $this;
  189. }
  190. /**
  191. * Verify that a string was passed as the filter/function name.
  192. *
  193. * @param mixed $name
  194. *
  195. * @return $this
  196. */
  197. private function validateName($name)
  198. {
  199. if (true === is_string($name)) {
  200. return $this;
  201. }
  202. throw new RuntimeException(
  203. 'Invalid function/filter name provided to $s (you must provide a string).', null, null, __METHOD__
  204. );
  205. }
  206. /**
  207. * @param string $type
  208. *
  209. * @return array
  210. */
  211. private function getCallableCollectionForType($type)
  212. {
  213. $this->validateType($type);
  214. $type = substr($type, 0, strlen($type) - 1);
  215. $callableCollection = [];
  216. $callableCollectionName = $type.self::PROPERTY_PART_METHOD;
  217. $twigExtensionClassName = 'Twig_Simple'.ucfirst($type);
  218. if (false === is_array($this->{$callableCollectionName}) || 0 === count($this->{$callableCollectionName})) {
  219. return $callableCollection;
  220. }
  221. foreach ($this->{$callableCollectionName} as $name => $callable) {
  222. $callableCollection[$name] = new $twigExtensionClassName(
  223. $name, $callable, $this->resolvedOptions($type, $name)
  224. );
  225. }
  226. return $callableCollection;
  227. }
  228. /**
  229. * Returns an array of {@see Twig_SimpleFunction} instances, providing the beidge between twig function calls
  230. * and the methods in this class.
  231. *
  232. * @return array
  233. */
  234. public function getFunctions()
  235. {
  236. return $this->getCallableCollectionForType(__FUNCTION__);
  237. }
  238. /**
  239. * Returns an array of {@see Twig_SimpleFilter} instances, providing the beidge between twig function calls
  240. * and the methods in this class.
  241. *
  242. * @return array
  243. */
  244. public function getFilters()
  245. {
  246. return $this->getCallableCollectionForType(__FUNCTION__);
  247. }
  248. /**
  249. * Returns the name of the Twig extension based on the classname.
  250. *
  251. * @return string
  252. */
  253. final public function getName()
  254. {
  255. return strtolower(sprintf('s.twig_extension.%s', ClassInfo::getClassNameByInstance($this)));
  256. }
  257. }
  258. /* EOF */