* Copyright (c) 2005, Cake Software Foundation, Inc. * 1785 E. Sahara Avenue, Suite 490-204 * Las Vegas, Nevada 89104 * * Licensed under The MIT License * Redistributions of files must retain the above copyright notice. * * @filesource * @copyright Copyright (c) 2005, Cake Software Foundation, Inc. * @link http://www.cakefoundation.org/projects/info/cakephp CakePHP Project * @version 1.0.0.0 * @package cake * @subpackage cake.app.views * @since CakePHP v 0.10.4.1693 * @version $Revision$ * @modifiedby $LastChangedBy$ * @lastmodified $Date$ * @license http://www.opensource.org/licenses/mit-license.php The MIT License */ /** * Included libraries. */ vendor('Smarty'.DS.'libs'.DS.'Smarty.class'); /** * CakePHP Smarty view class * * This class will allow using Smarty with CakePHP * Hack based on Larry Masters work * Use view/layouts/elements, etc as normal, only if they are .TPL Smarty files, they will get "smartied". * * Quickstart: * Make dirs app/smarty/cache and app/smarty/compile * Add "var $view = 'Smarty';" to your app_controller.php * * @version 1.0.0.0 * @package cake * @subpackage cake.app.views * @modifiedby lloydhome , aphexddb * @since CakePHP v 0.10.0.1693 */ class SmartyView extends View { /** * SmartyView onstructor * * @param $controller instance of calling controller */ function __construct (&$controller) { parent::__construct($controller); $this->Smarty = &new Smarty(); $this->ext = '.tpl'; $this->smartyExt = '.tpl'; $this->cakeExt = '.thtml'; $this->Smarty->compile_dir = APP.'smarty'.DS.'compile'.DS; $this->Smarty->cache_dir = APP.'smarty'.DS.'cache'.DS; $this->Smarty->template_dir = VIEWS; if ( isset($controller->debugging) ) $this->Smarty->debugging = $controller->debugging; // version 1.1 backward compatible if (!empty($this->viewVars)) $this->_viewVars = $this->viewVars; $this->cacheAction = $controller->cacheAction; } /** * Overrides the View::_render() * Sets variables used in CakePHP to Smarty variables * * @param string $___viewFn * @param string $___data_for_view * @param string $___play_safe * @param string $loadHelpers * @return rendered views */ function _render($___viewFn, $___data_for_view, $loadHelpers = true, $cached = false) { $___play_safe = $cached; // try and find the smarty version of the supplied file if possible $this->findSmartyFile($___viewFn, $___viewFn); // render smarty files appropiately $SMARTYMODE = 0; preg_match("/^(.+)\W(\w+)(\.tpl|\.thtml|\.ctp)$/",$___viewFn,$file); $fileExt = $file[3]; if ($this->smartyExt == $fileExt) $SMARTYMODE = 1; if ($this->helpers != false && $loadHelpers === true) { $loadedHelpers = array(); $loadedHelpers = $this->_loadHelpers($loadedHelpers, $this->helpers); foreach(array_keys($loadedHelpers) as $helper) { $replace = strtolower(substr($helper, 0, 1)); $camelBackedHelper = preg_replace('/\\w/', $replace, $helper, 1); ${$camelBackedHelper} =& $loadedHelpers[$helper]; if(isset(${$camelBackedHelper}->helpers) && is_array(${$camelBackedHelper}->helpers)) { foreach(${$camelBackedHelper}->helpers as $subHelper) { ${$camelBackedHelper}->{$subHelper} =& $loadedHelpers[$subHelper]; } } $this->loaded[$camelBackedHelper] = (${$camelBackedHelper}); if ($SMARTYMODE) { $this->Smarty->assign_by_ref($camelBackedHelper, ${$camelBackedHelper}); } } } if ($SMARTYMODE) { foreach($___data_for_view as $data => $value) { if(!is_object($data)) { $this->Smarty->assign($data, $value); } } $this->Smarty->assign_by_ref('view', $this); ob_start(); $this->Smarty->display($___viewFn); } else { extract($___data_for_view, EXTR_SKIP); # load all view variables $BASE = $this->base; $params = &$this->params; $page_title = $this->pageTitle; ob_start(); $___play_safe? @include($___viewFn): include($___viewFn); } if ($this->helpers != false && $loadHelpers === true) { foreach ($loadedHelpers as $helper) { if (is_object($helper)) { if (is_subclass_of($helper, 'Helper') || is_subclass_of($helper, 'helper')) { $helper->afterRender(); } } } } $out = ob_get_clean(); if (isset($this->loaded['smartyCache'])) $this->loaded['cache'] =& $this->loaded['smartyCache']; if (isset($this->loaded['cache']) && (($this->cacheAction != false)) && (defined('CACHE_CHECK') && CACHE_CHECK === true)) { if (is_a($this->loaded['cache'], 'CacheHelper')) { $cache =& $this->loaded['cache']; if ($cached === true) { $cache->view =& $this; } $cache->base = $this->base; $cache->here = $this->here; $cache->helpers = $this->helpers; $cache->action = $this->action; $cache->controllerName = $this->name; $cache->layout = $this->layout; $cache->cacheAction = $this->cacheAction; if ($SMARTYMODE) { $cache->cache($this->Smarty->_get_compile_path($___viewFn), $out, $cached ); } else { $cache->cache($___viewFn, $out, $cached); } } } return $out; } /** * Returns filename of given action's template file (.thtml) as a string. CamelCased action names will be under_scored! This means that you can have LongActionNames that refer to long_action_names.thtml views. * * @param string $action Controller action to find template filename for * @return string Template filename * @access private */ function _getViewFileName($action) { $action = Inflector::underscore($action); $paths = Configure::getInstance(); if (!is_null($this->webservices)) { $type = strtolower($this->webservices) . DS; } else { $type = null; } $position = strpos($action, '..'); if ($position === false) { } else { $action = explode('/', $action); $i = array_search('..', $action); unset($action[$i - 1]); unset($action[$i]); $action='..' . DS . implode(DS, $action); } if (!is_null($this->plugin)) { $viewFileName = APP . 'plugins' . DS . $this->plugin . DS . 'views' . DS . $this->viewPath . DS . $action . $this->ext; if ($this->findSmartyFile(APP . 'views' . DS . 'plugins' . DS . $this->plugin . DS . $this->subDir . $type . $action . $this->ext, $viewFileName)) { return $viewFileName; } elseif ($this->findSmartyFile(APP . 'plugins' . DS . $this->plugin . DS . 'views' . DS . $this->viewPath . DS . $action . $this->ext, $viewFileName)) { return $viewFileName; } else { $this->cakeError('missingView', array(array( 'className' => $this->name, 'action' => $action, 'file' => $viewFileName, 'base' => $this->base))); exit(); } } $viewFileName = ''; foreach($paths->viewPaths as $path) { if ($this->findSmartyFile($path . $this->viewPath . DS . $this->subDir . $type . $action . $this->ext, $viewFileName)) { return $viewFileName; } } if ($viewFileName = fileExistsInPath(LIBS . 'view' . DS . 'templates' . DS . 'errors' . DS . $type . $action . '.ctp')) { return $viewFileName; } elseif($viewFileName = fileExistsInPath(LIBS . 'view' . DS . 'templates' . DS . $this->viewPath . DS . $type . $action . '.ctp')) { return $viewFileName; } elseif ($viewFileName = fileExistsInPath(LIBS . 'view' . DS . 'templates' . DS . 'errors' . DS . $type . $action . '.thtml')) { return $viewFileName; } elseif($viewFileName = fileExistsInPath(LIBS . 'view' . DS . 'templates' . DS . $this->viewPath . DS . $type . $action . '.thtml')) { return $viewFileName; } else { $viewFileName = APP . DS . 'views' . DS . $this->viewPath . DS . $action . $this->ext; $this->_missingView($viewFileName, $action); } return false; } /** * Renders a layout. Returns output from _render(). Returns false on error. * * @param string $content_for_layout Content to render in a view, wrapped by the surrounding layout. * @return mixed Rendered output, or false on error */ function renderLayout($content_for_layout) { $layout_fn = $this->_getLayoutFileName(); if(DEBUG > 2) { if (fileExistsInPath(LIBS.'view'.DS.'templates'.DS.'elements'.DS.'dump.ctp')) $debug = View::_render(LIBS.'view'.DS.'templates'.DS.'elements'.DS.'dump.ctp', array('controller' => $this->controller), true, false); else $debug = View::_render(LIBS.'view'.DS.'templates'.DS.'elements'.DS.'dump.thtml', array('controller' => $this->controller), true, false); } else { $debug = ''; } $data_for_layout = array_merge($this->_viewVars, array( 'title_for_layout'=>$this->pageTitle !== false? $this->pageTitle: Inflector::humanize($this->viewPath), 'content_for_layout'=>$content_for_layout, 'cakeDebug' => $debug)); // try and find the smarty version of the supplied file if possible $this->findSmartyFile($layout_fn, $layout_fn); if (is_file($layout_fn)) { if (empty($this->loaded) && !empty($this->helpers)) { $loadHelpers = true; } else { $loadHelpers = false; $data_for_layout = array_merge($data_for_layout, $this->loaded); } //$data_for_layout = array_merge($data_for_layout,$this->loaded); # load all view variables) if(substr($layout_fn, -1*strlen($this->smartyExt)) === $this->smartyExt) { $out = $this->_render($layout_fn, $data_for_layout, $loadHelpers, true); } elseif (substr($layout_fn, -3) === 'ctp' || substr($layout_fn, -5) === 'thtml') { $out = View::_render($layout_fn, $data_for_layout, $loadHelpers, true); } else { $out = View::_render($layout_fn, $data_for_layout, $loadHelpers, false); } if ($out === false) { $out = $this->_render($layout_fn, $data_for_layout, false); trigger_error(sprintf(__("Error in layout %s, got:
%s
"), $layout_fn, $out), E_USER_ERROR); return false; } else { return $out; } } else { return $this->cakeError('missingLayout', array( array( 'layout' => $this->layout, 'file' => $layout_fn, 'base' => $this->base ) )); } } /** * Searches the specified file for a smarty version (file ext. specified with $this->smartyExt) * * @param string $___viewFn * @since 1.1 * @return string */ function findSmartyFile($___viewFn, &$return) { preg_match("/^(.+)\W(\w+)(\.tpl|\.thtml|\.ctp)$/",$___viewFn,$file); $fileBase = $file[1]; $fileName = $file[2]; $fileExt = $file[3]; $smartyFileName = $fileBase . DS . $fileName . $this->smartyExt; if (is_file($smartyFileName)) { $return = $smartyFileName; return true; } $cakeFileName12 = $fileBase . DS . $fileName . '.ctp'; if (is_file($cakeFileName12)) { $return = $cakeFileName12; return true; } $cakeFileName11 = $fileBase . DS . $fileName . '.thtml'; if (is_file($cakeFileName11)) { $return = $cakeFileName11; return true; } $cakeFileName = $fileBase . DS . $fileName . $fileExt; if (is_file($cakeFileName)) { $return = $cakeFileName; return true; } return false; } // end func } ?>