Subversion-Projekte lars-tiefland.cakephp

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
/* SVN FILE: $Id: view.php 7961 2008-12-25 23:21:36Z gwoo $ */
3
/**
4
 * Methods for displaying presentation data in the view.
5
 *
6
 * PHP versions 4 and 5
7
 *
8
 * CakePHP(tm) :  Rapid Development Framework (http://www.cakephp.org)
9
 * Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
10
 *
11
 * Licensed under The MIT License
12
 * Redistributions of files must retain the above copyright notice.
13
 *
14
 * @filesource
15
 * @copyright     Copyright 2005-2008, Cake Software Foundation, Inc. (http://www.cakefoundation.org)
16
 * @link          http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project
17
 * @package       cake
18
 * @subpackage    cake.cake.libs.view
19
 * @since         CakePHP(tm) v 0.10.0.1076
20
 * @version       $Revision: 7961 $
21
 * @modifiedby    $LastChangedBy: gwoo $
22
 * @lastmodified  $Date: 2008-12-25 15:21:36 -0800 (Thu, 25 Dec 2008) $
23
 * @license       http://www.opensource.org/licenses/mit-license.php The MIT License
24
 */
25
/**
26
 * Included libraries.
27
 */
28
App::import('Core', array('Helper', 'ClassRegistry'));
29
/**
30
 * View, the V in the MVC triad.
31
 *
32
 * Class holding methods for displaying presentation data.
33
 *
34
 * @package       cake
35
 * @subpackage    cake.cake.libs.view
36
 */
