blade.php 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. <?php namespace Laravel;
  2. class Blade {
  3. /**
  4. * All of the compiler functions used by Blade.
  5. *
  6. * @var array
  7. */
  8. protected static $compilers = array(
  9. 'echos',
  10. 'forelse',
  11. 'empty',
  12. 'endforelse',
  13. 'structure_openings',
  14. 'structure_closings',
  15. 'else',
  16. 'yields',
  17. 'section_start',
  18. 'section_end',
  19. );
  20. /**
  21. * Register the Blade view engine with Laravel.
  22. *
  23. * @return void
  24. */
  25. public static function sharpen()
  26. {
  27. Event::listen(View::engine, function($view)
  28. {
  29. // The Blade view engine should only handle the rendering of views which
  30. // end with the Blade extension. If the given view does not, we will
  31. // return false so the View can be rendered as normal.
  32. if ( ! str_contains($view->path, BLADE_EXT))
  33. {
  34. return false;
  35. }
  36. $compiled = path('storage').'views/'.md5($view->path);
  37. // If the view doesn't exist or has been modified since the last time it
  38. // was compiled, we will recompile the view into pure PHP from it's
  39. // Blade representation, writing it to cached storage.
  40. if ( ! file_exists($compiled) or (filemtime($view->path) > filemtime($compiled)))
  41. {
  42. file_put_contents($compiled, Blade::compile($view->path));
  43. }
  44. $view->path = $compiled;
  45. // Once the view has been compiled, we can simply set the path to the
  46. // compiled view on the view instance and call the typical "get"
  47. // method on the view to evaluate the compiled PHP view.
  48. return $view->get();
  49. });
  50. }
  51. /**
  52. * Compiles the specified file containing Blade pseudo-code into valid PHP.
  53. *
  54. * @param string $path
  55. * @return string
  56. */
  57. public static function compile($path)
  58. {
  59. return static::compile_string(file_get_contents($path));
  60. }
  61. /**
  62. * Compiles the given string containing Blade pseudo-code into valid PHP.
  63. *
  64. * @param string $value
  65. * @return string
  66. */
  67. public static function compile_string($value)
  68. {
  69. foreach (static::$compilers as $compiler)
  70. {
  71. $method = "compile_{$compiler}";
  72. $value = static::$method($value);
  73. }
  74. return $value;
  75. }
  76. /**
  77. * Rewrites Blade echo statements into PHP echo statements.
  78. *
  79. * @param string $value
  80. * @return string
  81. */
  82. protected static function compile_echos($value)
  83. {
  84. return preg_replace('/\{\{(.+?)\}\}/', '<?php echo $1; ?>', $value);
  85. }
  86. /**
  87. * Rewrites Blade "for else" statements into valid PHP.
  88. *
  89. * @param string $value
  90. * @return string
  91. */
  92. protected static function compile_forelse($value)
  93. {
  94. preg_match_all('/(\s*)@forelse(\s*\(.*\))(\s*)/', $value, $matches);
  95. // First we'll loop through all of the "@forelse" lines. We need to
  96. // wrap each loop in an "if/else" statement that checks the count
  97. // of the variable being iterated against.
  98. if (isset($matches[0]))
  99. {
  100. foreach ($matches[0] as $forelse)
  101. {
  102. preg_match('/\$[^\s]*/', $forelse, $variable);
  103. // Once we have extracted the variable being looped against, we cab
  104. // prepend an "if" statmeent to the start of the loop that checks
  105. // that the count of the variable is greater than zero.
  106. $if = "<?php if (count({$variable[0]}) > 0): ?>";
  107. $search = '/(\s*)@forelse(\s*\(.*\))/';
  108. $replace = '$1'.$if.'<?php foreach$2: ?>';
  109. $blade = preg_replace($search, $replace, $forelse);
  110. // Finally, once we have the check prepended to the loop, we will
  111. // replace all instances of this "forelse" structure in the
  112. // content of the view being compiled to Blade syntax.
  113. $value = str_replace($forelse, $blade, $value);
  114. }
  115. }
  116. return $value;
  117. }
  118. /**
  119. * Rewrites Blade "empty" statements into valid PHP.
  120. *
  121. * @param string $value
  122. * @return string
  123. */
  124. protected static function compile_empty($value)
  125. {
  126. return str_replace('@empty', '<?php endforeach; ?><?php else: ?>', $value);
  127. }
  128. /**
  129. * Rewrites Blade "forelse" endings into valid PHP.
  130. *
  131. * @param string $value
  132. * @return string
  133. */
  134. protected static function compile_endforelse($value)
  135. {
  136. return str_replace('@endforelse', '<?php endif; ?>', $value);
  137. }
  138. /**
  139. * Rewrites Blade structure openings into PHP structure openings.
  140. *
  141. * @param string $value
  142. * @return string
  143. */
  144. protected static function compile_structure_openings($value)
  145. {
  146. $pattern = '/(\s*)@(if|elseif|foreach|for|while)(\s*\(.*\))/';
  147. return preg_replace($pattern, '$1<?php $2$3: ?>', $value);
  148. }
  149. /**
  150. * Rewrites Blade structure closings into PHP structure closings.
  151. *
  152. * @param string $value
  153. * @return string
  154. */
  155. protected static function compile_structure_closings($value)
  156. {
  157. $pattern = '/(\s*)@(endif|endforeach|endfor|endwhile)(\s*)/';
  158. return preg_replace($pattern, '$1<?php $2; ?>$3', $value);
  159. }
  160. /**
  161. * Rewrites Blade else statements into PHP else statements.
  162. *
  163. * @param string $value
  164. * @return string
  165. */
  166. protected static function compile_else($value)
  167. {
  168. return preg_replace('/(\s*)@(else)(\s*)/', '$1<?php $2: ?>$3', $value);
  169. }
  170. /**
  171. * Rewrites Blade @yield statements into Section statements.
  172. *
  173. * The Blade @yield statement is a shortcut to the Section::yield method.
  174. *
  175. * @param string $value
  176. * @return string
  177. */
  178. protected static function compile_yields($value)
  179. {
  180. $pattern = static::matcher('yield');
  181. return preg_replace($pattern, '$1<?php echo \\Laravel\\Section::yield$2; ?>', $value);
  182. }
  183. /**
  184. * Rewrites Blade @section statements into Section statements.
  185. *
  186. * The Blade @section statement is a shortcut to the Section::start method.
  187. *
  188. * @param string $value
  189. * @return string
  190. */
  191. protected static function compile_section_start($value)
  192. {
  193. $pattern = static::matcher('section');
  194. return preg_replace($pattern, '$1<?php \\Laravel\\Section::start$2; ?>', $value);
  195. }
  196. /**
  197. * Rewrites Blade @endsection statements into Section statements.
  198. *
  199. * The Blade @endsection statement is a shortcut to the Section::stop method.
  200. *
  201. * @param string $value
  202. * @return string
  203. */
  204. protected static function compile_section_end($value)
  205. {
  206. return preg_replace('/@endsection/', '<?php \\Laravel\\Section::stop(); ?>', $value);
  207. }
  208. /**
  209. * Get the regular expression for a generic Blade function.
  210. *
  211. * @param string $function
  212. * @return string
  213. */
  214. protected static function matcher($function)
  215. {
  216. return '/(\s*)@'.$function.'(\s*\(.*\))/';
  217. }
  218. }