Smarty View for 1.2

By Michael Houghton (icedcheese)
This expands on the Smarty View code from Version 1.1. While its only a beginning, I am hoping someone else will pick up from what we had in version 1.1

In version 1.1 of Cakephp I used the Smarty View and thought it was a great additional. In my opinion Smarty and Cake work so well together because it allows a web design to stick to the Smarty side of things, and the developer to use Cake.



With Smarty Caching, I never found any performance issues using Smarty. It really does go well with Cake... In saying that, I have started a plugin for Smarty for Cake 1.2 which expands on Smarty View from 1.1 http://bakery.cakephp.org/articles/view/how-to-use-smarty-with-cake-smartyview



Note: At this point I have only found the HTML helpers work, not the new form functions which Cake has. I am hoping someone can expand on what I have got and will write those!



Installation



Step 1: Make the file /app/view/smarty.php



Download code
<?php
/* SVN FILE: $Id: view.php 6311 2008-01-02 06:33:52Z phpnut $ */

/**
 * Methods for displaying presentation data in the view.
 *
 * PHP versions 4 and 5
 *
 * CakePHP(tm) :  Rapid Development Framework <http://www.cakephp.org/>
 * Copyright 2005-2008, 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 2005-2008, Cake Software Foundation, Inc.
 * @link            http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project
 * @package            cake
 * @subpackage        cake.cake.libs.view
 * @since            CakePHP(tm) v 0.10.0.1076
 * @version            $Revision: 6311 $
 * @modifiedby        $LastChangedBy: phpnut $
 * @lastmodified    $Date: 2008-01-02 00:33:52 -0600 (Wed, 02 Jan 2008) $
 * @license            http://www.opensource.org/licenses/mit-license.php The MIT License
 */

/**
 * Include Smarty. By default expects it at ( VENDORS.'smarty'.DS.'Smarty.class.php' )
 */
vendor('smarty'.DS.'Smarty.class');

/**
 * CakePHP Smarty view class
 *
 * This class will allow using Smarty with CakePHP
 *
 * @version      1.1.0.0
 * @package      cake
 * @subpackage   cake.app.views
 * @since        CakePHP v 1.2
 */
class SmartyView extends View
{
/**
 * SmartyView constructor
 *
 * @param  $controller instance of calling controller
 */
    
function __construct (&$controller)
    {
        
parent::__construct($controller);
        
$this->Smarty = &new Smarty();
        
// requires views be in a 'smarty' subdirectory, you can remove this limitation if you aren't using other inherited views that use .tpl as the extension
        
$this->subDir 'smarty'.DS;
        
$this->ext'.tpl';
        
$this->Smarty->plugins_dir[] = VIEWS.'smarty_plugins'.DS;
        
$this->Smarty->compile_dir TMP.'smarty'.DS.'compile'.DS;
        
$this->Smarty->cache_dir TMP.'smarty'.DS.'cache'.DS;
        
$this->Smarty->error_reporting 'E_ALL & ~E_NOTICE';
        
$this->Smarty->debugging true;
    }

/**
 * 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$___play_safe true$loadHelpers true)
    {
        if (
$this->helpers != false && $loadHelpers === true)
        {
            
$loadedHelpers =  array();
            
$loadedHelpers $this->_loadHelpers($loadedHelpers$this->helpers);

            foreach(
array_keys($loadedHelpers) as $helper)
            {
                
$replace strtolower(substr($helper01));
                
$camelBackedHelper preg_replace('/\\w/'$replace$helper1);

                ${
$camelBackedHelper} =& $loadedHelpers[$helper];
                if(isset(${
$camelBackedHelper}->helpers) && is_array(${$camelBackedHelper}->helpers))
                {
                    foreach(${
$camelBackedHelper}->helpers as $subHelper)
                    {
                        ${
$camelBackedHelper}->{$subHelper} =& $loadedHelpers[$subHelper];
                    }
                }
                
$this->loaded[$camelBackedHelper] = (${$camelBackedHelper});
                
$this->Smarty->assign_by_ref($camelBackedHelper, ${$camelBackedHelper});
            }
        }

        
$this->register_functions();

        foreach(
$___data_for_view as $data => $value)
        {
            if(!
is_object($data))
            {
                
$this->Smarty->assign($data$value);
            }
        }
        
$this->Smarty->assign_by_ref('view'$this);
        return 
$this->Smarty->fetch($___viewFn);
    }
    
/**
 * Returns layout filename for this template as a string.
 *
 * @return string Filename for layout file (.ctp).
 * @access private
 */
    
function _getLayoutFileName() {
        if (isset(
$this->webservices) && !is_null($this->webservices)) {
            
$type strtolower($this->webservices) . DS;
        } else {
            
$type null;
        }

        if (isset(
$this->plugin) && !is_null($this->plugin)) {
            if (
file_exists(APP 'plugins' DS $this->plugin DS 'views' DS 'layouts' DS $this->layout $this->ext)) {
                
$layoutFileName APP 'plugins' DS $this->plugin DS 'views' DS 'layouts' DS $this->layout $this->ext;
                return 
$layoutFileName;
            }
        }
        
$paths Configure::getInstance();

        foreach(
$paths->viewPaths as $path) {
            if (
file_exists($path 'layouts' DS $this->subDir $type $this->layout $this->ext)) {
                
$layoutFileName $path 'layouts' DS $this->subDir $type $this->layout $this->ext;
                return 
$layoutFileName;
            }
        }

        
// added for .ctp viewPath fallback
        
foreach($paths->viewPaths as $path) {
            if (
file_exists($path 'layouts' DS  $type $this->layout '.ctp')) {
                
$layoutFileName $path 'layouts' DS $type $this->layout '.ctp';
                return 
$layoutFileName;
            }
        }

        if(
$layoutFileName fileExistsInPath(LIBS 'view' DS 'templates' DS 'layouts' DS $type $this->layout '.ctp')) {
        } else {
            
$layoutFileName LAYOUTS $type $this->layout.$this->ext;
        }
        return 
$layoutFileName;
    }
    
    
/**
 * Returns filename of given action's template file (.tpl) as a string.
 * CamelCased action names will be under_scored! This means that you can have
 * LongActionNames that refer to long_action_names.ctp views.
 *
 * @param string $action Controller action to find template filename for
 * @return string Template filename
 * @access protected
 */
    
function _getViewFileName($name null) {
        
$subDir null;

        if (!
is_null($this->webservices)) {
            
$subDir strtolower($this->webservices) . DS;
        }
        if (!
is_null($this->subDir)) {
            
$subDir $this->subDir DS;
        }

        if (
$name === null) {
            
$name $this->action;
        }

        if (
strpos($name'/') === false && strpos($name'..') === false) {
            
$name $this->viewPath DS $subDir Inflector::underscore($name);
        } elseif (
strpos($name'/') !== false) {
            if (
$name{0} === '/') {
                if (
is_file($name)) {
                    return 
$name;
                }
                
$name trim($name'/');
            } else {
                
$name $this->viewPath DS $subDir $name;
            }
            if (
DS !== '/') {
                
$name implode(DSexplode('/'$name));
            }
        } elseif (
strpos($name'..') !== false) {
            
$name explode('/'$name);
            
$i array_search('..'$name);
            unset(
$name[$i 1]);
            unset(
$name[$i]);
            
$name '..' DS implode(DS$name);
        }

        
$paths $this->_paths($this->plugin);
        foreach (
$paths as $path) {
            if (
file_exists($path $name $this->ext)) {
                return 
$path $name $this->ext;
            } elseif (
file_exists($path $name '.ctp')) {
                return 
$path $name '.ctp';
            } elseif (
file_exists($path $name '.thtml')) {
                return 
$path $name '.thtml';
            }
        }

        return 
$this->_missingView($paths[0] . $name $this->ext'missingView');
    }    

    
/**
     * checks for existence of special method on loaded helpers, invoking it if it exists
     * this allows helpers to register smarty functions, modifiers, blocks, etc.
     */
    
function register_functions() {
        foreach(
array_keys($this->loaded) as $helper) {
            if (
method_exists($this->loaded[$helper], '_register_smarty_functions')) {
                
$this->loaded[$helper]->_register_smarty_functions(&$this->Smarty);
            }
        }
    }
}
?>


