1<?php defined('SYSPATH') OR die('No direct access allowed.');
2/**
3 * Loads and displays Kohana view files. Can also handle output of some binary
4 * files, such as image, Javascript, and CSS files.
5 *
6 * $Id: View.php 4072 2009-03-13 17:20:38Z jheathco $
7 *
8 * @package    Core
9 * @author     Kohana Team
10 * @copyright  (c) 2007-2008 Kohana Team
11 * @license    http://kohanaphp.com/license.html
12 */
13class View_Core {
14
15	// The view file name and type
16	protected $kohana_filename = FALSE;
17	protected $kohana_filetype = FALSE;
18
19	// View variable storage
20	protected $kohana_local_data = array();
21	protected static $kohana_global_data = array();
22
23	/**
24	 * Creates a new View using the given parameters.
25	 *
26	 * @param   string  view name
27	 * @param   array   pre-load data
28	 * @param   string  type of file: html, css, js, etc.
29	 * @return  object
30	 */
31	public static function factory($name = NULL, $data = NULL, $type = NULL)
32	{
33		return new View($name, $data, $type);
34	}
35
36	/**
37	 * Attempts to load a view and pre-load view data.
38	 *
39	 * @throws  Kohana_Exception  if the requested view cannot be found
40	 * @param   string  view name
41	 * @param   array   pre-load data
42	 * @param   string  type of file: html, css, js, etc.
43	 * @return  void
44	 */
45	public function __construct($name = NULL, $data = NULL, $type = NULL)
46	{
47		if (is_string($name) AND $name !== '')
48		{
49			// Set the filename
50			$this->set_filename($name, $type);
51		}
52
53		if (is_array($data) AND ! empty($data))
54		{
55			// Preload data using array_merge, to allow user extensions
56			$this->kohana_local_data = array_merge($this->kohana_local_data, $data);
57		}
58	}
59
60	/**
61	 * Magic method access to test for view property
62	 *
63	 * @param   string   View property to test for
64	 * @return  boolean
65	 */
66	public function __isset($key = NULL)
67	{
68		return $this->is_set($key);
69	}
70
71	/**
72	 * Sets the view filename.
73	 *
74	 * @chainable
75	 * @param   string  view filename
76	 * @param   string  view file type
77	 * @return  object
78	 */
79	public function set_filename($name, $type = NULL)
80	{
81		if ($type == NULL)
82		{
83			// Load the filename and set the content type
84			$this->kohana_filename = Kohana::find_file('views', $name, TRUE);
85			$this->kohana_filetype = EXT;
86		}
87		else
88		{
89			// Check if the filetype is allowed by the configuration
90			if ( ! in_array($type, Kohana::config('view.allowed_filetypes')))
91				throw new Kohana_Exception('core.invalid_filetype', $type);
92
93			// Load the filename and set the content type
94			$this->kohana_filename = Kohana::find_file('views', $name, TRUE, $type);
95			$this->kohana_filetype = Kohana::config('mimes.'.$type);
96
97			if ($this->kohana_filetype == NULL)
98			{
99				// Use the specified type
100				$this->kohana_filetype = $type;
101			}
102		}
103
104		return $this;
105	}
106
107	/**
108	 * Sets a view variable.
109	 *
110	 * @param   string|array  name of variable or an array of variables
111	 * @param   mixed         value when using a named variable
112	 * @return  object
113	 */
114	public function set($name, $value = NULL)
115	{
116		if (is_array($name))
117		{
118			foreach ($name as $key => $value)
119			{
120				$this->__set($key, $value);
121			}
122		}
123		else
124		{
125			$this->__set($name, $value);
126		}
127
128		return $this;
129	}
130
131	/**
132	 * Checks for a property existence in the view locally or globally. Unlike the built in __isset(),
133	 * this method can take an array of properties to test simultaneously.
134	 *
135	 * @param string $key property name to test for
136	 * @param array $key array of property names to test for
137	 * @return boolean property test result
138	 * @return array associative array of keys and boolean test result
139	 */
140	public function is_set( $key = FALSE )
141	{
142		// Setup result;
143		$result = FALSE;
144
145		// If key is an array
146		if (is_array($key))
147		{
148			// Set the result to an array
149			$result = array();
150
151			// Foreach key
152			foreach ($key as $property)
153			{
154				// Set the result to an associative array
155				$result[$property] = (array_key_exists($property, $this->kohana_local_data) OR array_key_exists($property, View::$kohana_global_data)) ? TRUE : FALSE;
156			}
157		}
158		else
159		{
160			// Otherwise just check one property
161			$result = (array_key_exists($key, $this->kohana_local_data) OR array_key_exists($key, View::$kohana_global_data)) ? TRUE : FALSE;
162		}
163
164		// Return the result
165		return $result;
166	}
167
168	/**
169	 * Sets a bound variable by reference.
170	 *
171	 * @param   string   name of variable
172	 * @param   mixed    variable to assign by reference
173	 * @return  object
174	 */
175	public function bind($name, & $var)
176	{
177		$this->kohana_local_data[$name] =& $var;
178
179		return $this;
180	}
181
182	/**
183	 * Sets a view global variable.
184	 *
185	 * @param   string|array  name of variable or an array of variables
186	 * @param   mixed         value when using a named variable
187	 * @return  void
188	 */
189	public static function set_global($name, $value = NULL)
190	{
191		if (is_array($name))
192		{
193			foreach ($name as $key => $value)
194			{
195				View::$kohana_global_data[$key] = $value;
196			}
197		}
198		else
199		{
200			View::$kohana_global_data[$name] = $value;
201		}
202	}
203
204	/**
205	 * Magically sets a view variable.
206	 *
207	 * @param   string   variable key
208	 * @param   string   variable value
209	 * @return  void
210	 */
211	public function __set($key, $value)
212	{
213		$this->kohana_local_data[$key] = $value;
214	}
215
216	/**
217	 * Magically gets a view variable.
218	 *
219	 * @param  string  variable key
220	 * @return mixed   variable value if the key is found
221	 * @return void    if the key is not found
222	 */
223	public function &__get($key)
224	{
225		if (isset($this->kohana_local_data[$key]))
226			return $this->kohana_local_data[$key];
227
228		if (isset(View::$kohana_global_data[$key]))
229			return View::$kohana_global_data[$key];
230
231		if (isset($this->$key))
232			return $this->$key;
233	}
234
235	/**
236	 * Magically converts view object to string.
237	 *
238	 * @return  string
239	 */
240	public function __toString()
241	{
242		try
243		{
244			return $this->render();
245		}
246		catch (Exception $e)
247		{
248			// Display the exception using its internal __toString method
249			return (string) $e;
250		}
251	}
252
253	/**
254	 * Renders a view.
255	 *
256	 * @param   boolean   set to TRUE to echo the output instead of returning it
257	 * @param   callback  special renderer to pass the output through
258	 * @return  string    if print is FALSE
259	 * @return  void      if print is TRUE
260	 */
261	public function render($print = FALSE, $renderer = FALSE)
262	{
263		if (empty($this->kohana_filename))
264			throw new Kohana_Exception('core.view_set_filename');
265
266		if (is_string($this->kohana_filetype))
267		{
268			// Merge global and local data, local overrides global with the same name
269			$data = array_merge(View::$kohana_global_data, $this->kohana_local_data);
270
271			// Load the view in the controller for access to $this
272			$output = Kohana::$instance->_kohana_load_view($this->kohana_filename, $data);
273
274			if ($renderer !== FALSE AND is_callable($renderer, TRUE))
275			{
276				// Pass the output through the user defined renderer
277				$output = call_user_func($renderer, $output);
278			}
279
280			if ($print === TRUE)
281			{
282				// Display the output
283				echo $output;
284				return;
285			}
286		}
287		else
288		{
289			// Set the content type and size
290			header('Content-Type: '.$this->kohana_filetype[0]);
291
292			if ($print === TRUE)
293			{
294				if ($file = fopen($this->kohana_filename, 'rb'))
295				{
296					// Display the output
297					fpassthru($file);
298					fclose($file);
299				}
300				return;
301			}
302
303			// Fetch the file contents
304			$output = file_get_contents($this->kohana_filename);
305		}
306
307		return $output;
308	}
309} // End View