Zend & Smarty – ステップニ

In this post I will reveal the secret of really smart integration between Zend and Smarty :) Since I’m too lazy to write 10 similar functions inside the Smarty plugin, I decided to modify the Smarty compiler. And it worked well.

Making Smarty zend-aware

This step is simple – you’re just adding a function that allows you to call Zend View Helper using
call_user_func_array.


class KB_SmartyZendAware extends Smarty {
    private $_zendView                 = null;
    private $_cfg;

    public function __construct() {
        parent::__construct();
        $this->compiler_class = 'KB_SmartyZendAwareCompiler';
    }

    public function setZendView(Zend_View_Abstract $view) {
        if( $view === null ) {
            throw new KB_Exception('Zend_View cannot be null.', KB_Exception::KB_SMARTY);
        }
        $this->_zendView = $view;
    }

    public function callZendViewHelper( $name, $method, $args ) {
        if( $this->_zendView === null || ! is_string($name) || strlen($name) == 0 ) {
            return '';
        }
        $helper = $this->_zendView->getHelper($name);

        if( ! is_string($method) || strlen($method) == 0 ) {
            return call_user_func_array( array( $helper, $name ), $args);
        } else {
            return call_user_func_array( array( call_user_func( array($helper, $name) ), $method ), $args);
        }
    }
}

And then you need to extend Smarty compiler itslef.

Zend-aware compiler


require_once 'Smarty/Smarty_Compiler.class.php';
require_once 'Zend/View.php';

class KB_SmartyZendAwareCompiler extends Smarty_Compiler {
    private $_zend_view;
    
    private $_messageStack = array();
    
    public function __construct() {
        parent::__construct ();
        $this->_zend_view = new Zend_View ( );
    }

    function _compile_custom_tag($tag_command, $tag_args, $tag_modifier, &$output) {
        $found = parent::_compile_custom_tag ( $tag_command, $tag_args, $tag_modifier, $output );
        if ( ! $found && ! $this->_compiler_function_exists($tag_command)
            && ! $this->_custom_block_exists($tag_command) ) {
            try {
                $tag_command = strtoupper(substr($tag_command, 0, 1)) . substr($tag_command, 1);
                $helper = $this->_zend_view->getHelper ( $tag_command );
                
                $helper_args = array ();
                
                $helper_args = null;
                if ($tag_args !== null) {
                    $helper_args  = $this->_parse_attrs($tag_args);
                }
                $method = '';
                if( $helper_args !== null && array_key_exists('method', $helper_args) ) {
                    $method = $helper_args['method'];
                    unset($helper_args['method']);    
                }
            
                $output = "\$this->callZendViewHelper('{$tag_command}', '{$method}', array(" . 
                    $this->_create_parameter_code ( $helper_args ) . "))";
                
                if($tag_modifier != '') {
                        $this->_parse_modifiers($output, $tag_modifier);
                }
                
                if($output != '') {
                    $output =  '<?php echo ' . $output . '; ?>' . $this->_additional_newline;
                }
        
                $found = true;
            } catch(Zend_Loader_PluginLoader_Exception $e ) {
                $found = false;
            } catch ( Zend_View_Exception $e ) {
                $found = false;
            } 
        }
        
        return $found;
    }
    
    private function _custom_code_exists($tag_command, $type) {
        $found = false;
        $have_function = true;

        /*
         * First we check if the $type function has already been registered
         * or loaded from a plugin file.
         */
        if (isset($this->_plugins[$type][$tag_command])) {
            $found = true;
            $plugin_func = $this->_plugins[$type][$tag_command][0];
            if ( ! is_callable( $plugin_func ) ) {
                $have_function = false;
            }
        }
        /*
         * Otherwise we need to load plugin file and look for the function
         * inside it.
         */
        else if ( $plugin_file = $this->_get_plugin_filepath($type, $tag_command) ) {
            $found = true;

            include_once $plugin_file;

            $plugin_func = "smarty_" . $type. "_" . $tag_command;
            if ( ! function_exists( $plugin_func ) ) {
                $have_function = false;
            } else {
                $this->_plugins[$type][$tag_command] = array($plugin_func, null, null, null, true);

            }
        } 
        
        return $found &amp;&amp; $have_function;       
    }
    
    private function _custom_block_exists($tag_command) {
        return $this->_custom_code_exists($tag_command, 'block');
    }
    
    private function _custom_function_exists($tag_command) {
         return $this->_custom_code_exists($tag_command, 'function');
    }
    
    private function _compiler_function_exists($tag_command) {
         return $this->_custom_code_exists($tag_command, 'compiler');
    }

    private function _create_parameter_code($params) {
        $code = '';
        
        $i = 1;
        $p_count = count ( $params );
        if( $p_count > 0 ) {
            foreach ( $params as $p ) {
                if (is_array ( $p ))
                    $code .= 'array(' . $this->_create_parameter_code ( $p ) . ')';
                else
                    $code .= $p;
                
                if ($i != $p_count)
                    $code .= ',';
                
                $i ++;
            }
        }        
        return $code;
    }
}


Since we overrode custom tag compilation, it is still possible to use modifiers inside Zend veiw helpers as shown below:


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml">
 {doctype}
 <head>
 {headTitle|upper title="index page"}
 {headLink}
 {headStyle}
 {headMeta}
 {headScript src="js/dojo/_base.js"}
 </link></head>
 <body>
 {if $debugging}
 {debug}
 {/if}
 <!-- YOUR DATA GOES HERE -->
 </body>
 </html>
 
Tags: , ,

Leave a Reply