37
class View extends Object {
38
/**
39
 * Path parts for creating links in views.
40
 *
41
 * @var string Base URL
42
 * @access public
43
 */
44
	var $base = null;
45
/**
46
 * Stores the current URL (for links etc.)
47
 *
48
 * @var string Current URL
49
 */
50
	var $here = null;
51
/**
52
 * Name of the plugin.
53
 *
54
 * @link          http://manual.cakephp.org/chapter/plugins
55
 * @var string
56
 */
57
	var $plugin = null;
58
/**
59
 * Name of the controller.
60
 *
61
 * @var string Name of controller
62
 * @access public
63
 */
64
	var $name = null;
65
/**
66
 * Action to be performed.
67
 *
68
 * @var string Name of action
69
 * @access public
70
 */
71
	var $action = null;
72
/**
73
 * Array of parameter data
74
 *
75
 * @var array Parameter data
76
 */
77
	var $params = array();
78
/**
79
 * Current passed params
80
 *
81
 * @var mixed
82
 */
83
	var $passedArgs = array();
84
/**
85
 * Array of data
86
 *
87
 * @var array Parameter data
88
 */
89
	var $data = array();
90
/**
91
 * An array of names of built-in helpers to include.
92
 *
93
 * @var mixed A single name as a string or a list of names as an array.
94
 * @access public
95
 */
96
	var $helpers = array('Html');
97
/**
98
 * Path to View.
99
 *
100
 * @var string Path to View
101
 */
102
	var $viewPath = null;
103
/**
104
 * Variables for the view
105
 *
106
 * @var array
107
 * @access public
108
 */
109
	var $viewVars = array();
110
/**
111
 * Name of layout to use with this View.
112
 *
113
 * @var string
114
 * @access public
115
 */
116
	var $layout = 'default';
117
/**
118
 * Path to Layout.
119
 *
120
 * @var string Path to Layout
121
 */
122
	var $layoutPath = null;
123
/**
124
 * Title HTML element of this View.
125
 *
126
 * @var string
127
 * @access public
128
 */
129
	var $pageTitle = false;
130
/**
131
 * Turns on or off Cake's conventional mode of rendering views. On by default.
132
 *
133
 * @var boolean
134
 * @access public
135
 */
136
	var $autoRender = true;
137
/**
138
 * Turns on or off Cake's conventional mode of finding layout files. On by default.
139
 *
140
 * @var boolean
141
 * @access public
142
 */
143
	var $autoLayout = true;
144
/**
145
 * File extension. Defaults to Cake's template ".ctp".
146
 *
147
 * @var string
148
 */
149
	var $ext = '.ctp';
150
/**
151
 * Sub-directory for this view file.
152
 *
153
 * @var string
154
 */
155
	var $subDir = null;
156
/**
157
 * Theme name.
158
 *
159
 * @var string
160
 */
161
	var $themeWeb = null;
162
/**
163
 * Used to define methods a controller that will be cached.
164
 *
165
 * @see Controller::$cacheAction
166
 * @var mixed
167
 * @access public
168
 */
169
	var $cacheAction = false;
170
/**
171
 * holds current errors for the model validation
172
 *
173
 * @var array
174
 */
175
	var $validationErrors = array();
176
/**
177
 * True when the view has been rendered.
178
 *
179
 * @var boolean
180
 */
181
	var $hasRendered = false;
182
/**
183
 * Array of loaded view helpers.
184
 *
185
 * @var array
186
 */
187
	var $loaded = array();
188
/**
189
 * True if in scope of model-specific region
190
 *
191
 * @var boolean
192
 */
193
	var $modelScope = false;
194
/**
195
 * Name of current model this view context is attached to
196
 *
197
 * @var string
198
 */
199
	var $model = null;
200
/**
201
 * Name of association model this view context is attached to
202
 *
203
 * @var string
204
 */
205
	var $association = null;
206
/**
207
 * Name of current model field this view context is attached to
208
 *
209
 * @var string
210
 */
211
	var $field = null;
212
/**
213
 * Suffix of current field this view context is attached to
214
 *
215
 * @var string
216
 */
217
	var $fieldSuffix = null;
218
/**
219
 * The current model ID this view context is attached to
220
 *
221
 * @var mixed
222
 */
223
	var $modelId = null;
224
/**
225
 * List of generated DOM UUIDs
226
 *
227
 * @var array
228
 */
229
	var $uuids = array();
230
/**
231
 * Holds View output.
232
 *
233
 * @var string
234
 **/
235
	var $output = false;
236
/**
237
 * List of variables to collect from the associated controller
238
 *
239
 * @var array
240
 * @access protected
241
 */
242
	var $__passedVars = array(
243
		'viewVars', 'action', 'autoLayout', 'autoRender', 'ext', 'base', 'webroot',
244
		'helpers', 'here', 'layout', 'name', 'pageTitle', 'layoutPath', 'viewPath',
245
		'params', 'data', 'plugin', 'passedArgs', 'cacheAction'
246
	);
247
/**
248
 * Scripts (and/or other <head /> tags) for the layout
249
 *
250
 * @var array
251
 * @access private
252
 */
253
	var $__scripts = array();
254
/**
255
 * Holds an array of paths.
256
 *
257
 * @var array
258
 */
259
	var $__paths = array();
260
/**
261
 * Constructor
262
 *
263
 * @return View
264
 */
265
	function __construct(&$controller, $register = true) {
266
		if (is_object($controller)) {
267
			$count = count($this->__passedVars);
268
			for ($j = 0; $j < $count; $j++) {
269
				$var = $this->__passedVars[$j];
270
				$this->{$var} = $controller->{$var};
271
			}
272
		}
273
		parent::__construct();
274
 
275
		if ($register) {
276
			ClassRegistry::addObject('view', $this);
277
		}
278
	}
279
/**
280
 * Renders a piece of PHP with provided parameters and returns HTML, XML, or any other string.
281
 *
282
 * This realizes the concept of Elements, (or "partial layouts")
283
 * and the $params array is used to send data to be used in the
284
 * Element.  Elements can be cached through use of the cache key.
285
 *
286
 * @param string $name Name of template file in the/app/views/elements/ folder
287
 * @param array $params Array of data to be made available to the for rendered
288
 *                      view (i.e. the Element)
289
 *    Special params:
290
 *		cache - enable caching for this element accepts boolean or strtotime compatible string.
291
 *      Can also be an array
292
 *				if an array,'time' is used to specify duration of cache.  'key' can be used to
293
 *              create unique cache files.
294
 *
295
 * @return string Rendered Element
296
 * @access public
297
 */
298
	function element($name, $params = array(), $loadHelpers = false) {
299
		$file = $plugin = $key = null;
300
 
301
		if (isset($params['plugin'])) {
302
			$plugin = $params['plugin'];
303
		}
304
 
305
		if (isset($this->plugin) && !$plugin) {
306
			$plugin = $this->plugin;
307
		}
308
 
309
		if (isset($params['cache'])) {
310
			$expires = '+1 day';
311
 
312
			if (is_array($params['cache'])) {
313
				$expires = $params['cache']['time'];
314
				$key = Inflector::slug($params['cache']['key']);
315
			} elseif ($params['cache'] !== true) {
316
				$expires = $params['cache'];
317
				$key = implode('_', array_keys($params));
318
			}
319
 
320
			if ($expires) {
321
				$cacheFile = 'element_' . $key . '_' . $plugin . Inflector::slug($name);
322
				$cache = cache('views' . DS . $cacheFile, null, $expires);
323
 
324
				if (is_string($cache)) {
325
					return $cache;
326
				}
327
			}
328
		}
329
		$paths = $this->_paths($plugin);
330
 
331
		foreach ($paths as $path) {
332
			if (file_exists($path . 'elements' . DS . $name . $this->ext)) {
333
				$file = $path . 'elements' . DS . $name . $this->ext;
334
				break;
335
			} elseif (file_exists($path . 'elements' . DS . $name . '.thtml')) {
336
				$file = $path . 'elements' . DS . $name . '.thtml';
337
				break;
338
			}
339
		}
340
 
341
		if (is_file($file)) {
342
			$params = array_merge_recursive($params, $this->loaded);
343
			$element = $this->_render($file, array_merge($this->viewVars, $params), $loadHelpers);
344
			if (isset($params['cache']) && isset($cacheFile) && isset($expires)) {
345
				cache('views' . DS . $cacheFile, $element, $expires);
346
			}
347
			return $element;
348
		}
349
		$file = $paths[0] . 'elements' . DS . $name . $this->ext;
350
 
351
		if (Configure::read() > 0) {
352
			return "Not Found: " . $file;
353
		}
354
	}
355
/**
356
 * Renders view for given action and layout. If $file is given, that is used
357
 * for a view filename (e.g. customFunkyView.ctp).
358
 *
359
 * @param string $action Name of action to render for
360
 * @param string $layout Layout to use
361
 * @param string $file Custom filename for view
362
 * @return string Rendered Element
363
 */
364
	function render($action = null, $layout = null, $file = null) {
365
		if ($this->hasRendered) {
366
			return true;
367
		}
368
		$out = null;
369
 
370
		if ($file != null) {
371
			$action = $file;
372
		}
373
 
374
		if ($action !== false && $viewFileName = $this->_getViewFileName($action)) {
375
			if (substr($viewFileName, -3) === 'ctp' || substr($viewFileName, -5) === 'thtml') {
376
				$out = View::_render($viewFileName, $this->viewVars);
377
			} else {
378
				$out = $this->_render($viewFileName, $this->viewVars);
379
			}
380
		}
381
 
382
		if ($layout === null) {
383
			$layout = $this->layout;
384
		}
385
 
386
		if ($out !== false) {
387
			if ($layout && $this->autoLayout) {
388
				$out = $this->renderLayout($out, $layout);
389
				$isCached = (
390
					isset($this->loaded['cache']) &&
391
					(($this->cacheAction != false)) && (Configure::read('Cache.check') === true)
392
				);
393
 
394
				if ($isCached) {
395
					$replace = array('<cake:nocache>', '</cake:nocache>');
396
					$out = str_replace($replace, '', $out);
397
				}
398
			}
399
			$this->hasRendered = true;
400
		} else {
401
			$out = $this->_render($viewFileName, $this->viewVars);
402
			$msg = __("Error in view %s, got: <blockquote>%s</blockquote>", true);
403
			trigger_error(sprintf($msg, $viewFileName, $out), E_USER_ERROR);
404
		}
405
		return $out;
406
	}
407
/**
408
 * Renders a layout. Returns output from _render(). Returns false on error.
409
 * Several variables are created for use in layout.
410
 *	title_for_layout - contains page title
411
 *	content_for_layout - contains rendered view file
412
 *	scripts_for_layout - contains scripts added to header
413
 *  cakeDebug - if debug is on, cake debug information is added.
414
 *
415
 * @param string $content_for_layout Content to render in a view, wrapped by the surrounding layout.
416
 * @return mixed Rendered output, or false on error
417
 */
418
	function renderLayout($content_for_layout, $layout = null) {
419
		$layoutFileName = $this->_getLayoutFileName($layout);
420
		$debug = '';
421
 
422
		if (isset($this->viewVars['cakeDebug']) && Configure::read() > 2) {
423
			$params = array('controller' => $this->viewVars['cakeDebug']);
424
			$debug = View::element('dump', $params, false);
425
			unset($this->viewVars['cakeDebug']);
426
		}
427
 
428
		if ($this->pageTitle !== false) {
429
			$pageTitle = $this->pageTitle;
430
		} else {
431
			$pageTitle = Inflector::humanize($this->viewPath);
432
		}
433
		$data_for_layout = array_merge($this->viewVars, array(
434
			'title_for_layout' => $pageTitle,
435
			'content_for_layout' => $content_for_layout,
436
			'scripts_for_layout' => join("\n\t", $this->__scripts),
437
			'cakeDebug' => $debug
438
		));
439
 
440
		if (empty($this->loaded) && !empty($this->helpers)) {
441
			$loadHelpers = true;
442
		} else {
443
			$loadHelpers = false;
444
			$data_for_layout = array_merge($data_for_layout, $this->loaded);
445
		}
446
 
447
		$this->_triggerHelpers('beforeLayout');
448
 
449
		if (substr($layoutFileName, -3) === 'ctp' || substr($layoutFileName, -5) === 'thtml') {
450
			$this->output = View::_render($layoutFileName, $data_for_layout, $loadHelpers, true);
451
		} else {
452
			$this->output = $this->_render($layoutFileName, $data_for_layout, $loadHelpers);
453
		}
454
 
455
		if ($this->output === false) {
456
			$this->output = $this->_render($layoutFileName, $data_for_layout);
457
			$msg = __("Error in layout %s, got: <blockquote>%s</blockquote>", true);
458
			trigger_error(sprintf($msg, $layoutFileName, $this->output), E_USER_ERROR);
459
			return false;
460
		}
461
 
462
		$this->_triggerHelpers('afterLayout');
463
 
464
		return $this->output;
465
	}
466
/**
467
 * Fire a callback on all loaded Helpers
468
 *
469
 * @param string $callback name of callback fire.
470
 * @access protected
471
 * @return void
472
 */
473
	function _triggerHelpers($callback) {
474
		if (empty($this->loaded)) {
475
			return false;
476
		}
477
		$helpers = array_keys($this->loaded);
478
		foreach ($helpers as $helperName) {
479
			$helper =& $this->loaded[$helperName];
480
			if (is_object($helper)) {
481
				if (is_subclass_of($helper, 'Helper')) {
482
					$helper->{$callback}();
483
				}
484
			}
485
		}
486
	}
487
/**
488
 * Render cached view
489
 *
490
 * @param string $filename the cache file to include
491
 * @param string $timeStart the page render start time
492
 */
493
	function renderCache($filename, $timeStart) {
494
		ob_start();
495
		include ($filename);
496
 
497
		if (Configure::read() > 0 && $this->layout != 'xml') {
498
			echo "<!-- Cached Render Time: " . round(getMicrotime() - $timeStart, 4) . "s -->";
499
		}
500
		$out = ob_get_clean();
501
 
502
		if (preg_match('/^<!--cachetime:(\\d+)-->/', $out, $match)) {
503
			if (time() >= $match['1']) {
504
				@unlink($filename);
505
				unset ($out);
506
				return false;
507
			} else {
508
				if ($this->layout === 'xml') {
509
					header('Content-type: text/xml');
510
				}
511
				echo str_replace('<!--cachetime:' . $match['1'] . '-->', '', $out);
512
				return true;
513
			}
514
		}
515
	}
516
/**
517
 * Returns a list of variables available in the current View context
518
 *
519
 * @return array
520
 * @access public
521
 */
522
	function getVars() {
523
		return array_keys($this->viewVars);
524
	}
525
/**
526
 * Returns the contents of the given View variable(s)
527
 *
528
 * @return array
529
 * @access public
530
 */
531
	function getVar($var) {
532
		if (!isset($this->viewVars[$var])) {
533
			return null;
534
		} else {
535
			return $this->viewVars[$var];
536
		}
537
	}
538
/**
539
 * Adds a script block or other element to be inserted in $scripts_for_layout in
540
 * the <head /> of a document layout
541
 *
542
 * @param string $name
543
 * @param string $content
544
 * @return void
545
 * @access public
546
 */
547
	function addScript($name, $content = null) {
548
		if (empty($content)) {
549
			if (!in_array($name, array_values($this->__scripts))) {
550
				$this->__scripts[] = $name;
551
			}
552
		} else {
553
			$this->__scripts[$name] = $content;
554
		}
555
	}
556
/**
557
 * Generates a unique, non-random DOM ID for an object, based on the object type and the target URL.
558
 *
559
 * @param string $object Type of object, i.e. 'form' or 'link'
560
 * @param string $url The object's target URL
561
 * @return string
562
 * @access public
563
 */
564
	function uuid($object, $url) {
565
		$c = 1;
566
		$url = Router::url($url);
567
		$hash = $object . substr(md5($object . $url), 0, 10);
568
		while (in_array($hash, $this->uuids)) {
569
			$hash = $object . substr(md5($object . $url . $c), 0, 10);
570
			$c++;
571
		}
572
		$this->uuids[] = $hash;
573
		return $hash;
574
	}
575
/**
576
 * Returns the entity reference of the current context as an array of identity parts
577
 *
578
 * @return array An array containing the identity elements of an entity
579
 */
580
	function entity() {
581
		$assoc = ($this->association) ? $this->association : $this->model;
582
		return array_values(Set::filter(
583
			array($assoc, $this->modelId, $this->field, $this->fieldSuffix)
584
		));
585
	}
586
/**
587
 * Allows a template or element to set a variable that will be available in
588
 * a layout or other element. Analagous to Controller::set.
589
 *
590
 * @param mixed $one A string or an array of data.
591
 * @param mixed $two Value in case $one is a string (which then works as the key).
592
 *              Unused if $one is an associative array, otherwise serves as the
593
 *              values to $one's keys.
594
 * @return unknown
595
 */
596
	function set($one, $two = null) {
597
		$data = null;
598
		if (is_array($one)) {
599
			if (is_array($two)) {
600
				$data = array_combine($one, $two);
601
			} else {
602
				$data = $one;
603
			}
604
		} else {
605
			$data = array($one => $two);
606
		}
607
 
608
		if ($data == null) {
609
			return false;
610
		}
611
 
612
		foreach ($data as $name => $value) {
613
			if ($name == 'title') {
614
				$this->pageTitle = $value;
615
			} else {
616
				$this->viewVars[$name] = $value;
617
			}
618
		}
619
	}
620
/**
621
 * Displays an error page to the user. Uses layouts/error.ctp to render the page.
622
 *
623
 * @param integer $code HTTP Error code (for instance: 404)
624
 * @param string $name Name of the error (for instance: Not Found)
625
 * @param string $message Error message as a web page
626
 */
627
	function error($code, $name, $message) {
628
		header ("HTTP/1.1 {$code} {$name}");
629
		print ($this->_render(
630
			$this->_getLayoutFileName('error'),
631
			array('code' => $code, 'name' => $name, 'message' => $message)
632
		));
633
	}
634
/**
635
 * Renders and returns output for given view filename with its
636
 * array of data.
637
 *
638
 * @param string $___viewFn Filename of the view
639
 * @param array $___dataForView Data to include in rendered view
640
 * @return string Rendered output
641
 * @access protected
642
 */
643
	function _render($___viewFn, $___dataForView, $loadHelpers = true, $cached = false) {
644
		$loadedHelpers = array();
645
 
646
		if ($this->helpers != false && $loadHelpers === true) {
647
			$loadedHelpers = $this->_loadHelpers($loadedHelpers, $this->helpers);
648
 
649
			foreach (array_keys($loadedHelpers) as $helper) {
650
				$camelBackedHelper = Inflector::variable($helper);
651
				${$camelBackedHelper} =& $loadedHelpers[$helper];
652
				$this->loaded[$camelBackedHelper] =& ${$camelBackedHelper};
653
			}
654
 
655
			$this->_triggerHelpers('beforeRender');
656
		}
657
 
658
		extract($___dataForView, EXTR_SKIP);
659
		ob_start();
660
 
661
		if (Configure::read() > 0) {
662
			include ($___viewFn);
663
		} else {
664
			@include ($___viewFn);
665
		}
666
 
667
		if ($loadHelpers === true) {
668
			$this->_triggerHelpers('afterRender');
669
		}
670
 
671
		$out = ob_get_clean();
672
		$caching = (
673
			isset($this->loaded['cache']) &&
674
			(($this->cacheAction != false)) && (Configure::read('Cache.check') === true)
675
		);
676
 
677
		if ($caching) {
678
			if (is_a($this->loaded['cache'], 'CacheHelper')) {
679
				$cache =& $this->loaded['cache'];
680
				$cache->base = $this->base;
681
				$cache->here = $this->here;
682
				$cache->helpers = $this->helpers;
683
				$cache->action = $this->action;
684
				$cache->controllerName = $this->name;
685
				$cache->layout	= $this->layout;
686
				$cache->cacheAction = $this->cacheAction;
687
				$cache->cache($___viewFn, $out, $cached);
688
			}
689
		}
690
		return $out;
691
	}
692
/**
693
 * Loads helpers, with their dependencies.
694
 *
695
 * @param array $loaded List of helpers that are already loaded.
696
 * @param array $helpers List of helpers to load.
697
 * @param string $parent holds name of helper, if loaded helper has helpers
698
 * @return array
699
 */
700
	function &_loadHelpers(&$loaded, $helpers, $parent = null) {
701
		if (empty($loaded)) {
702
			$helpers[] = 'Session';
703
		}
704
 
705
		foreach ($helpers as $i => $helper) {
706
			$options = array();
707
 
708
			if (!is_int($i)) {
709
				$options = $helper;
710
				$helper = $i;
711
			}
712
			$plugin = $this->plugin;
713
 
714
			if (strpos($helper, '.') !== false) {
715
				list($plugin, $helper) = explode('.', $helper);
716
			}
717
			$helperCn = $helper . 'Helper';
718
 
719
			if (!isset($loaded[$helper])) {
720
				if (!class_exists($helperCn)) {
721
					$isLoaded = false;
722
					if (!is_null($plugin)) {
723
						$isLoaded = App::import('Helper', $plugin . '.' . $helper);
724
					}
725
					if (!$isLoaded) {
726
						if (!App::import('Helper', $helper)) {
727
							$this->cakeError('missingHelperFile', array(array(
728
								'helper' => $helper,
729
								'file' => Inflector::underscore($helper) . '.php',
730
								'base' => $this->base
731
							)));
732
							return false;
733
						}
734
					}
735
					if (!class_exists($helperCn)) {
736
						$this->cakeError('missingHelperClass', array(array(
737
							'helper' => $helper,
738
							'file' => Inflector::underscore($helper) . '.php',
739
							'base' => $this->base
740
						)));
741
						return false;
742
					}
743
				}
744
				$loaded[$helper] =& new $helperCn($options);
745
				$vars = array(
746
					'base', 'webroot', 'here', 'params', 'action', 'data', 'themeWeb', 'plugin'
747
				);
748
				$c = count($vars);
749
 
750
				for ($j = 0; $j < $c; $j++) {
751
					$loaded[$helper]->{$vars[$j]} = $this->{$vars[$j]};
752
				}
753
 
754
				if (!empty($this->validationErrors)) {
755
					$loaded[$helper]->validationErrors = $this->validationErrors;
756
				}
757
				if (is_array($loaded[$helper]->helpers) && !empty($loaded[$helper]->helpers)) {
758
					$loaded =& $this->_loadHelpers($loaded, $loaded[$helper]->helpers, $helper);
759
				}
760
			}
761
			if (isset($loaded[$parent])) {
762
				$loaded[$parent]->{$helper} =& $loaded[$helper];
763
			}
764
		}
765
		return $loaded;
766
	}
767
/**
768
 * Returns filename of given action's template file (.ctp) as a string.
769
 * CamelCased action names will be under_scored! This means that you can have
770
 * LongActionNames that refer to long_action_names.ctp views.
771
 *
772
 * @param string $action Controller action to find template filename for
773
 * @return string Template filename
774
 * @access protected
775
 */
776
	function _getViewFileName($name = null) {
777
		$subDir = null;
778
 
779
		if (!is_null($this->subDir)) {
780
			$subDir = $this->subDir . DS;
781
		}
782
 
783
		if ($name === null) {
784
			$name = $this->action;
785
		}
786
		$name = str_replace('/', DS, $name);
787
 
788
		if (strpos($name, DS) === false && $name[0] !== '.') {
789
			$name = $this->viewPath . DS . $subDir . Inflector::underscore($name);
790
		} elseif (strpos($name, DS) !== false) {
791
			if ($name{0} === DS || $name{1} === ':') {
792
				if (is_file($name)) {
793
					return $name;
794
				}
795
				$name = trim($name, DS);
796
			} else if ($name[0] === '.') {
797
				$name = substr($name, 3);
798
			} else {
799
				$name = $this->viewPath . DS . $subDir . $name;
800
			}
801
		}
802
 
803
		$paths = $this->_paths($this->plugin);
804
 
805
		foreach ($paths as $path) {
806
			if (file_exists($path . $name . $this->ext)) {
807
				return $path . $name . $this->ext;
808
			} elseif (file_exists($path . $name . '.ctp')) {
809
				return $path . $name . '.ctp';
810
			} elseif (file_exists($path . $name . '.thtml')) {
811
				return $path . $name . '.thtml';
812
			}
813
		}
814
		$defaultPath = $paths[0];
815
 
816
		if ($this->plugin) {
817
			$pluginPaths = Configure::read('pluginPaths');
818
			foreach ($paths as $path) {
819
				if (strpos($path, $pluginPaths[0]) === 0) {
820
					$defaultPath = $path;
821
					break;
822
				}
823
			}
824
		}
825
		return $this->_missingView($defaultPath . $name . $this->ext, 'missingView');
826
	}
827
 
828
/**
829
 * Returns layout filename for this template as a string.
830
 *
831
 * @return string Filename for layout file (.ctp).
832
 * @access protected
833
 */
834
	function _getLayoutFileName($name = null) {
835
		if ($name === null) {
836
			$name = $this->layout;
837
		}
838
		$subDir = null;
839
 
840
		if (!is_null($this->layoutPath)) {
841
			$subDir = $this->layoutPath . DS;
842
		}
843
		$paths = $this->_paths($this->plugin);
844
		$file = 'layouts' . DS . $subDir . $name;
845
 
846
		$exts = array($this->ext, '.ctp', '.thtml');
847
		foreach ($paths as $path) {
848
			foreach ($exts as $ext) {
849
				if (file_exists($path . $file . $ext)) {
850
					return $path . $file . $ext;
851
				}
852
			}
853
		}
854
		return $this->_missingView($paths[0] . $file . $this->ext, 'missingLayout');
855
	}
856
/**
857
 * Return a misssing view error message
858
 *
859
 * @param string $viewFileName the filename that should exist
860
 * @return cakeError
861
 */
862
	function _missingView($file, $error = 'missingView') {
863
 
864
		if ($error === 'missingView') {
865
			$this->cakeError('missingView', array(
866
				'className' => $this->name,
867
				'action' => $this->action,
868
				'file' => $file,
869
				'base' => $this->base
870
			));
871
			return false;
872
		} elseif ($error === 'missingLayout') {
873
			$this->cakeError('missingLayout', array(
874
				'layout' => $this->layout,
875
				'file' => $file,
876
				'base' => $this->base
877
			));
878
			return false;
879
		}
880
	}
881
/**
882
 * Return all possible paths to find view files in order
883
 *
884
 * @param string $plugin
885
 * @return array paths
886
 * @access protected
887
 */
888
	function _paths($plugin = null, $cached = true) {
889
		if ($plugin === null && $cached === true && !empty($this->__paths)) {
890
			return $this->__paths;
891
		}
892
		$paths = array();
893
		$viewPaths = Configure::read('viewPaths');
894
 
895
		if ($plugin !== null) {
896
			$count = count($viewPaths);
897
			for ($i = 0; $i < $count; $i++) {
898
				$paths[] = $viewPaths[$i] . 'plugins' . DS . $plugin . DS;
899
			}
900
			$pluginPaths = Configure::read('pluginPaths');
901
			$count = count($pluginPaths);
902
 
903
			for ($i = 0; $i < $count; $i++) {
904
				$paths[] = $pluginPaths[$i] . $plugin . DS . 'views' . DS;
905
			}
906
		}
907
		$paths = array_merge($paths, $viewPaths);
908
 
909
		if (empty($this->__paths)) {
910
			$this->__paths = $paths;
911
		}
912
		return $paths;
913
	}
914
/**
915
 * @deprecated
916
 * @see View::element
917
 */
918
	function renderElement($name, $params = array(), $loadHelpers = false) {
919
		return $this->element($name, $params, $loadHelpers);
920
	}
921
}
922
 
923
?>