PageRenderTime 40ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/laravel/framework/src/Illuminate/View/Compilers/BladeCompiler.php

https://gitlab.com/Pasantias/pasantiasASLG
PHP | 889 lines | 356 code | 109 blank | 424 comment | 18 complexity | 00551031baba2254e296dfa203ed8dba MD5 | raw file
  1. <?php
  2. namespace Illuminate\View\Compilers;
  3. use Illuminate\Support\Arr;
  4. use Illuminate\Support\Str;
  5. class BladeCompiler extends Compiler implements CompilerInterface
  6. {
  7. /**
  8. * All of the registered extensions.
  9. *
  10. * @var array
  11. */
  12. protected $extensions = [];
  13. /**
  14. * All custom "directive" handlers.
  15. *
  16. * This was implemented as a more usable "extend" in 5.1.
  17. *
  18. * @var array
  19. */
  20. protected $customDirectives = [];
  21. /**
  22. * The file currently being compiled.
  23. *
  24. * @var string
  25. */
  26. protected $path;
  27. /**
  28. * All of the available compiler functions.
  29. *
  30. * @var array
  31. */
  32. protected $compilers = [
  33. 'Extensions',
  34. 'Statements',
  35. 'Comments',
  36. 'Echos',
  37. ];
  38. /**
  39. * Array of opening and closing tags for raw echos.
  40. *
  41. * @var array
  42. */
  43. protected $rawTags = ['{!!', '!!}'];
  44. /**
  45. * Array of opening and closing tags for regular echos.
  46. *
  47. * @var array
  48. */
  49. protected $contentTags = ['{{', '}}'];
  50. /**
  51. * Array of opening and closing tags for escaped echos.
  52. *
  53. * @var array
  54. */
  55. protected $escapedTags = ['{{{', '}}}'];
  56. /**
  57. * The "regular" / legacy echo string format.
  58. *
  59. * @var string
  60. */
  61. protected $echoFormat = 'e(%s)';
  62. /**
  63. * Array of footer lines to be added to template.
  64. *
  65. * @var array
  66. */
  67. protected $footer = [];
  68. /**
  69. * Counter to keep track of nested forelse statements.
  70. *
  71. * @var int
  72. */
  73. protected $forelseCounter = 0;
  74. /**
  75. * Compile the view at the given path.
  76. *
  77. * @param string $path
  78. * @return void
  79. */
  80. public function compile($path = null)
  81. {
  82. if ($path) {
  83. $this->setPath($path);
  84. }
  85. $contents = $this->compileString($this->files->get($this->getPath()));
  86. if (! is_null($this->cachePath)) {
  87. $this->files->put($this->getCompiledPath($this->getPath()), $contents);
  88. }
  89. }
  90. /**
  91. * Get the path currently being compiled.
  92. *
  93. * @return string
  94. */
  95. public function getPath()
  96. {
  97. return $this->path;
  98. }
  99. /**
  100. * Set the path currently being compiled.
  101. *
  102. * @param string $path
  103. * @return void
  104. */
  105. public function setPath($path)
  106. {
  107. $this->path = $path;
  108. }
  109. /**
  110. * Compile the given Blade template contents.
  111. *
  112. * @param string $value
  113. * @return string
  114. */
  115. public function compileString($value)
  116. {
  117. $result = '';
  118. $this->footer = [];
  119. // Here we will loop through all of the tokens returned by the Zend lexer and
  120. // parse each one into the corresponding valid PHP. We will then have this
  121. // template as the correctly rendered PHP that can be rendered natively.
  122. foreach (token_get_all($value) as $token) {
  123. $result .= is_array($token) ? $this->parseToken($token) : $token;
  124. }
  125. // If there are any footer lines that need to get added to a template we will
  126. // add them here at the end of the template. This gets used mainly for the
  127. // template inheritance via the extends keyword that should be appended.
  128. if (count($this->footer) > 0) {
  129. $result = ltrim($result, PHP_EOL)
  130. .PHP_EOL.implode(PHP_EOL, array_reverse($this->footer));
  131. }
  132. return $result;
  133. }
  134. /**
  135. * Parse the tokens from the template.
  136. *
  137. * @param array $token
  138. * @return string
  139. */
  140. protected function parseToken($token)
  141. {
  142. list($id, $content) = $token;
  143. if ($id == T_INLINE_HTML) {
  144. foreach ($this->compilers as $type) {
  145. $content = $this->{"compile{$type}"}($content);
  146. }
  147. }
  148. return $content;
  149. }
  150. /**
  151. * Execute the user defined extensions.
  152. *
  153. * @param string $value
  154. * @return string
  155. */
  156. protected function compileExtensions($value)
  157. {
  158. foreach ($this->extensions as $compiler) {
  159. $value = call_user_func($compiler, $value, $this);
  160. }
  161. return $value;
  162. }
  163. /**
  164. * Compile Blade comments into valid PHP.
  165. *
  166. * @param string $value
  167. * @return string
  168. */
  169. protected function compileComments($value)
  170. {
  171. $pattern = sprintf('/%s--(.*?)--%s/s', $this->contentTags[0], $this->contentTags[1]);
  172. return preg_replace($pattern, '<?php /*$1*/ ?>', $value);
  173. }
  174. /**
  175. * Compile Blade echos into valid PHP.
  176. *
  177. * @param string $value
  178. * @return string
  179. */
  180. protected function compileEchos($value)
  181. {
  182. foreach ($this->getEchoMethods() as $method => $length) {
  183. $value = $this->$method($value);
  184. }
  185. return $value;
  186. }
  187. /**
  188. * Get the echo methods in the proper order for compilation.
  189. *
  190. * @return array
  191. */
  192. protected function getEchoMethods()
  193. {
  194. $methods = [
  195. 'compileRawEchos' => strlen(stripcslashes($this->rawTags[0])),
  196. 'compileEscapedEchos' => strlen(stripcslashes($this->escapedTags[0])),
  197. 'compileRegularEchos' => strlen(stripcslashes($this->contentTags[0])),
  198. ];
  199. uksort($methods, function ($method1, $method2) use ($methods) {
  200. // Ensure the longest tags are processed first
  201. if ($methods[$method1] > $methods[$method2]) {
  202. return -1;
  203. }
  204. if ($methods[$method1] < $methods[$method2]) {
  205. return 1;
  206. }
  207. // Otherwise give preference to raw tags (assuming they've overridden)
  208. if ($method1 === 'compileRawEchos') {
  209. return -1;
  210. }
  211. if ($method2 === 'compileRawEchos') {
  212. return 1;
  213. }
  214. if ($method1 === 'compileEscapedEchos') {
  215. return -1;
  216. }
  217. if ($method2 === 'compileEscapedEchos') {
  218. return 1;
  219. }
  220. });
  221. return $methods;
  222. }
  223. /**
  224. * Compile Blade statements that start with "@".
  225. *
  226. * @param string $value
  227. * @return mixed
  228. */
  229. protected function compileStatements($value)
  230. {
  231. $callback = function ($match) {
  232. if (method_exists($this, $method = 'compile'.ucfirst($match[1]))) {
  233. $match[0] = $this->$method(Arr::get($match, 3));
  234. } elseif (isset($this->customDirectives[$match[1]])) {
  235. $match[0] = call_user_func($this->customDirectives[$match[1]], Arr::get($match, 3));
  236. }
  237. return isset($match[3]) ? $match[0] : $match[0].$match[2];
  238. };
  239. return preg_replace_callback('/\B@(\w+)([ \t]*)(\( ( (?>[^()]+) | (?3) )* \))?/x', $callback, $value);
  240. }
  241. /**
  242. * Compile the "raw" echo statements.
  243. *
  244. * @param string $value
  245. * @return string
  246. */
  247. protected function compileRawEchos($value)
  248. {
  249. $pattern = sprintf('/(@)?%s\s*(.+?)\s*%s(\r?\n)?/s', $this->rawTags[0], $this->rawTags[1]);
  250. $callback = function ($matches) {
  251. $whitespace = empty($matches[3]) ? '' : $matches[3].$matches[3];
  252. return $matches[1] ? substr($matches[0], 1) : '<?php echo '.$this->compileEchoDefaults($matches[2]).'; ?>'.$whitespace;
  253. };
  254. return preg_replace_callback($pattern, $callback, $value);
  255. }
  256. /**
  257. * Compile the "regular" echo statements.
  258. *
  259. * @param string $value
  260. * @return string
  261. */
  262. protected function compileRegularEchos($value)
  263. {
  264. $pattern = sprintf('/(@)?%s\s*(.+?)\s*%s(\r?\n)?/s', $this->contentTags[0], $this->contentTags[1]);
  265. $callback = function ($matches) {
  266. $whitespace = empty($matches[3]) ? '' : $matches[3].$matches[3];
  267. $wrapped = sprintf($this->echoFormat, $this->compileEchoDefaults($matches[2]));
  268. return $matches[1] ? substr($matches[0], 1) : '<?php echo '.$wrapped.'; ?>'.$whitespace;
  269. };
  270. return preg_replace_callback($pattern, $callback, $value);
  271. }
  272. /**
  273. * Compile the escaped echo statements.
  274. *
  275. * @param string $value
  276. * @return string
  277. */
  278. protected function compileEscapedEchos($value)
  279. {
  280. $pattern = sprintf('/(@)?%s\s*(.+?)\s*%s(\r?\n)?/s', $this->escapedTags[0], $this->escapedTags[1]);
  281. $callback = function ($matches) {
  282. $whitespace = empty($matches[3]) ? '' : $matches[3].$matches[3];
  283. return $matches[1] ? $matches[0] : '<?php echo e('.$this->compileEchoDefaults($matches[2]).'); ?>'.$whitespace;
  284. };
  285. return preg_replace_callback($pattern, $callback, $value);
  286. }
  287. /**
  288. * Compile the default values for the echo statement.
  289. *
  290. * @param string $value
  291. * @return string
  292. */
  293. public function compileEchoDefaults($value)
  294. {
  295. return preg_replace('/^(?=\$)(.+?)(?:\s+or\s+)(.+?)$/s', 'isset($1) ? $1 : $2', $value);
  296. }
  297. /**
  298. * Compile the each statements into valid PHP.
  299. *
  300. * @param string $expression
  301. * @return string
  302. */
  303. protected function compileEach($expression)
  304. {
  305. return "<?php echo \$__env->renderEach{$expression}; ?>";
  306. }
  307. /**
  308. * Compile the inject statements into valid PHP.
  309. *
  310. * @param string $expression
  311. * @return string
  312. */
  313. protected function compileInject($expression)
  314. {
  315. $segments = explode(',', preg_replace("/[\(\)\\\"\']/", '', $expression));
  316. return '<?php $'.trim($segments[0])." = app('".trim($segments[1])."'); ?>";
  317. }
  318. /**
  319. * Compile the yield statements into valid PHP.
  320. *
  321. * @param string $expression
  322. * @return string
  323. */
  324. protected function compileYield($expression)
  325. {
  326. return "<?php echo \$__env->yieldContent{$expression}; ?>";
  327. }
  328. /**
  329. * Compile the show statements into valid PHP.
  330. *
  331. * @param string $expression
  332. * @return string
  333. */
  334. protected function compileShow($expression)
  335. {
  336. return '<?php echo $__env->yieldSection(); ?>';
  337. }
  338. /**
  339. * Compile the section statements into valid PHP.
  340. *
  341. * @param string $expression
  342. * @return string
  343. */
  344. protected function compileSection($expression)
  345. {
  346. return "<?php \$__env->startSection{$expression}; ?>";
  347. }
  348. /**
  349. * Compile the append statements into valid PHP.
  350. *
  351. * @param string $expression
  352. * @return string
  353. */
  354. protected function compileAppend($expression)
  355. {
  356. return '<?php $__env->appendSection(); ?>';
  357. }
  358. /**
  359. * Compile the end-section statements into valid PHP.
  360. *
  361. * @param string $expression
  362. * @return string
  363. */
  364. protected function compileEndsection($expression)
  365. {
  366. return '<?php $__env->stopSection(); ?>';
  367. }
  368. /**
  369. * Compile the stop statements into valid PHP.
  370. *
  371. * @param string $expression
  372. * @return string
  373. */
  374. protected function compileStop($expression)
  375. {
  376. return '<?php $__env->stopSection(); ?>';
  377. }
  378. /**
  379. * Compile the overwrite statements into valid PHP.
  380. *
  381. * @param string $expression
  382. * @return string
  383. */
  384. protected function compileOverwrite($expression)
  385. {
  386. return '<?php $__env->stopSection(true); ?>';
  387. }
  388. /**
  389. * Compile the unless statements into valid PHP.
  390. *
  391. * @param string $expression
  392. * @return string
  393. */
  394. protected function compileUnless($expression)
  395. {
  396. return "<?php if ( ! $expression): ?>";
  397. }
  398. /**
  399. * Compile the end unless statements into valid PHP.
  400. *
  401. * @param string $expression
  402. * @return string
  403. */
  404. protected function compileEndunless($expression)
  405. {
  406. return '<?php endif; ?>';
  407. }
  408. /**
  409. * Compile the lang statements into valid PHP.
  410. *
  411. * @param string $expression
  412. * @return string
  413. */
  414. protected function compileLang($expression)
  415. {
  416. return "<?php echo app('translator')->get$expression; ?>";
  417. }
  418. /**
  419. * Compile the choice statements into valid PHP.
  420. *
  421. * @param string $expression
  422. * @return string
  423. */
  424. protected function compileChoice($expression)
  425. {
  426. return "<?php echo app('translator')->choice$expression; ?>";
  427. }
  428. /**
  429. * Compile the else statements into valid PHP.
  430. *
  431. * @param string $expression
  432. * @return string
  433. */
  434. protected function compileElse($expression)
  435. {
  436. return '<?php else: ?>';
  437. }
  438. /**
  439. * Compile the for statements into valid PHP.
  440. *
  441. * @param string $expression
  442. * @return string
  443. */
  444. protected function compileFor($expression)
  445. {
  446. return "<?php for{$expression}: ?>";
  447. }
  448. /**
  449. * Compile the foreach statements into valid PHP.
  450. *
  451. * @param string $expression
  452. * @return string
  453. */
  454. protected function compileForeach($expression)
  455. {
  456. return "<?php foreach{$expression}: ?>";
  457. }
  458. /**
  459. * Compile the forelse statements into valid PHP.
  460. *
  461. * @param string $expression
  462. * @return string
  463. */
  464. protected function compileForelse($expression)
  465. {
  466. $empty = '$__empty_'.++$this->forelseCounter;
  467. return "<?php {$empty} = true; foreach{$expression}: {$empty} = false; ?>";
  468. }
  469. /**
  470. * Compile the can statements into valid PHP.
  471. *
  472. * @param string $expression
  473. * @return string
  474. */
  475. protected function compileCan($expression)
  476. {
  477. return "<?php if (app('Illuminate\\Contracts\\Auth\\Access\\Gate')->check{$expression}): ?>";
  478. }
  479. /**
  480. * Compile the cannot statements into valid PHP.
  481. *
  482. * @param string $expression
  483. * @return string
  484. */
  485. protected function compileCannot($expression)
  486. {
  487. return "<?php if (app('Illuminate\\Contracts\\Auth\\Access\\Gate')->denies{$expression}): ?>";
  488. }
  489. /**
  490. * Compile the if statements into valid PHP.
  491. *
  492. * @param string $expression
  493. * @return string
  494. */
  495. protected function compileIf($expression)
  496. {
  497. return "<?php if{$expression}: ?>";
  498. }
  499. /**
  500. * Compile the else-if statements into valid PHP.
  501. *
  502. * @param string $expression
  503. * @return string
  504. */
  505. protected function compileElseif($expression)
  506. {
  507. return "<?php elseif{$expression}: ?>";
  508. }
  509. /**
  510. * Compile the forelse statements into valid PHP.
  511. *
  512. * @param string $expression
  513. * @return string
  514. */
  515. protected function compileEmpty($expression)
  516. {
  517. $empty = '$__empty_'.$this->forelseCounter--;
  518. return "<?php endforeach; if ({$empty}): ?>";
  519. }
  520. /**
  521. * Compile the while statements into valid PHP.
  522. *
  523. * @param string $expression
  524. * @return string
  525. */
  526. protected function compileWhile($expression)
  527. {
  528. return "<?php while{$expression}: ?>";
  529. }
  530. /**
  531. * Compile the end-while statements into valid PHP.
  532. *
  533. * @param string $expression
  534. * @return string
  535. */
  536. protected function compileEndwhile($expression)
  537. {
  538. return '<?php endwhile; ?>';
  539. }
  540. /**
  541. * Compile the end-for statements into valid PHP.
  542. *
  543. * @param string $expression
  544. * @return string
  545. */
  546. protected function compileEndfor($expression)
  547. {
  548. return '<?php endfor; ?>';
  549. }
  550. /**
  551. * Compile the end-for-each statements into valid PHP.
  552. *
  553. * @param string $expression
  554. * @return string
  555. */
  556. protected function compileEndforeach($expression)
  557. {
  558. return '<?php endforeach; ?>';
  559. }
  560. /**
  561. * Compile the end-can statements into valid PHP.
  562. *
  563. * @param string $expression
  564. * @return string
  565. */
  566. protected function compileEndcan($expression)
  567. {
  568. return '<?php endif; ?>';
  569. }
  570. /**
  571. * Compile the end-cannot statements into valid PHP.
  572. *
  573. * @param string $expression
  574. * @return string
  575. */
  576. protected function compileEndcannot($expression)
  577. {
  578. return '<?php endif; ?>';
  579. }
  580. /**
  581. * Compile the end-if statements into valid PHP.
  582. *
  583. * @param string $expression
  584. * @return string
  585. */
  586. protected function compileEndif($expression)
  587. {
  588. return '<?php endif; ?>';
  589. }
  590. /**
  591. * Compile the end-for-else statements into valid PHP.
  592. *
  593. * @param string $expression
  594. * @return string
  595. */
  596. protected function compileEndforelse($expression)
  597. {
  598. return '<?php endif; ?>';
  599. }
  600. /**
  601. * Compile the extends statements into valid PHP.
  602. *
  603. * @param string $expression
  604. * @return string
  605. */
  606. protected function compileExtends($expression)
  607. {
  608. if (Str::startsWith($expression, '(')) {
  609. $expression = substr($expression, 1, -1);
  610. }
  611. $data = "<?php echo \$__env->make($expression, array_except(get_defined_vars(), array('__data', '__path')))->render(); ?>";
  612. $this->footer[] = $data;
  613. return '';
  614. }
  615. /**
  616. * Compile the include statements into valid PHP.
  617. *
  618. * @param string $expression
  619. * @return string
  620. */
  621. protected function compileInclude($expression)
  622. {
  623. if (Str::startsWith($expression, '(')) {
  624. $expression = substr($expression, 1, -1);
  625. }
  626. return "<?php echo \$__env->make($expression, array_except(get_defined_vars(), array('__data', '__path')))->render(); ?>";
  627. }
  628. /**
  629. * Compile the stack statements into the content.
  630. *
  631. * @param string $expression
  632. * @return string
  633. */
  634. protected function compileStack($expression)
  635. {
  636. return "<?php echo \$__env->yieldContent{$expression}; ?>";
  637. }
  638. /**
  639. * Compile the push statements into valid PHP.
  640. *
  641. * @param string $expression
  642. * @return string
  643. */
  644. protected function compilePush($expression)
  645. {
  646. return "<?php \$__env->startSection{$expression}; ?>";
  647. }
  648. /**
  649. * Compile the endpush statements into valid PHP.
  650. *
  651. * @param string $expression
  652. * @return string
  653. */
  654. protected function compileEndpush($expression)
  655. {
  656. return '<?php $__env->appendSection(); ?>';
  657. }
  658. /**
  659. * Get the extensions used by the compiler.
  660. *
  661. * @return array
  662. */
  663. public function getExtensions()
  664. {
  665. return $this->extensions;
  666. }
  667. /**
  668. * Register a custom Blade compiler.
  669. *
  670. * @param callable $compiler
  671. * @return void
  672. */
  673. public function extend(callable $compiler)
  674. {
  675. $this->extensions[] = $compiler;
  676. }
  677. /**
  678. * Register a handler for custom directives.
  679. *
  680. * @param string $name
  681. * @param callable $handler
  682. * @return void
  683. */
  684. public function directive($name, callable $handler)
  685. {
  686. $this->customDirectives[$name] = $handler;
  687. }
  688. /**
  689. * Get the list of custom directives.
  690. *
  691. * @return array
  692. */
  693. public function getCustomDirectives()
  694. {
  695. return $this->customDirectives;
  696. }
  697. /**
  698. * Gets the raw tags used by the compiler.
  699. *
  700. * @return array
  701. */
  702. public function getRawTags()
  703. {
  704. return $this->rawTags;
  705. }
  706. /**
  707. * Sets the raw tags used for the compiler.
  708. *
  709. * @param string $openTag
  710. * @param string $closeTag
  711. * @return void
  712. */
  713. public function setRawTags($openTag, $closeTag)
  714. {
  715. $this->rawTags = [preg_quote($openTag), preg_quote($closeTag)];
  716. }
  717. /**
  718. * Sets the content tags used for the compiler.
  719. *
  720. * @param string $openTag
  721. * @param string $closeTag
  722. * @param bool $escaped
  723. * @return void
  724. */
  725. public function setContentTags($openTag, $closeTag, $escaped = false)
  726. {
  727. $property = ($escaped === true) ? 'escapedTags' : 'contentTags';
  728. $this->{$property} = [preg_quote($openTag), preg_quote($closeTag)];
  729. }
  730. /**
  731. * Sets the escaped content tags used for the compiler.
  732. *
  733. * @param string $openTag
  734. * @param string $closeTag
  735. * @return void
  736. */
  737. public function setEscapedContentTags($openTag, $closeTag)
  738. {
  739. $this->setContentTags($openTag, $closeTag, true);
  740. }
  741. /**
  742. * Gets the content tags used for the compiler.
  743. *
  744. * @return string
  745. */
  746. public function getContentTags()
  747. {
  748. return $this->getTags();
  749. }
  750. /**
  751. * Gets the escaped content tags used for the compiler.
  752. *
  753. * @return string
  754. */
  755. public function getEscapedContentTags()
  756. {
  757. return $this->getTags(true);
  758. }
  759. /**
  760. * Gets the tags used for the compiler.
  761. *
  762. * @param bool $escaped
  763. * @return array
  764. */
  765. protected function getTags($escaped = false)
  766. {
  767. $tags = $escaped ? $this->escapedTags : $this->contentTags;
  768. return array_map('stripcslashes', $tags);
  769. }
  770. /**
  771. * Set the echo format to be used by the compiler.
  772. *
  773. * @param string $format
  774. * @return void
  775. */
  776. public function setEchoFormat($format)
  777. {
  778. $this->echoFormat = $format;
  779. }
  780. }