PageRenderTime 69ms CodeModel.GetById 39ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Illuminate/View/Environment.php

https://bitbucket.org/mikebosire/framework
PHP | 577 lines | 236 code | 72 blank | 269 comment | 7 complexity | 1540ce1d3495dc01ae76a05ef189e0eb MD5 | raw file
  1. <?php namespace Illuminate\View;
  2. use Closure;
  3. use Illuminate\Events\Dispatcher;
  4. use Illuminate\Container\Container;
  5. use Illuminate\View\Engines\EngineResolver;
  6. class Environment {
  7. /**
  8. * The engine implementation.
  9. *
  10. * @var \Illuminate\View\Engines\EngineResolver
  11. */
  12. protected $engines;
  13. /**
  14. * The view finder implementation.
  15. *
  16. * @var \Illuminate\View\ViewFinderInterface
  17. */
  18. protected $finder;
  19. /**
  20. * The event dispatcher instance.
  21. *
  22. * @var \Illuminate\Events\Dispatcher
  23. */
  24. protected $events;
  25. /**
  26. * The IoC container instance.
  27. *
  28. * @var \Illuminate\Container
  29. */
  30. protected $container;
  31. /**
  32. * Data that should be available to all templates.
  33. *
  34. * @var array
  35. */
  36. protected $shared = array();
  37. /**
  38. * The extension to engine bindings.
  39. *
  40. * @var array
  41. */
  42. protected $extensions = array('blade.php' => 'blade', 'php' => 'php');
  43. /**
  44. * The view composer events.
  45. *
  46. * @var array
  47. */
  48. protected $composers = array();
  49. /**
  50. * All of the finished, captured sections.
  51. *
  52. * @var array
  53. */
  54. protected $sections = array();
  55. /**
  56. * The stack of in-progress sections.
  57. *
  58. * @var array
  59. */
  60. protected $sectionStack = array();
  61. /**
  62. * The number of active rendering operations.
  63. *
  64. * @var int
  65. */
  66. protected $renderCount = 0;
  67. /**
  68. * Create a new view environment instance.
  69. *
  70. * @param \Illuminate\View\Engines\EngineResolver $engines
  71. * @param \Illuminate\View\ViewFinderInterface $finder
  72. * @param \Illuminate\Events\Dispatcher $events
  73. * @return void
  74. */
  75. public function __construct(EngineResolver $engines, ViewFinderInterface $finder, Dispatcher $events)
  76. {
  77. $this->finder = $finder;
  78. $this->events = $events;
  79. $this->engines = $engines;
  80. $this->share('__env', $this);
  81. }
  82. /**
  83. * Get a evaluated view contents for the given view.
  84. *
  85. * @param string $view
  86. * @param mixed $data
  87. * @return \Illuminate\View\View
  88. */
  89. public function make($view, $data = array())
  90. {
  91. $path = $this->finder->find($view);
  92. return new View($this, $this->getEngineFromPath($path), $view, $path, $data);
  93. }
  94. /**
  95. * Determine if a given view exists.
  96. *
  97. * @param string $view
  98. * @return bool
  99. */
  100. public function exists($view)
  101. {
  102. try
  103. {
  104. $this->finder->find($view);
  105. }
  106. catch (\InvalidArgumentException $e)
  107. {
  108. return false;
  109. }
  110. return true;
  111. }
  112. /**
  113. * Get the rendered contents of a partial from a loop.
  114. *
  115. * @param string $view
  116. * @param array $data
  117. * @param string $iterator
  118. * @param string $empty
  119. * @return string
  120. */
  121. public function renderEach($view, $data, $iterator, $empty = 'raw|')
  122. {
  123. $result = '';
  124. // If is actually data in the array, we will loop through the data and append
  125. // an instance of the partial view to the final result HTML passing in the
  126. // iterated value of this data array, allowing the views to access them.
  127. if (count($data) > 0)
  128. {
  129. foreach ($data as $key => $value)
  130. {
  131. $data = array('key' => $key, $iterator => $value);
  132. $result .= $this->make($view, $data)->render();
  133. }
  134. }
  135. // If there is no data in the array, we will render the contents of the empty
  136. // view. Alternatively, the "empty view" could be a raw string that begins
  137. // with "raw|" for convenience and to let this know that it is a string.
  138. else
  139. {
  140. if (starts_with($empty, 'raw|'))
  141. {
  142. $result = substr($empty, 4);
  143. }
  144. else
  145. {
  146. $result = $this->make($empty)->render();
  147. }
  148. }
  149. return $result;
  150. }
  151. /**
  152. * Get the appropriate view engine for the given path.
  153. *
  154. * @param string $path
  155. * @return \Illuminate\View\Engines\EngineInterface
  156. */
  157. protected function getEngineFromPath($path)
  158. {
  159. $engine = $this->extensions[$this->getExtension($path)];
  160. return $this->engines->resolve($engine);
  161. }
  162. /**
  163. * Get the extension used by the view file.
  164. *
  165. * @param string $path
  166. * @return string
  167. */
  168. protected function getExtension($path)
  169. {
  170. $extensions = array_keys($this->extensions);
  171. return array_first($extensions, function($key, $value) use ($path)
  172. {
  173. return ends_with($path, $value);
  174. });
  175. }
  176. /**
  177. * Add a piece of shared data to the environment.
  178. *
  179. * @param string $key
  180. * @param mixed $value
  181. * @return void
  182. */
  183. public function share($key, $value)
  184. {
  185. $this->shared[$key] = $value;
  186. }
  187. /**
  188. * Register a view composer event.
  189. *
  190. * @param array|string $views
  191. * @param Closure|string $callback
  192. * @return Closure
  193. */
  194. public function composer($views, $callback)
  195. {
  196. $composers = array();
  197. foreach ((array) $views as $view)
  198. {
  199. $composers[] = $this->addComposer($view, $callback);
  200. }
  201. return $composers;
  202. }
  203. /**
  204. * Add a composer for a given view.
  205. *
  206. * @param string $view
  207. * @param Closure|string $callback
  208. * @return Closure
  209. */
  210. protected function addComposer($view, $callback)
  211. {
  212. if ($callback instanceof Closure)
  213. {
  214. $this->events->listen('composing: '.$view, $callback);
  215. return $callback;
  216. }
  217. elseif (is_string($callback))
  218. {
  219. return $this->addClassComposer($view, $callback);
  220. }
  221. }
  222. /**
  223. * Register a class based view composer.
  224. *
  225. * @param string $view
  226. * @param string $class
  227. * @return Closure
  228. */
  229. protected function addClassComposer($view, $class)
  230. {
  231. $name = 'composing: '.$view;
  232. // When registering a class based view "composer", we will simply resolve the
  233. // classes from the application IoC container then call the compose method
  234. // on the instance. This allows for convenient, testable view composers.
  235. $callback = $this->buildClassComposerCallback($class);
  236. $this->events->listen($name, $callback);
  237. return $callback;
  238. }
  239. /**
  240. * Build a class based container callback Closure.
  241. *
  242. * @param string $class
  243. * @return Closure
  244. */
  245. protected function buildClassComposerCallback($class)
  246. {
  247. $container = $this->container;
  248. list($class, $method) = $this->parseClassComposer($class);
  249. // Once we have the class and method name, we can build the Closure to resolve
  250. // the instance out of the IoC container and call the method on it with the
  251. // given arguments that are passed to the Closure as the composer's data.
  252. return function() use ($class, $method, $container)
  253. {
  254. $callable = array($container->make($class), $method);
  255. return call_user_func_array($callable, func_get_args());
  256. };
  257. }
  258. /**
  259. * Parse a class based composer name.
  260. *
  261. * @param string $class
  262. * @return array
  263. */
  264. protected function parseClassComposer($class)
  265. {
  266. return str_contains($class, '@') ? explode('@', $class) : array($class, 'compose');
  267. }
  268. /**
  269. * Call the composer for a given view.
  270. *
  271. * @param \Illuminate\View\View $view
  272. * @return void
  273. */
  274. public function callComposer(View $view)
  275. {
  276. $this->events->fire('composing: '.$view->getName(), array($view));
  277. }
  278. /**
  279. * Start injecting content into a section.
  280. *
  281. * @param string $section
  282. * @param string $content
  283. * @return void
  284. */
  285. public function startSection($section, $content = '')
  286. {
  287. if ($content === '')
  288. {
  289. ob_start() and $this->sectionStack[] = $section;
  290. }
  291. else
  292. {
  293. $this->extendSection($section, $content);
  294. }
  295. }
  296. /**
  297. * Inject inline content into a section.
  298. *
  299. * @param string $section
  300. * @param string $content
  301. * @return void
  302. */
  303. public function inject($section, $content)
  304. {
  305. return $this->startSection($section, $content);
  306. }
  307. /**
  308. * Stop injecting content into a section and return its contents.
  309. *
  310. * @return string
  311. */
  312. public function yieldSection()
  313. {
  314. return $this->yieldContent($this->stopSection());
  315. }
  316. /**
  317. * Stop injecting content into a section.
  318. *
  319. * @return string
  320. */
  321. public function stopSection()
  322. {
  323. $last = array_pop($this->sectionStack);
  324. $this->extendSection($last, ob_get_clean());
  325. return $last;
  326. }
  327. /**
  328. * Append content to a given section.
  329. *
  330. * @param string $section
  331. * @param string $content
  332. * @return void
  333. */
  334. protected function extendSection($section, $content)
  335. {
  336. if (isset($this->sections[$section]))
  337. {
  338. $content = str_replace('@parent', $content, $this->sections[$section]);
  339. $this->sections[$section] = $content;
  340. }
  341. else
  342. {
  343. $this->sections[$section] = $content;
  344. }
  345. }
  346. /**
  347. * Get the string contents of a section.
  348. *
  349. * @param string $section
  350. * @return string
  351. */
  352. public function yieldContent($section)
  353. {
  354. return isset($this->sections[$section]) ? $this->sections[$section] : '';
  355. }
  356. /**
  357. * Flush all of the section contents.
  358. *
  359. * @return void
  360. */
  361. public function flushSections()
  362. {
  363. $this->sections = array();
  364. $this->sectionStack = array();
  365. }
  366. /**
  367. * Increment the rendering counter.
  368. *
  369. * @return void
  370. */
  371. public function incrementRender()
  372. {
  373. $this->renderCount++;
  374. }
  375. /**
  376. * Decrement the rendering counter.
  377. *
  378. * @return void
  379. */
  380. public function decrementRender()
  381. {
  382. $this->renderCount--;
  383. }
  384. /**
  385. * Check if there are no active render operations.
  386. *
  387. * @return bool
  388. */
  389. public function doneRendering()
  390. {
  391. return $this->renderCount == 0;
  392. }
  393. /**
  394. * Add a location to the array of view locations.
  395. *
  396. * @param string $location
  397. * @return void
  398. */
  399. public function addLocation($location)
  400. {
  401. $this->finder->addLocation($location);
  402. }
  403. /**
  404. * Add a new namespace to the loader.
  405. *
  406. * @param string $namespace
  407. * @param string|array $hints
  408. * @return void
  409. */
  410. public function addNamespace($namespace, $hints)
  411. {
  412. $this->finder->addNamespace($namespace, $hints);
  413. }
  414. /**
  415. * Register a valid view extension and its engine.
  416. *
  417. * @param string $extension
  418. * @param string $engine
  419. * @param Closure $resolver
  420. * @return void
  421. */
  422. public function addExtension($extension, $engine, $resolver = null)
  423. {
  424. $this->finder->addExtension($extension);
  425. if (isset($resolver))
  426. {
  427. $this->engines->register($engine, $resolver);
  428. }
  429. unset($this->extensions[$engine]);
  430. $this->extensions = array_merge(array($extension => $engine), $this->extensions);
  431. }
  432. /**
  433. * Get the extension to engine bindings.
  434. *
  435. * @return array
  436. */
  437. public function getExtensions()
  438. {
  439. return $this->extensions;
  440. }
  441. /**
  442. * Get the engine resolver instance.
  443. *
  444. * @return \Illuminate\View\Engines\EngineResolver
  445. */
  446. public function getEngineResolver()
  447. {
  448. return $this->engines;
  449. }
  450. /**
  451. * Get the view finder instance.
  452. *
  453. * @return \Illuminate\View\ViewFinderInterface
  454. */
  455. public function getFinder()
  456. {
  457. return $this->finder;
  458. }
  459. /**
  460. * Get the event dispatcher instance.
  461. *
  462. * @return \Illuminate\Events\Dispatcher
  463. */
  464. public function getDispatcher()
  465. {
  466. return $this->events;
  467. }
  468. /**
  469. * Get the IoC container instance.
  470. *
  471. * @return \Illuminate\Container\Container
  472. */
  473. public function getContainer()
  474. {
  475. return $this->container;
  476. }
  477. /**
  478. * Set the IoC container instance.
  479. *
  480. * @param \Illuminate\Container\Container $container
  481. * @return void
  482. */
  483. public function setContainer(Container $container)
  484. {
  485. $this->container = $container;
  486. }
  487. /**
  488. * Get all of the shared data for the environment.
  489. *
  490. * @return array
  491. */
  492. public function getShared()
  493. {
  494. return $this->shared;
  495. }
  496. /**
  497. * Get the entire array of sections.
  498. *
  499. * @return array
  500. */
  501. public function getSections()
  502. {
  503. return $this->sections;
  504. }
  505. }