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

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

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