PageRenderTime 35ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/laravel/view.php

http://github.com/ericbarnes/Status-Board
PHP | 390 lines | 132 code | 40 blank | 218 comment | 7 complexity | 59e00537d49ac37fe0ae1fe4f00bcda2 MD5 | raw file
Possible License(s): MIT
  1. <?php namespace Laravel; use Closure, ArrayAccess;
  2. class View implements ArrayAccess {
  3. /**
  4. * The name of the view.
  5. *
  6. * @var string
  7. */
  8. public $view;
  9. /**
  10. * The view data.
  11. *
  12. * @var array
  13. */
  14. public $data;
  15. /**
  16. * The path to the view on disk.
  17. *
  18. * @var string
  19. */
  20. public $path;
  21. /**
  22. * All of the shared view data.
  23. *
  24. * @var array
  25. */
  26. public static $shared = array();
  27. /**
  28. * All of the registered view names.
  29. *
  30. * @var array
  31. */
  32. public static $names = array();
  33. /**
  34. * Create a new view instance.
  35. *
  36. * <code>
  37. * // Create a new view instance
  38. * $view = new View('home.index');
  39. *
  40. * // Create a new view instance of a bundle's view
  41. * $view = new View('admin::home.index');
  42. *
  43. * // Create a new view instance with bound data
  44. * $view = new View('home.index', array('name' => 'Taylor'));
  45. * </code>
  46. *
  47. * @param string $view
  48. * @param array $data
  49. * @return void
  50. */
  51. public function __construct($view, $data = array())
  52. {
  53. $this->view = $view;
  54. $this->data = $data;
  55. $this->path = $this->path($view);
  56. // If a session driver has been specified, we will bind an instance of the
  57. // validation error message container to every view. If an errors instance
  58. // exists in the session, we will use that instance.
  59. //
  60. // This makes error display in the view extremely convenient, since the
  61. // developer can always assume they have a message container instance
  62. // available to them in the view's variables.
  63. if ( ! isset($this->data['errors']))
  64. {
  65. if (Session::started() and Session::has('errors'))
  66. {
  67. $this->data['errors'] = Session::get('errors');
  68. }
  69. else
  70. {
  71. $this->data['errors'] = new Messages;
  72. }
  73. }
  74. }
  75. /**
  76. * Get the path to a given view on disk.
  77. *
  78. * @param string $view
  79. * @return string
  80. */
  81. protected function path($view)
  82. {
  83. $view = str_replace('.', '/', $view);
  84. $root = Bundle::path(Bundle::name($view)).'views/';
  85. // Views may have the normal PHP extension or the Blade PHP extension, so
  86. // we need to check if either of them exist in the base views directory
  87. // for the bundle and return the first one we find.
  88. foreach (array(EXT, BLADE_EXT) as $extension)
  89. {
  90. if (file_exists($path = $root.Bundle::element($view).$extension))
  91. {
  92. return $path;
  93. }
  94. }
  95. throw new \Exception("View [$view] does not exist.");
  96. }
  97. /**
  98. * Create a new view instance.
  99. *
  100. * <code>
  101. * // Create a new view instance
  102. * $view = View::make('home.index');
  103. *
  104. * // Create a new view instance of a bundle's view
  105. * $view = View::make('admin::home.index');
  106. *
  107. * // Create a new view instance with bound data
  108. * $view = View::make('home.index', array('name' => 'Taylor'));
  109. * </code>
  110. *
  111. * @param string $view
  112. * @param array $data
  113. * @return View
  114. */
  115. public static function make($view, $data = array())
  116. {
  117. return new static($view, $data);
  118. }
  119. /**
  120. * Create a new view instance of a named view.
  121. *
  122. * <code>
  123. * // Create a new named view instance
  124. * $view = View::of('profile');
  125. *
  126. * // Create a new named view instance with bound data
  127. * $view = View::of('profile', array('name' => 'Taylor'));
  128. * </code>
  129. *
  130. * @param string $name
  131. * @param array $data
  132. * @return View
  133. */
  134. public static function of($name, $data = array())
  135. {
  136. return new static(static::$names[$name], $data);
  137. }
  138. /**
  139. * Assign a name to a view.
  140. *
  141. * <code>
  142. * // Assign a name to a view
  143. * View::name('partials.profile', 'profile');
  144. *
  145. * // Resolve an instance of a named view
  146. * $view = View::of('profile');
  147. * </code>
  148. *
  149. * @param string $view
  150. * @param string $name
  151. * @return void
  152. */
  153. public static function name($view, $name)
  154. {
  155. static::$names[$name] = $view;
  156. }
  157. /**
  158. * Register a view composer with the Event class.
  159. *
  160. * <code>
  161. * // Register a composer for the "home.index" view
  162. * View::composer('home.index', function($view)
  163. * {
  164. * $view['title'] = 'Home';
  165. * });
  166. * </code>
  167. *
  168. * @param string $view
  169. * @param Closure $composer
  170. * @return void
  171. */
  172. public static function composer($view, $composer)
  173. {
  174. Event::listen("laravel.composing: {$view}", $composer);
  175. }
  176. /**
  177. * Get the evaluated string content of the view.
  178. *
  179. * @return string
  180. */
  181. public function render()
  182. {
  183. // To allow bundles or other pieces of the application to modify the
  184. // view before it is rendered, we will fire an event, passing in the
  185. // view instance so it can modified.
  186. Event::fire("laravel.composing: {$this->view}", array($this));
  187. $data = $this->data();
  188. ob_start() and extract($data, EXTR_SKIP);
  189. // If the view is Bladed, we need to check the view for changes and
  190. // get the path to the compiled view file. Otherwise, we'll just
  191. // use the regular path to the view.
  192. //
  193. // Also, if the Blade view has expired or doesn't exist it will be
  194. // re-compiled and placed in the view storage directory. The Blade
  195. // views are re-compiled the original view changes.
  196. if (strpos($this->path, BLADE_EXT) !== false)
  197. {
  198. $this->path = $this->compile();
  199. }
  200. try {include $this->path;} catch(\Exception $e) {ob_get_clean(); throw $e;}
  201. return ob_get_clean();
  202. }
  203. /**
  204. * Get the array of view data for the view instance.
  205. *
  206. * The shared view data will be combined with the view data for the instance.
  207. *
  208. * @return array
  209. */
  210. protected function data()
  211. {
  212. $data = array_merge($this->data, static::$shared);
  213. // All nested views and responses are evaluated before the main view.
  214. // This allows the assets used by nested views to be added to the
  215. // asset container before the main view is evaluated.
  216. foreach ($data as &$value)
  217. {
  218. if ($value instanceof View or $value instanceof Response)
  219. {
  220. $value = $value->render();
  221. }
  222. }
  223. return $data;
  224. }
  225. /**
  226. * Get the path to the compiled version of the Blade view.
  227. *
  228. * @return string
  229. */
  230. protected function compile()
  231. {
  232. // Compiled views are stored in the storage directory using the MD5
  233. // hash of their path. This allows us to easily store the views in
  234. // the directory without worrying about structure.
  235. $compiled = path('storage').'views/'.md5($this->path);
  236. // The view will only be re-compiled if the view has been modified
  237. // since the last compiled version of the view was created or no
  238. // compiled view exists at all in storage.
  239. if ( ! file_exists($compiled) or (filemtime($this->path) > filemtime($compiled)))
  240. {
  241. file_put_contents($compiled, Blade::compile($this->path));
  242. }
  243. return $compiled;
  244. }
  245. /**
  246. * Add a view instance to the view data.
  247. *
  248. * <code>
  249. * // Add a view instance to a view's data
  250. * $view = View::make('foo')->nest('footer', 'partials.footer');
  251. *
  252. * // Equivalent functionality using the "with" method
  253. * $view = View::make('foo')->with('footer', View::make('partials.footer'));
  254. * </code>
  255. *
  256. * @param string $key
  257. * @param string $view
  258. * @param array $data
  259. * @return View
  260. */
  261. public function nest($key, $view, $data = array())
  262. {
  263. return $this->with($key, static::make($view, $data));
  264. }
  265. /**
  266. * Add a key / value pair to the view data.
  267. *
  268. * Bound data will be available to the view as variables.
  269. *
  270. * @param string $key
  271. * @param mixed $value
  272. * @return View
  273. */
  274. public function with($key, $value)
  275. {
  276. $this->data[$key] = $value;
  277. return $this;
  278. }
  279. /**
  280. * Add a key / value pair to the shared view data.
  281. *
  282. * Shared view data is accessible to every view created by the application.
  283. *
  284. * @param string $key
  285. * @param mixed $value
  286. * @return void
  287. */
  288. public static function share($key, $value)
  289. {
  290. static::$shared[$key] = $value;
  291. }
  292. /**
  293. * Implementation of the ArrayAccess offsetExists method.
  294. */
  295. public function offsetExists($offset)
  296. {
  297. return array_key_exists($offset, $this->data);
  298. }
  299. /**
  300. * Implementation of the ArrayAccess offsetGet method.
  301. */
  302. public function offsetGet($offset)
  303. {
  304. if (isset($this[$offset])) return $this->data[$offset];
  305. }
  306. /**
  307. * Implementation of the ArrayAccess offsetSet method.
  308. */
  309. public function offsetSet($offset, $value)
  310. {
  311. $this->data[$offset] = $value;
  312. }
  313. /**
  314. * Implementation of the ArrayAccess offsetUnset method.
  315. */
  316. public function offsetUnset($offset)
  317. {
  318. unset($this->data[$offset]);
  319. }
  320. /**
  321. * Magic Method for handling dynamic data access.
  322. */
  323. public function __get($key)
  324. {
  325. return $this->data[$key];
  326. }
  327. /**
  328. * Magic Method for handling the dynamic setting of data.
  329. */
  330. public function __set($key, $value)
  331. {
  332. $this->data[$key] = $value;
  333. }
  334. /**
  335. * Magic Method for checking dynamically-set data.
  336. */
  337. public function __isset($key)
  338. {
  339. return isset($this->data[$key]);
  340. }
  341. /**
  342. * Get the evaluated string content of the view.
  343. *
  344. * @return string
  345. */
  346. public function __toString()
  347. {
  348. return $this->render();
  349. }
  350. }