Comment out this line so that Smarty files don't have to go in /app/views/pages/smarty/home.tpl but /app/views/pages/home.tpl instead



Download code
$this->subDir = 'smarty'.DS;


Step 2:



Download Smarty[br]
http://smarty.php.net/download.php[br]
Extract tarball so Smarty.class.php sits at:[br] /vendor/smarty/Smarty.class.php



Step 3:



Create the folders /app/tmp/smarty[br]
/app/tmp/smarty/compile (chmod 777)[br]
/app/tmp/smarty/cache (chmod 777)



Step 4:



Include in your controller[br]
(in app_controller.php to do it app-wide)



Download code
var $view = 'Smarty';

 

Comments 602

CakePHP Team Comments Author Comments
 

Comment

1 deprecated vendor

Hi,

I'm testing cake since 2 days, as I've a great experience with Smarty, I followed the instructions.
the way vendor is used to import the smarty class is deprecated in the version 1.2.0.7125 RC1.

my little modifications in the class SmartyView extends View :

just add "App::import" but be aware smarty files contains dot (https://trac.cakephp.org/changeset/6600)
and comment or delete the deprecated vendor

Controller Class:

<?php 
//vendor('smarty'.DS.'libs'.DS.'Smarty.class');
?>


Controller Class:

<?php 
function __construct (&$controller)
{
    
App::import('Vendor''Smarty', array('file' => 'smarty'.DS.'libs'.DS.'Smarty.class.php'));
....    
?>


hope this will help beginners like me
Posted Jun 19, 2008 by magamar
 

Comment

2 a usefull thing in smarty

Using smarty let you include other template files like this :

...
<div class="languages">
   <a href=""><img src="..." alt="..." title="..." border="0" /></a>
</div>
{include file="login_box.tpl"}


I haven't found how this could be using smarty with cake php.
Using this syntax make it search in a default smarty directory called "templates". If you want it to search in views/elements for instance just add in the constructor of SmartyView Class

$this->Smarty->template_dir = VIEWS.'elements'.DS;

nice bake
Posted Jun 22, 2008 by magamar
 

Comment

3 Loading Helpers

It doesn't look like helpers are actually being assigned by reference. If the layout isn't a Smarty template, and it has $scripts_for_layout in the <head>, and somewhere a Smarty template tries to do {$javascript->link('some_script_that_goes_in_head', false)}, then it won't work. Because the Pages controller and the Smarty template uses different copies of the Javascript helper

I think you need to change this:

$loadedHelpers = $this->_loadHelpers($loadedHelpers, $this->helpers);

to this:

$loadedHelpers =& $this->_loadHelpers($loadedHelpers, $this->helpers);
Posted Jun 28, 2008 by Kasper Sevaj