Smarty Forum Index Smarty
The discussions here are for Smarty, a template engine for the PHP programming language.
[2.6.27] With or without block/compiler end tag possible?

 
Post new topic   Reply to topic    Smarty Forum Index -> Plugins
View previous topic :: View next topic  
Author Message
rudiedirkx
Smarty Rookie


Joined: 12 Aug 2010
Posts: 5

PostPosted: Sat Dec 22, 2012 3:14 pm    Post subject: [2.6.27] With or without block/compiler end tag possible? Reply with quote

Maybe what I want is a custom block compiler? Like foreach and if. Not once, but with end tag (sometimes).

I have a function that's a block sometimes and a function other times, depending on tag attributes. It's called title.

Currently I've added 'title' and '/title' cases in Smarty_Compiler::_compile_tag. I can use _push_tag and _pop_tag to keep track of whether it's a block or a function.

The block returns code to start ob and end it in /title.

The function returns code to assign the tags to a custom function (in the plugins folder).

If a /title is encountered while no ob started, an empty string is returned, so ob is always ended.

I don't think this is possible without hacking Smarty. A custom block would require an end tag even before evaluating the tag attributes. A function would never check for end tag, so I can't handle the /title. Same for a compiler: no end tag and I can't handle /title with a compiler.

The solution IMO is simple: allow smarty_core_assemble_plugin_filepath so handle end tags: have /title include the title plugin. The custom compiler itself can see if it's a start or end tag.

Current code in Smarty_Compiler::_compile_tag:

Code:

case 'title':
   $attrs = $this->_parse_attrs($tag_args);
   if ( isset($attrs['key']) ) {
      $export = $this->_var_export($attrs);
      return '<?php $this->assign("title", smarty_function_translate(' . $export . ', $this)); ?>';
   }

   $this->_push_tag('title');
   $this->_opened_title_tag = true;
   return '<?php ob_start(); ?>';
   break;

case '/title':
   if ( $this->_opened_title_tag ) {
      $this->_opened_title_tag = false;
      return '<?php $this->assign("title", trim(preg_replace("#\s+#", " ", ob_get_clean()))); ?>';
   }
   return '';
   break;


Is this possible without hacking Smarty_Compiler?

(How can this form not have markup for inline code??)
Back to top
View user's profile Send private message
rudiedirkx
Smarty Rookie


Joined: 12 Aug 2010
Posts: 5

PostPosted: Sat Dec 22, 2012 3:59 pm    Post subject: Reply with quote

I can add dynamic compile blocks to Smarty with only 3 small adjustments (or 'hacks'):

Change Smarty::_get_plugin_filepath:

Code:
function _get_plugin_filepath($type, &$name)
{
    if ($type == 'compiler') {
        $name = ltrim($name, '/');
    }


(added & before $name and the if-statement)

Change Smarty_Compiler::_compile_compiler_tag:

Code:
$have_function = true;
$end_tag = substr($tag_command, 0, 1) == '/';


(added $end_tag variable to use later on)

Change Smarty_Compiler::_compile_compiler_tag some more:

Code:
if ($found) {
    if ($have_function) {
        $output = call_user_func_array($plugin_func, array($tag_args, &$this, $end_tag));


(added $end_tag to the plugin function arguments list)

With those adjustments, I can make a custom compiler function that handles the start and end tag and knows which is parsed:

Code:
function smarty_compiler_title($tag_attrs, &$compiler, $end_tag) {
   $start_tag = !$end_tag;

   // Open tag
   if ( $start_tag ) {
      $attrs = $compiler->_parse_attrs($tag_attrs);
      if ( isset($attrs['key']) ) {
         $export = _smarty_compiler_title_var_export($attrs);
         return '$this->assign("title", smarty_function_translate(' . $export . ', $this));';
      }

      $compiler->_push_tag('title');
      $compiler->_opened_title_tag = true;
      return 'ob_start();';
   }

   // Close tag
   if ( !empty($compiler->_opened_title_tag) ) {
      unset($compiler->_opened_title_tag);
      $_open_tag = $compiler->_pop_tag('title');
      return '$this->assign("title", trim(preg_replace("#\s+#", " ", ob_get_clean())));';
   }

   return '';
}

function _smarty_compiler_title_var_export($attrs) {
   $items = array();

   foreach ( $attrs AS $key => $value ) {
      $items[] = "'" . $key . "' => " . $value;
   }

   return 'array(' . implode(', ', $items) . ')';
}


Is this an idea to add in a next release? It's completely 100% backward compatible and harmless.
Back to top
View user's profile Send private message
rudiedirkx
Smarty Rookie


Joined: 12 Aug 2010
Posts: 5

PostPosted: Sat Dec 22, 2012 4:09 pm    Post subject: Reply with quote

Nope. Scratch that. Making $name in Smarty::_get_plugin_filepath by-reference is a baaad idea.
Back to top
View user's profile Send private message
rudiedirkx
Smarty Rookie


Joined: 12 Aug 2010
Posts: 5

PostPosted: Sat Dec 22, 2012 4:16 pm    Post subject: Reply with quote

Even better. Only for custom compilers.

No changes to Smarty::_get_plugin_filepath.

Add below $end_tag in Smarty_Compiler::_compile_compiler_tag:

Code:
$tag_command = ltrim($tag_command, '/');


Now it really is backward compatible, because it doesn't change any function headers/definitions.

The only thing that changes now is parse errors in block end tags aren't caught as block end tags, but as custom compilers.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Smarty Forum Index -> Plugins All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group
Protected by Anti-Spam ACP