Smarty View for 1.2

by 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



<?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



$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)



var $view = 'Smarty';

Report

More on Helpers

Advertising

Comments

  • fat7i posted on 10/17/10 06:22:15 PM
    guys what about 1.3
  • David.Ko posted on 03/26/10 09:42:16 AM
    Hi all,
    Just provide a solution to use layout correctly when using EmailComponent.
    Please add below code in _getLayoutFileName() before forloop getting $layoutFileName to satisfy this issue.

    // solve subDir issue for EmailComponent
    if (!is_null( $this->layoutPath )) {
    $this->subDir = $this->layoutPath . DS;
    }
  • pedrojventura posted on 09/10/09 08:58:58 AM
    hi!

    i have my views working with SMARTY engine templates and i was working on a project over one month, but i realize that it´s hard to keep developing using this views because there aren´t so much documentation and just a few helpers, snippets, components,... working for smarty views.
    Right now i am trying to validate some forms with a "Ajax Validation Component"http://bakery.cakephp.org/articles/view/ajax-validation-component, but it´s hard to implement it with SMARTY view,
    do you have any ideas how to do it??

    Do you think is worth it to keep developing my project with smarty views?? I need some advice!

    THX a lot!!
  • heavyworks posted on 06/16/09 02:29:36 PM
    Noone ever used the cake's email component? It will simply fail because this functions is lacking layoutPath code that email component sets between email html and text layouts.

    Here's the fix:

    if (isset($this->layoutPath) && !is_null($this->layoutPath))
    $type .= $this->layoutPath . DS;


    This easy!
  • oagostinho posted on 03/05/09 11:32:42 AM
    Hi, People

    It's a pleasure to help. This what i did, and it's not my intention to say that my workaround it's the last word. In that way, i would like to heard opinions for another people:

    For this: Undefined property: SmartyView::$webservices

    In the file:smarty.php, try this:

    At the function: function _getViewFileName($action);
    change this line:

    if (!is_null($this->webservices))

    by this:

    if (isset($this->webservices) && !is_null($this->webservices)){


    For me was ok! What do you think?

    Cheers!
    Orlando Agostinho
  • Imagineer posted on 12/01/08 04:08:59 AM
    I have problem in migrating it with smarty.,

    Undefined property: SmartyView::$webservices

    Help me to solve it.,
  • xciv posted on 11/04/08 06:32:13 AM
    I'm not sure what's going on here but adding a null webservices has fixed that warning.. I was also trying to use the above suggestion of removing the need for a smarty template subdirectory but that no longer seems to work.

    Thanks for the pointer though as I now have a working installation.
  • nanomag posted on 11/03/08 03:17:21 PM
    Hi Paul, I've just migrated to rc3, and I didn't have this error.

    But looking at the function _getViewFileName in smarty.php, you can see that if the property "webservices" is set the function will search your templates files in this directory, if not then it will search in "subDir" property, if these 2 properties are null, it's the classic path.

    To use other path for templates (instead of app/views/Users for instance)
    you could use :
    var $webservices = "Your path";
    OR in constructor :
    $this->subDir = 'YourPath'.DS;

    To use smarty syntax {include file="login_box.tpl"}, you should add : $this->Smarty->template_dir = VIEWS.'elements'.DS; in smarty php on line 70 in constructor.
    It's useful for all other little block of html you use and reuse in your app, it's independent of all model or constructor, views
  • xciv posted on 11/03/08 08:29:43 AM
    Do you have this working with CakePHP 1.2 RC2 or RC3 at all?

    I get this strange error:

    Notice (8): Undefined property: SmartyView::$webservices [APP/views/smarty.php, line 170]

    I don't *think* there is anything wrong with my installation, any ideas?

    Cheers,
    Paul.
  • xciv posted on 11/03/08 07:35:50 AM
    Does anyone have this working with the latest 1.2 releases, ie. it doesn't seem to work with RC2 or RC3 for me?

    I get:

    Notice (8): Undefined property: SmartyView::$webservices [APP/views/smarty.php, line 170]
  • JacquesBrel posted on 06/28/08 04:20:42 AM
    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 , 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);
  • nanomag posted on 06/22/08 10:42:46 AM
    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
  • nanomag posted on 06/19/08 02:32:13 PM
    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
login to post a comment.