PageRenderTime 41ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/fuel/core/classes/view.php

https://github.com/mzkrelx/milm-search-ui-php
PHP | 550 lines | 239 code | 60 blank | 251 comment | 24 complexity | 1c3e7ab0bc769219cd3d4aa3b8f0f33f MD5 | raw file
  1. <?php
  2. /**
  3. * Part of the Fuel framework.
  4. *
  5. * @package Fuel
  6. * @version 1.0
  7. * @author Fuel Development Team
  8. * @license MIT License
  9. * @copyright 2010 - 2012 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. * @package Fuel
  21. * @category Core
  22. * @link http://docs.fuelphp.com/classes/view.html
  23. */
  24. class View
  25. {
  26. /**
  27. * @var array Global view data
  28. */
  29. protected static $global_data = array();
  30. /**
  31. * @var array Holds a list of specific filter rules for global variables
  32. */
  33. protected static $global_filter = array();
  34. /**
  35. * @var array Current active search paths
  36. */
  37. protected $request_paths = array();
  38. /**
  39. * @var bool Whether to auto-filter the view's data
  40. */
  41. protected $auto_filter = true;
  42. /**
  43. * @var array Holds a list of specific filter rules for local variables
  44. */
  45. protected $local_filter = array();
  46. /**
  47. * @var string The view's filename
  48. */
  49. protected $file_name;
  50. /**
  51. * @var array The view's data
  52. */
  53. protected $data = array();
  54. /**
  55. * @var string The view file extension
  56. */
  57. protected $extension = 'php';
  58. /**
  59. * @var Request active request when the View was created
  60. */
  61. protected $active_request;
  62. /**
  63. * Returns a new View object. If you do not define the "file" parameter,
  64. * you must call [static::set_filename].
  65. *
  66. * $view = View::forge($file);
  67. *
  68. * @param string view filename
  69. * @param array array of values
  70. * @return View
  71. */
  72. public static function forge($file = null, $data = null, $auto_filter = null)
  73. {
  74. return new static($file, $data, $auto_filter);
  75. }
  76. /**
  77. * Sets the initial view filename and local data.
  78. *
  79. * $view = new View($file);
  80. *
  81. * @param string view filename
  82. * @param array array of values
  83. * @return void
  84. * @uses View::set_filename
  85. */
  86. public function __construct($file = null, $data = null, $filter = null)
  87. {
  88. if (is_object($data) === true)
  89. {
  90. $data = get_object_vars($data);
  91. }
  92. elseif ($data and ! is_array($data))
  93. {
  94. throw new \InvalidArgumentException('The data parameter only accepts objects and arrays.');
  95. }
  96. // @TODO in v1.2 remove the auto_encode_view_data reference.
  97. $this->auto_filter = is_null($filter) ? \Config::get('security.auto_filter_output', \Config::get('security.auto_encode_view_data', true)) : $filter;
  98. if ($file !== null)
  99. {
  100. $this->set_filename($file);
  101. }
  102. if ($data !== null)
  103. {
  104. // Add the values to the current data
  105. $this->data = $data;
  106. }
  107. // store the current request search paths to deal with out-of-context rendering
  108. if (class_exists('Request', false) and $active = \Request::active() and \Request::main() != $active)
  109. {
  110. $this->request_paths = $active->get_paths();
  111. }
  112. isset($active) and $this->active_request = $active;
  113. }
  114. /**
  115. * Magic method, searches for the given variable and returns its value.
  116. * Local variables will be returned before global variables.
  117. *
  118. * $value = $view->foo;
  119. *
  120. * @param string variable name
  121. * @return mixed
  122. * @throws OutOfBoundsException
  123. */
  124. public function & __get($key)
  125. {
  126. return $this->get($key);
  127. }
  128. /**
  129. * Magic method, calls [static::set] with the same parameters.
  130. *
  131. * $view->foo = 'something';
  132. *
  133. * @param string variable name
  134. * @param mixed value
  135. * @return void
  136. */
  137. public function __set($key, $value)
  138. {
  139. $this->set($key, $value);
  140. }
  141. /**
  142. * Magic method, determines if a variable is set.
  143. *
  144. * isset($view->foo);
  145. *
  146. * [!!] `null` variables are not considered to be set by [isset](http://php.net/isset).
  147. *
  148. * @param string variable name
  149. * @return boolean
  150. */
  151. public function __isset($key)
  152. {
  153. return (isset($this->data[$key]) or isset(static::$global_data[$key]));
  154. }
  155. /**
  156. * Magic method, unsets a given variable.
  157. *
  158. * unset($view->foo);
  159. *
  160. * @param string variable name
  161. * @return void
  162. */
  163. public function __unset($key)
  164. {
  165. unset($this->data[$key], static::$global_data[$key]);
  166. }
  167. /**
  168. * Magic method, returns the output of [static::render].
  169. *
  170. * @return string
  171. * @uses View::render
  172. */
  173. public function __toString()
  174. {
  175. try
  176. {
  177. return $this->render();
  178. }
  179. catch (\Exception $e)
  180. {
  181. \Error::exception_handler($e);
  182. return '';
  183. }
  184. }
  185. /**
  186. * Captures the output that is generated when a view is included.
  187. * The view data will be extracted to make local variables. This method
  188. * is static to prevent object scope resolution.
  189. *
  190. * $output = $this->process_file();
  191. *
  192. * @param string File override
  193. * @param array variables
  194. * @return string
  195. */
  196. protected function process_file($file_override = false)
  197. {
  198. $clean_room = function($__file_name, array $__data)
  199. {
  200. extract($__data, EXTR_REFS);
  201. // Capture the view output
  202. ob_start();
  203. try
  204. {
  205. // Load the view within the current scope
  206. include $__file_name;
  207. }
  208. catch (\Exception $e)
  209. {
  210. // Delete the output buffer
  211. ob_end_clean();
  212. // Re-throw the exception
  213. throw $e;
  214. }
  215. // Get the captured output and close the buffer
  216. return ob_get_clean();
  217. };
  218. return $clean_room($file_override ?: $this->file_name, $this->get_data());
  219. }
  220. /**
  221. * Retrieves all the data, both local and global. It filters the data if
  222. * necessary.
  223. *
  224. * $data = $this->get_data();
  225. *
  226. * @param string $scope local/glocal/all
  227. * @return array view data
  228. */
  229. protected function get_data($scope = 'all')
  230. {
  231. $clean_it = function ($data, $rules, $auto_filter)
  232. {
  233. foreach ($data as $key => $value)
  234. {
  235. $filter = array_key_exists($key, $rules) ? $rules[$key] : null;
  236. $filter = is_null($filter) ? $auto_filter : $filter;
  237. $data[$key] = $filter ? \Security::clean($value, null, 'security.output_filter') : $value;
  238. }
  239. return $data;
  240. };
  241. $data = array();
  242. if ( ! empty($this->data) and ($scope === 'all' or $scope === 'local'))
  243. {
  244. $data += $clean_it($this->data, $this->local_filter, $this->auto_filter);
  245. }
  246. if ( ! empty(static::$global_data) and ($scope === 'all' or $scope === 'global'))
  247. {
  248. $data += $clean_it(static::$global_data, static::$global_filter, $this->auto_filter);
  249. }
  250. return $data;
  251. }
  252. /**
  253. * Sets a global variable, similar to [static::set], except that the
  254. * variable will be accessible to all views.
  255. *
  256. * View::set_global($name, $value);
  257. *
  258. * @param string variable name or an array of variables
  259. * @param mixed value
  260. * @param bool whether to filter the data or not
  261. * @return void
  262. */
  263. public static function set_global($key, $value = null, $filter = null)
  264. {
  265. if (is_array($key))
  266. {
  267. foreach ($key as $name => $value)
  268. {
  269. if ($filter !== null)
  270. {
  271. static::$global_filter[$name] = $filter;
  272. }
  273. static::$global_data[$name] = $value;
  274. }
  275. }
  276. else
  277. {
  278. if ($filter !== null)
  279. {
  280. static::$global_filter[$key] = $filter;
  281. }
  282. static::$global_data[$key] = $value;
  283. }
  284. }
  285. /**
  286. * Assigns a global variable by reference, similar to [static::bind], except
  287. * that the variable will be accessible to all views.
  288. *
  289. * View::bind_global($key, $value);
  290. *
  291. * @param string variable name
  292. * @param mixed referenced variable
  293. * @param bool whether to filter the data or not
  294. * @return void
  295. */
  296. public static function bind_global($key, &$value, $filter = null)
  297. {
  298. if ($filter !== null)
  299. {
  300. static::$global_filter[$key] = $filter;
  301. }
  302. static::$global_data[$key] =& $value;
  303. }
  304. /**
  305. * Sets whether to filter the data or not.
  306. *
  307. * $view->auto_filter(false);
  308. *
  309. * @param bool whether to auto filter or not
  310. * @return View
  311. */
  312. public function auto_filter($filter = true)
  313. {
  314. if (func_num_args() == 0)
  315. {
  316. return $this->auto_filter;
  317. }
  318. $this->auto_filter = $filter;
  319. return $this;
  320. }
  321. /**
  322. * Sets the view filename.
  323. *
  324. * $view->set_filename($file);
  325. *
  326. * @param string view filename
  327. * @return View
  328. * @throws FuelException
  329. */
  330. public function set_filename($file)
  331. {
  332. // set find_file's one-time-only search paths
  333. \Finder::instance()->flash($this->request_paths);
  334. // locate the view file
  335. if (($path = \Finder::search('views', $file, '.'.$this->extension, false, false)) === false)
  336. {
  337. throw new \FuelException('The requested view could not be found: '.\Fuel::clean_path($file));
  338. }
  339. // Store the file path locally
  340. $this->file_name = $path;
  341. return $this;
  342. }
  343. /**
  344. * Searches for the given variable and returns its value.
  345. * Local variables will be returned before global variables.
  346. *
  347. * $value = $view->get('foo', 'bar');
  348. *
  349. * If a default parameter is not given and the variable does not
  350. * exist, it will throw an OutOfBoundsException.
  351. *
  352. * @param string The variable name
  353. * @param mixed The default value to return
  354. * @return mixed
  355. * @throws OutOfBoundsException
  356. */
  357. public function &get($key, $default = null)
  358. {
  359. if (array_key_exists($key, $this->data))
  360. {
  361. return $this->data[$key];
  362. }
  363. elseif (array_key_exists($key, static::$global_data))
  364. {
  365. return static::$global_data[$key];
  366. }
  367. if (is_null($default) and func_num_args() === 1)
  368. {
  369. throw new \OutOfBoundsException('View variable is not set: '.$key);
  370. }
  371. else
  372. {
  373. return \Fuel::value($default);
  374. }
  375. }
  376. /**
  377. * Assigns a variable by name. Assigned values will be available as a
  378. * variable within the view file:
  379. *
  380. * // This value can be accessed as $foo within the view
  381. * $view->set('foo', 'my value');
  382. *
  383. * You can also use an array to set several values at once:
  384. *
  385. * // Create the values $food and $beverage in the view
  386. * $view->set(array('food' => 'bread', 'beverage' => 'water'));
  387. *
  388. * @param string variable name or an array of variables
  389. * @param mixed value
  390. * @param bool whether to filter the data or not
  391. * @return $this
  392. */
  393. public function set($key, $value = null, $filter = null)
  394. {
  395. if (is_array($key))
  396. {
  397. foreach ($key as $name => $value)
  398. {
  399. if ($filter !== null)
  400. {
  401. $this->local_filter[$name] = $filter;
  402. }
  403. $this->data[$name] = $value;
  404. }
  405. }
  406. else
  407. {
  408. if ($filter !== null)
  409. {
  410. $this->local_filter[$key] = $filter;
  411. }
  412. $this->data[$key] = $value;
  413. }
  414. return $this;
  415. }
  416. /**
  417. * The same as set(), except this defaults to not-encoding the variable
  418. * on output.
  419. *
  420. * $view->set_safe('foo', 'bar');
  421. *
  422. * @param string variable name or an array of variables
  423. * @param mixed value
  424. * @return $this
  425. */
  426. public function set_safe($key, $value = null)
  427. {
  428. return $this->set($key, $value, false);
  429. }
  430. /**
  431. * Assigns a value by reference. The benefit of binding is that values can
  432. * be altered without re-setting them. It is also possible to bind variables
  433. * before they have values. Assigned values will be available as a
  434. * variable within the view file:
  435. *
  436. * // This reference can be accessed as $ref within the view
  437. * $view->bind('ref', $bar);
  438. *
  439. * @param string variable name
  440. * @param mixed referenced variable
  441. * @param bool Whether to filter the var on output
  442. * @return $this
  443. */
  444. public function bind($key, &$value, $filter = null)
  445. {
  446. if ($filter !== null)
  447. {
  448. $this->local_filter[$key] = $filter;
  449. }
  450. $this->data[$key] =& $value;
  451. return $this;
  452. }
  453. /**
  454. * Renders the view object to a string. Global and local data are merged
  455. * and extracted to create local variables within the view file.
  456. *
  457. * $output = $view->render();
  458. *
  459. * [!!] Global variables with the same key name as local variables will be
  460. * overwritten by the local variable.
  461. *
  462. * @param string view filename
  463. * @return string
  464. * @throws FuelException
  465. * @uses static::capture
  466. */
  467. public function render($file = null)
  468. {
  469. if (class_exists('Request', false))
  470. {
  471. $current_request = \Request::active();
  472. \Request::active($this->active_request);
  473. }
  474. if ($file !== null)
  475. {
  476. $this->set_filename($file);
  477. }
  478. if (empty($this->file_name))
  479. {
  480. throw new \FuelException('You must set the file to use within your view before rendering');
  481. }
  482. // Combine local and global data and capture the output
  483. $return = $this->process_file();
  484. if (class_exists('Request', false))
  485. {
  486. \Request::active($current_request);
  487. }
  488. return $return;
  489. }
  490. }