PageRenderTime 25ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/classes/view.php

https://github.com/joshuarubin/fuel_core
PHP | 423 lines | 166 code | 49 blank | 208 comment | 12 complexity | 697b5a74adac23a4e1d0163e51060db2 MD5 | raw file
  1. <?php
  2. /**
  3. * Fuel is a fast, lightweight, community driven PHP5 framework.
  4. *
  5. * @package Fuel
  6. * @version 1.0
  7. * @author Fuel Development Team
  8. * @license MIT License
  9. * @copyright 2010 - 2011 Fuel Development Team
  10. * @link http://fuelphp.com
  11. */
  12. namespace Fuel\Core;
  13. /**
  14. * View class
  15. *
  16. * Acts as an object wrapper for HTML pages with embedded PHP, called "views".
  17. * Variables can be assigned with the view object and referenced locally within
  18. * the view.
  19. *
  20. * NOTE: This class has been taken from the Kohana framework and slightly modified,
  21. * but on the whole all credit goes to them. Over time this will be worked on.
  22. *
  23. * @package Fuel
  24. * @category Core
  25. * @author Kohana Team
  26. * @modified Phil Sturgeon - Fuel Development Team
  27. * @copyright (c) 2008-2010 Kohana Team
  28. * @license http://kohanaframework.org/license
  29. * @link http://fuelphp.com/docs/classes/view.html
  30. */
  31. class View {
  32. // array of global view data
  33. protected static $_global_data = array();
  34. // Current active search paths
  35. protected $request_paths = array();
  36. // Output encoding setting
  37. public static $auto_encode = true;
  38. // View filename
  39. protected $_file;
  40. // array of local variables
  41. protected $_data = array();
  42. // File extension used for views
  43. protected $extension = 'php';
  44. /*
  45. * initialisation and auto configuration
  46. */
  47. public static function _init()
  48. {
  49. static::$auto_encode = \Config::get('security.auto_encode_view_data', true);
  50. }
  51. /**
  52. * Returns a new View object. If you do not define the "file" parameter,
  53. * you must call [static::set_filename].
  54. *
  55. * $view = View::factory($file);
  56. *
  57. * @param string view filename
  58. * @param array array of values
  59. * @return View
  60. */
  61. public static function factory($file = null, array $data = null, $auto_encode = null)
  62. {
  63. return new static($file, $data, $auto_encode);
  64. }
  65. /**
  66. * Sets the initial view filename and local data.
  67. *
  68. * $view = new View($file);
  69. *
  70. * @param string view filename
  71. * @param array array of values
  72. * @return void
  73. * @uses View::set_filename
  74. */
  75. public function __construct($file = null, array $data = null, $encode = null)
  76. {
  77. $encode === null and $encode = static::$auto_encode;
  78. if ($file !== null)
  79. {
  80. $this->set_filename($file);
  81. }
  82. if ($data !== null)
  83. {
  84. if ($encode)
  85. {
  86. foreach ($data as $k => $v)
  87. {
  88. $data[$k] = \Security::htmlentities($v);
  89. }
  90. }
  91. // Add the values to the current data
  92. $this->_data = $data + $this->_data;
  93. }
  94. // store the current request search paths to deal with out-of-context rendering
  95. if (class_exists('Request', false) and $active = \Request::active() and \Request::main() != $active)
  96. {
  97. $this->request_paths = $active->get_paths();
  98. }
  99. }
  100. /**
  101. * Magic method, searches for the given variable and returns its value.
  102. * Local variables will be returned before global variables.
  103. *
  104. * $value = $view->foo;
  105. *
  106. * [!!] If the variable has not yet been set, an exception will be thrown.
  107. *
  108. * @param string variable name
  109. * @return mixed
  110. * @throws OutOfBoundsException
  111. */
  112. public function & __get($key)
  113. {
  114. if (array_key_exists($key, $this->_data))
  115. {
  116. return $this->_data[$key];
  117. }
  118. elseif (array_key_exists($key, static::$_global_data))
  119. {
  120. return static::$_global_data[$key];
  121. }
  122. else
  123. {
  124. throw new \OutOfBoundsException('View variable is not set: '.$key);
  125. }
  126. }
  127. /**
  128. * Magic method, calls [static::set] with the same parameters.
  129. *
  130. * $view->foo = 'something';
  131. *
  132. * @param string variable name
  133. * @param mixed value
  134. * @return void
  135. */
  136. public function __set($key, $value)
  137. {
  138. $this->set($key, $value, static::$auto_encode);
  139. }
  140. /**
  141. * Magic method, determines if a variable is set.
  142. *
  143. * isset($view->foo);
  144. *
  145. * [!!] `null` variables are not considered to be set by [isset](http://php.net/isset).
  146. *
  147. * @param string variable name
  148. * @return boolean
  149. */
  150. public function __isset($key)
  151. {
  152. return (isset($this->_data[$key]) or isset(static::$_global_data[$key]));
  153. }
  154. /**
  155. * Magic method, unsets a given variable.
  156. *
  157. * unset($view->foo);
  158. *
  159. * @param string variable name
  160. * @return void
  161. */
  162. public function __unset($key)
  163. {
  164. unset($this->_data[$key], static::$_global_data[$key]);
  165. }
  166. /**
  167. * Magic method, returns the output of [static::render].
  168. *
  169. * @return string
  170. * @uses View::render
  171. */
  172. public function __toString()
  173. {
  174. try
  175. {
  176. return $this->render();
  177. }
  178. catch (\Exception $e)
  179. {
  180. \Error::exception_handler($e);
  181. return '';
  182. }
  183. }
  184. /**
  185. * Captures the output that is generated when a view is included.
  186. * The view data will be extracted to make local variables. This method
  187. * is static to prevent object scope resolution.
  188. *
  189. * $output = View::capture($file, $data);
  190. *
  191. * @param string filename
  192. * @param array variables
  193. * @return string
  194. */
  195. protected static function capture($view_filename, array $view_data)
  196. {
  197. // Import the view variables to local namespace
  198. $view_data AND extract($view_data, EXTR_SKIP);
  199. if (static::$_global_data)
  200. {
  201. // Import the global view variables to local namespace and maintain references
  202. extract(static::$_global_data, EXTR_REFS);
  203. }
  204. // Capture the view output
  205. ob_start();
  206. try
  207. {
  208. // Load the view within the current scope
  209. include $view_filename;
  210. }
  211. catch (\Exception $e)
  212. {
  213. // Delete the output buffer
  214. ob_end_clean();
  215. // Re-throw the exception
  216. throw $e;
  217. }
  218. // Get the captured output and close the buffer
  219. return ob_get_clean();
  220. }
  221. /**
  222. * Sets a global variable, similar to [static::set], except that the
  223. * variable will be accessible to all views.
  224. *
  225. * View::set_global($name, $value);
  226. *
  227. * @param string variable name or an array of variables
  228. * @param mixed value
  229. * @param bool whether to encode the data or not
  230. * @return void
  231. */
  232. public static function set_global($key, $value = null, $encode = null)
  233. {
  234. $encode === null and $encode = static::$auto_encode;
  235. if (is_array($key))
  236. {
  237. foreach ($key as $key2 => $value)
  238. {
  239. static::$_global_data[$key2] = $encode ? \Security::htmlentities($value) : $value;
  240. }
  241. }
  242. else
  243. {
  244. static::$_global_data[$key] = $encode ? \Security::htmlentities($value) : $value;
  245. }
  246. }
  247. /**
  248. * Assigns a global variable by reference, similar to [static::bind], except
  249. * that the variable will be accessible to all views.
  250. *
  251. * View::bind_global($key, $value);
  252. *
  253. * @param string variable name
  254. * @param mixed referenced variable
  255. * @return void
  256. */
  257. public static function bind_global($key, & $value)
  258. {
  259. static::$_global_data[$key] =& $value;
  260. }
  261. /**
  262. * Sets whether to encode the data or not.
  263. *
  264. * $view->auto_encode(false);
  265. *
  266. * @param bool whether to auto encode or not
  267. * @return View
  268. */
  269. public function auto_encode($encode = true)
  270. {
  271. static::$auto_encode = $encode;
  272. return $this;
  273. }
  274. /**
  275. * Sets the view filename.
  276. *
  277. * $view->set_filename($file);
  278. *
  279. * @param string view filename
  280. * @return View
  281. * @throws Fuel_Exception
  282. */
  283. public function set_filename($file)
  284. {
  285. // set find_file's one-time-only search paths
  286. \Fuel::$volatile_paths = $this->request_paths;
  287. // locate the view file
  288. if (($path = \Fuel::find_file('views', $file, '.'.$this->extension, false, false)) === false)
  289. {
  290. throw new \Fuel_Exception('The requested view could not be found: '.\Fuel::clean_path($file));
  291. }
  292. // Store the file path locally
  293. $this->_file = $path;
  294. return $this;
  295. }
  296. /**
  297. * Assigns a variable by name. Assigned values will be available as a
  298. * variable within the view file:
  299. *
  300. * // This value can be accessed as $foo within the view
  301. * $view->set('foo', 'my value');
  302. *
  303. * You can also use an array to set several values at once:
  304. *
  305. * // Create the values $food and $beverage in the view
  306. * $view->set(array('food' => 'bread', 'beverage' => 'water'));
  307. *
  308. * @param string variable name or an array of variables
  309. * @param mixed value
  310. * @param bool whether to encode the data or not
  311. * @return $this
  312. */
  313. public function set($key, $value = null, $encode = null)
  314. {
  315. $encode === null and $encode = static::$auto_encode;
  316. if (is_array($key))
  317. {
  318. foreach ($key as $name => $value)
  319. {
  320. $this->_data[$name] = $encode ? \Security::htmlentities($value) : $value;
  321. }
  322. }
  323. else
  324. {
  325. $this->_data[$key] = $encode ? \Security::htmlentities($value) : $value;
  326. }
  327. return $this;
  328. }
  329. /**
  330. * Assigns a value by reference. The benefit of binding is that values can
  331. * be altered without re-setting them. It is also possible to bind variables
  332. * before they have values. Assigned values will be available as a
  333. * variable within the view file:
  334. *
  335. * // This reference can be accessed as $ref within the view
  336. * $view->bind('ref', $bar);
  337. *
  338. * @param string variable name
  339. * @param mixed referenced variable
  340. * @return $this
  341. */
  342. public function bind($key, & $value)
  343. {
  344. $this->_data[$key] =& $value;
  345. return $this;
  346. }
  347. /**
  348. * Renders the view object to a string. Global and local data are merged
  349. * and extracted to create local variables within the view file.
  350. *
  351. * $output = $view->render();
  352. *
  353. * [!!] Global variables with the same key name as local variables will be
  354. * overwritten by the local variable.
  355. *
  356. * @param string view filename
  357. * @return string
  358. * @throws Fuel_Exception
  359. * @uses static::capture
  360. */
  361. public function render($file = null)
  362. {
  363. if ($file !== null)
  364. {
  365. $this->set_filename($file);
  366. }
  367. if (empty($this->_file))
  368. {
  369. throw new \Fuel_Exception('You must set the file to use within your view before rendering');
  370. }
  371. // Combine local and global data and capture the output
  372. return static::capture($this->_file, $this->_data);
  373. }
  374. }