PageRenderTime 42ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/xandra.org/www/application/vendor/Flow/Template.php

https://bitbucket.org/ekkl/tanora
PHP | 712 lines | 618 code | 94 blank | 0 comment | 87 complexity | 8a7188e270a6890d898e5fc372fcd44d MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause
  1. <?php
  2. namespace Flow;
  3. abstract class Template
  4. {
  5. protected $loader;
  6. protected $helpers;
  7. protected $parent;
  8. protected $blocks;
  9. protected $macros;
  10. protected $imports;
  11. protected $stack;
  12. public function __construct($loader, $helpers = array())
  13. {
  14. $this->loader = $loader;
  15. $this->helpers = $helpers;
  16. $this->parent = null;
  17. $this->blocks = array();
  18. $this->macros = array();
  19. $this->imports = array();
  20. $this->stack = array();
  21. }
  22. public function loadExtends($template)
  23. {
  24. try {
  25. return $this->loader->load($template, static::NAME);
  26. } catch (\Exception $e) {
  27. throw new \RuntimeException(sprintf(
  28. 'error extending %s (%s) from %s line %d',
  29. $template, $e->getMessage(), static::NAME,
  30. $this->getLineTrace($e)
  31. ));
  32. }
  33. }
  34. public function loadInclude($template)
  35. {
  36. try {
  37. return $this->loader->load($template, static::NAME);
  38. } catch (\Exception $e) {
  39. throw new \RuntimeException(sprintf(
  40. 'error including %s (%s) from %s line %d',
  41. $template, $e->getMessage(), static::NAME,
  42. $this->getLineTrace($e)
  43. ));
  44. }
  45. }
  46. public function loadImport($template)
  47. {
  48. try {
  49. return $this->loader->load($template, static::NAME)->getMacros();
  50. } catch (\Exception $e) {
  51. throw new \RuntimeException(sprintf(
  52. 'error importing %s (%s) from %s line %d',
  53. $template, $e->getMessage(), static::NAME,
  54. $this->getLineTrace($e)
  55. ));
  56. }
  57. }
  58. public function displayBlock($name, $context, $blocks, $macros, $imports)
  59. {
  60. $blocks = $blocks + $this->blocks;
  61. $macros = $macros + $this->macros;
  62. $imports = $imports + $this->imports;
  63. if (isset($blocks[$name]) && is_callable($blocks[$name])) {
  64. return call_user_func(
  65. $blocks[$name], $context, $blocks, $macros, $imports
  66. );
  67. }
  68. }
  69. public function displayParent($name, $context, $blocks, $macros, $imports)
  70. {
  71. $parent = $this;
  72. while ($parent = $parent->parent) {
  73. if (isset($parent->blocks[$name]) &&
  74. is_callable($parent->blocks[$name])) {
  75. return call_user_func($parent->blocks[$name], $context, $blocks,
  76. $macros, $imports);
  77. }
  78. }
  79. }
  80. public function expandMacro($module, $name, $params, $context, $macros,
  81. $imports)
  82. {
  83. $macros = $macros + $this->macros;
  84. $imports = $imports + $this->imports;
  85. if (isset($module) && isset($imports[$module])) {
  86. $macros = $macros + $imports[$module];
  87. }
  88. if (isset($macros[$name]) && is_callable($macros[$name])) {
  89. return call_user_func(
  90. $macros[$name], $params, $context, $macros, $imports
  91. );
  92. }
  93. }
  94. public function pushContext(&$context, $name)
  95. {
  96. if (!array_key_exists($name, $this->stack)) {
  97. $this->stack[$name] = array();
  98. }
  99. array_push($this->stack[$name], isset($context[$name]) ?
  100. $context[$name] : null
  101. );
  102. return $this;
  103. }
  104. public function popContext(&$context, $name)
  105. {
  106. if (!empty($this->stack[$name])) {
  107. $context[$name] = array_pop($this->stack[$name]);
  108. }
  109. return $this;
  110. }
  111. public function getLineTrace(\Exception $e = null)
  112. {
  113. if (!isset($e)) {
  114. $e = new \Exception;
  115. }
  116. $lines = static::$lines;
  117. $file = get_class($this) . '.php';
  118. foreach ($e->getTrace() as $trace) {
  119. if (isset($trace['file']) && basename($trace['file']) == $file) {
  120. $line = $trace['line'];
  121. return isset($lines[$line]) ? $lines[$line] : null;
  122. }
  123. }
  124. return null;
  125. }
  126. public function helper($name, $args = array())
  127. {
  128. $args = func_get_args();
  129. $name = array_shift($args);
  130. try {
  131. if (isset($this->helpers[$name]) &&
  132. is_callable($this->helpers[$name])) {
  133. return call_user_func_array($this->helpers[$name], $args);
  134. } elseif (is_callable("\\Flow\\Helper\\$name")) {
  135. return call_user_func_array("\\Flow\\Helper\\$name", $args);
  136. }
  137. } catch (\Exception $e) {
  138. throw new \RuntimeException(
  139. sprintf(
  140. '%s in %s line %d',
  141. $e->getMessage(), static::NAME, $this->getLineTrace($e)
  142. )
  143. );
  144. }
  145. throw new \RuntimeException(
  146. sprintf(
  147. 'undefined helper "%s" in %s line %d',
  148. $name, static::NAME, $this->getLineTrace()
  149. )
  150. );
  151. }
  152. abstract public function display($context = array(), $blocks = array(),
  153. $macros = array(), $imports = array());
  154. public function render($context = array(), $blocks = array(),
  155. $macros = array(), $imports = array())
  156. {
  157. ob_start();
  158. $this->display($context, $blocks, $macros);
  159. return ob_get_clean();
  160. }
  161. public function iterate($context, $seq)
  162. {
  163. return new Helper\ContextIterator($seq, isset($context['loop']) ?
  164. $context['loop'] : null);
  165. }
  166. public function getBlocks()
  167. {
  168. return $this->blocks;
  169. }
  170. public function getMacros()
  171. {
  172. return $this->macros;
  173. }
  174. public function getImports()
  175. {
  176. return $this->imports;
  177. }
  178. public function getAttr($obj, $attr, $args = array())
  179. {
  180. if (is_array($obj)) {
  181. if (isset($obj[$attr])) {
  182. if ($obj[$attr] instanceof \Closure) {
  183. if (is_array($args)) {
  184. array_unshift($args, $obj);
  185. } else {
  186. $args = array($obj);
  187. }
  188. return call_user_func_array($obj[$attr], $args);
  189. } else {
  190. return $obj[$attr];
  191. }
  192. } else {
  193. return null;
  194. }
  195. } elseif (is_object($obj)) {
  196. if (is_array($args)) {
  197. $callable = array($obj, $attr);
  198. return is_callable($callable) ?
  199. call_user_func_array($callable, $args) : null;
  200. } else {
  201. $members = array_keys(get_object_vars($obj));
  202. $methods = get_class_methods(get_class($obj));
  203. if (in_array($attr, $members)) {
  204. return @$obj->$attr;
  205. } elseif (in_array('__get', $methods)) {
  206. return $obj->__get($attr);
  207. } else {
  208. $callable = array($obj, $attr);
  209. return is_callable($callable) ?
  210. call_user_func($callable) : null;
  211. }
  212. }
  213. } else {
  214. return null;
  215. }
  216. }
  217. public function setAttr(&$obj, $attrs, $value)
  218. {
  219. if (empty($attrs)) {
  220. $obj = $value;
  221. return;
  222. }
  223. $attr = array_shift($attrs);
  224. if (is_object($obj)) {
  225. $class = get_class($obj);
  226. $members = array_keys(get_object_vars($obj));
  227. if (!in_array($attr, $members)) {
  228. if (empty($attrs) && method_exists($obj, '__set')) {
  229. $obj->__set($attr, $value);
  230. return;
  231. } elseif (property_exists($class, $attr)) {
  232. throw new \RuntimeException(
  233. "inaccessible '$attr' object attribute"
  234. );
  235. } else {
  236. if ($attr === null || $attr === false || $attr === '') {
  237. if ($attr === null) $token = 'null';
  238. if ($attr === false) $token = 'false';
  239. if ($attr === '') $token = 'empty string';
  240. throw new \RuntimeException(
  241. sprintf(
  242. 'invalid object attribute (%s) in %s line %d',
  243. $token, static::NAME, $this->getLineTrace()
  244. )
  245. );
  246. }
  247. $obj->{$attr} = null;
  248. }
  249. }
  250. if (!isset($obj->$attr)) $obj->$attr = null;
  251. $this->setAttr($obj->$attr, $attrs, $value);
  252. } else {
  253. if (!is_array($obj)) $obj = array();
  254. $this->setAttr($obj[$attr], $attrs, $value);
  255. }
  256. }
  257. }
  258. namespace Flow\Helper;
  259. class ContextIterator implements \Iterator
  260. {
  261. protected $sequence;
  262. public function __construct($sequence, $parent)
  263. {
  264. if ($sequence instanceof \Traversable) {
  265. $this->length = ($sequence instanceof \Countable) ?
  266. count($sequence) : iterator_count($sequence);
  267. $this->sequence = $sequence;
  268. } elseif (is_array($sequence)) {
  269. $this->length = count($sequence);
  270. $this->sequence = new \ArrayIterator($sequence);
  271. } else {
  272. $this->length = 0;
  273. $this->sequence = new \ArrayIterator;
  274. }
  275. $this->parent = $parent;
  276. }
  277. public function rewind()
  278. {
  279. $this->sequence->rewind();
  280. $this->index = 0;
  281. $this->count = $this->index + 1;
  282. $this->first = $this->count == 1;
  283. $this->last = $this->count == $this->length;
  284. }
  285. public function key()
  286. {
  287. return $this->sequence->key();
  288. }
  289. public function valid()
  290. {
  291. return $this->sequence->valid();
  292. }
  293. public function next()
  294. {
  295. $this->sequence->next();
  296. $this->index += 1;
  297. $this->count = $this->index + 1;
  298. $this->first = $this->count == 1;
  299. $this->last = $this->count == $this->length;
  300. }
  301. public function current()
  302. {
  303. return $this->sequence->current();
  304. }
  305. }
  306. class RangeIterator implements \Iterator
  307. {
  308. protected $lower;
  309. protected $upper;
  310. protected $step;
  311. protected $current;
  312. public function __construct($lower, $upper, $step = 1)
  313. {
  314. $this->lower = $lower;
  315. $this->upper = $upper;
  316. $this->step = $step;
  317. }
  318. public function length()
  319. {
  320. return \abs($this->upper - $this->lower) / \abs($this->step);
  321. }
  322. public function includes($n)
  323. {
  324. if ($this->upper >= $this->lower) {
  325. return $n >= $this->lower && $n <= $this->upper;
  326. } else {
  327. return $n <= $this->lower && $n >= $this->upper;
  328. }
  329. }
  330. public function random($seed = null)
  331. {
  332. if (isset($seed)) mt_srand($seed);
  333. return $this->upper >= $this->lower ?
  334. mt_rand($this->lower, $this->upper) :
  335. mt_rand($this->upper, $this->lower);
  336. }
  337. public function rewind()
  338. {
  339. $this->current = $this->lower;
  340. }
  341. public function key()
  342. {
  343. return $this->current;
  344. }
  345. public function valid()
  346. {
  347. if ($this->upper >= $this->lower) {
  348. return $this->current >= $this->lower &&
  349. $this->current <= $this->upper;
  350. } else {
  351. return $this->current <= $this->lower &&
  352. $this->current >= $this->upper;
  353. }
  354. }
  355. public function next()
  356. {
  357. $this->current += $this->step;
  358. return $this;
  359. }
  360. public function current()
  361. {
  362. return $this->current;
  363. }
  364. }
  365. class Cycler implements \IteratorAggregate
  366. {
  367. protected $elements;
  368. protected $length;
  369. protected $idx;
  370. public function __construct($elements)
  371. {
  372. $this->elements = $elements;
  373. $this->length = count($this->elements);
  374. $this->idx = 0;
  375. }
  376. public function getIterator()
  377. {
  378. return new \ArrayIterator($this->elements);
  379. }
  380. public function next()
  381. {
  382. return $this->elements[($this->idx++) % ($this->length)];
  383. }
  384. public function random($seed = null)
  385. {
  386. if (isset($seed)) mt_srand($seed);
  387. return $this->elements[mt_rand(0, $this->length - 1)];
  388. }
  389. public function count()
  390. {
  391. return $this->idx;
  392. }
  393. public function cycle()
  394. {
  395. return ceil($this->idx / $this->length);
  396. }
  397. }
  398. function abs($obj = null)
  399. {
  400. return \abs(intval($obj));
  401. }
  402. function bytes($obj = null, $decimals = 1, $dec = '.', $sep = ',')
  403. {
  404. $obj = max(0, intval($obj));
  405. $places = strlen($obj);
  406. if ($places <= 9 && $places >= 7) {
  407. $obj = \number_format($obj / 1048576, $decimals, $dec, $sep);
  408. return "$obj MB";
  409. } elseif ($places >= 10) {
  410. $obj = \number_format($obj / 1073741824, $decimals, $dec, $sep);
  411. return "$obj GB";
  412. } else {
  413. $obj = \number_format($obj / 1024, $decimals, $dec, $sep);
  414. return "$obj KB";
  415. }
  416. }
  417. function capitalize($obj)
  418. {
  419. return ucfirst(strval($obj));
  420. }
  421. function cycle($obj = null)
  422. {
  423. $obj = ($obj instanceof \Traversable) ?
  424. iterator_to_array($obj) : (array) $obj;
  425. return new Cycler((array) $obj);
  426. }
  427. function date($obj = null, $format = 'Y-m-d')
  428. {
  429. return \date($format, $obj ?: time());
  430. }
  431. function dump($obj = null)
  432. {
  433. echo '<pre>';
  434. print_r($obj);
  435. echo '</pre>';
  436. }
  437. function e($obj = null, $force = false)
  438. {
  439. return escape($obj, $force);
  440. }
  441. function escape($obj = null, $force = false)
  442. {
  443. return htmlspecialchars(strval($obj), ENT_QUOTES, 'UTF-8', $force);
  444. }
  445. function first($obj = null, $default = null)
  446. {
  447. if (is_string($obj)) return strlen($obj) ? substr($obj, 0, 1) : $default;
  448. $obj = ($obj instanceof \Traversable) ?
  449. iterator_to_array($obj) : (array) $obj;
  450. $keys = array_keys($obj);
  451. if (count($keys)) {
  452. return $obj[$keys[0]];
  453. }
  454. return $default;
  455. }
  456. function format($obj, $args)
  457. {
  458. return call_user_func_array('sprintf', func_get_args());
  459. }
  460. function is_divisible_by($obj = null, $number = null)
  461. {
  462. if (!isset($number)) return false;
  463. if (!is_numeric($obj) || !is_numeric($number)) return false;
  464. if ($number == 0) return false;
  465. return ($obj % $number == 0);
  466. }
  467. function is_empty($obj = null)
  468. {
  469. if (is_null($obj)) {
  470. return true;
  471. } elseif (is_array($obj)) {
  472. return empty($obj);
  473. } elseif (is_string($obj)) {
  474. return strlen($obj) == 0;
  475. } elseif ($obj instanceof \Countable) {
  476. return count($obj) ? false : true;
  477. } elseif ($obj instanceof \Traversable) {
  478. return iterator_count($obj);
  479. } else {
  480. return false;
  481. }
  482. }
  483. function is_even($obj = null)
  484. {
  485. if (is_scalar($obj) || is_null($obj)) {
  486. $obj = is_numeric($obj) ? intval($obj) : strlen($obj);
  487. } elseif (is_array($obj)) {
  488. $obj = count($obj);
  489. } elseif ($obj instanceof \Traversable) {
  490. $obj = iterator_count($obj);
  491. } else {
  492. return false;
  493. }
  494. return \abs($obj % 2) == 0;
  495. }
  496. function is_odd($obj = null)
  497. {
  498. if (is_scalar($obj) || is_null($obj)) {
  499. $obj = is_numeric($obj) ? intval($obj) : strlen($obj);
  500. } elseif (is_array($obj)) {
  501. $obj = count($obj);
  502. } elseif ($obj instanceof \Traversable) {
  503. $obj = iterator_count($obj);
  504. } else {
  505. return false;
  506. }
  507. return \abs($obj % 2) == 1;
  508. }
  509. function join($obj = null, $glue = '')
  510. {
  511. $obj = ($obj instanceof \Traversable) ?
  512. iterator_to_array($obj) : (array) $obj;
  513. return \join($glue, $obj);
  514. }
  515. function json_encode($obj = null)
  516. {
  517. return \json_encode($obj);
  518. }
  519. function keys($obj = null)
  520. {
  521. if (is_array($obj)) {
  522. return array_keys($obj);
  523. } elseif ($obj instanceof \Traversable) {
  524. return array_keys(iterator_to_array($obj));
  525. }
  526. return null;
  527. }
  528. function last($obj = null, $default = null)
  529. {
  530. if (is_string($obj)) return strlen($obj) ? substr($obj, -1) : $default;
  531. $obj = ($obj instanceof \Traversable) ?
  532. iterator_to_array($obj) : (array) $obj;
  533. $keys = array_keys($obj);
  534. if ($len = count($keys)) {
  535. return $obj[$keys[$len - 1]];
  536. }
  537. return $default;
  538. }
  539. function length($obj = null)
  540. {
  541. if (is_string($obj)) {
  542. return strlen($obj);
  543. } elseif (is_array($obj) || ($obj instanceof \Countable)) {
  544. return count($obj);
  545. } elseif ($obj instanceof \Traversable) {
  546. return iterator_count($obj);
  547. } else {
  548. return 1;
  549. }
  550. }
  551. function lower($obj = null)
  552. {
  553. return strtolower(strval($obj));
  554. }
  555. function nl2br($obj = null, $is_xhtml = false)
  556. {
  557. return \nl2br(strval($obj), $is_xhtml);
  558. }
  559. function number_format($obj = null, $decimals = 0, $dec_point = '.',
  560. $thousands_sep = ',')
  561. {
  562. return \number_format(strval($obj), $decimals, $dec_point, $thousands_sep);
  563. }
  564. function range($lower = null, $upper = null, $step = 1)
  565. {
  566. return new RangeIterator(intval($lower), intval($upper), intval($step));
  567. }
  568. function repeat($obj, $times = 2)
  569. {
  570. return str_repeat(strval($obj), $times);
  571. }
  572. function replace($obj = null, $search = '', $replace = '', $regex = false)
  573. {
  574. if ($regex) {
  575. return preg_replace($search, $replace, strval($obj));
  576. } else {
  577. return str_replace($search, $replace, strval($obj));
  578. }
  579. }
  580. function strip_tags($obj = null, $allowableTags = '')
  581. {
  582. return \strip_tags(strval($obj), $allowableTags);
  583. }
  584. function title($obj = null)
  585. {
  586. return ucwords(strval($obj));
  587. }
  588. function trim($obj = null, $charlist = " \t\n\r\0\x0B")
  589. {
  590. return \trim(strval($obj), $charlist);
  591. }
  592. function truncate($obj = null, $length = 255, $preserve_words = false,
  593. $hellip = '&hellip;')
  594. {
  595. $obj = strval($obj);
  596. $len = strlen($obj);
  597. if ($length >= $len) return $obj;
  598. $truncated = $preserve_words ?
  599. preg_replace('/\s+?(\S+)?$/', '', substr($obj, 0, $length + 1)) :
  600. substr($obj, 0, $length);
  601. return $truncated . $hellip;
  602. }
  603. function unescape($obj = null)
  604. {
  605. return htmlspecialchars_decode(strval($obj), ENT_QUOTES);
  606. }
  607. function upper($obj = null)
  608. {
  609. return strtoupper(strval($obj));
  610. }
  611. function url_encode($obj = null)
  612. {
  613. return urlencode(strval($obj));
  614. }
  615. function word_wrap($obj = null, $width = 75, $break = "\n", $cut = false)
  616. {
  617. return wordwrap(strval($obj), $width, $break, $cut);
  618. }