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