Smarty Forum Index Smarty
The discussions here are for Smarty, a template engine for the PHP programming language.
Creating your own smarty tag like {section}
Goto page 1, 2  Next
 
Post new topic   Reply to topic    Smarty Forum Index -> Plugins
View previous topic :: View next topic  
Author Message
Domino
Smarty Rookie


Joined: 27 Jun 2012
Posts: 12

PostPosted: Mon Jul 02, 2012 11:55 am    Post subject: Creating your own smarty tag like {section} Reply with quote

Hey,

I want to implement smarty into my cms (based on CodeIgniter) as a template engine. But I want to make my cms also for people that know only html/css (maybe a little of js) and for that I need simple template engine like smarty with extra tags of my own that are working like smarty section tag.
That is why I duplicated file: smarty_internal_compile_section.php and change a little of source, and name to smarty_internal_compile_dgc_model.php.
Code:
<?php
/**
 * Smarty Internal Plugin Compile DGC Model
 *
 * Compiles the {dgc_model} {dgc_model_else} {/dgc_model} tags
 *
 * @package DGC
 * @subpackage Compiler
 * @author Dominik Zagrodzki zagroda[AT]gmail.com, dominik[AT]domino-group.eu
 */

/**
 * Smarty Internal Plugin Compile DGC Model Class
 *
 * @package DGC
 * @subpackage Compiler
 */
class Smarty_Internal_Compile_Dgc_model extends Smarty_Internal_CompileBase {

    /**
     * Attribute definition: Overwrites base class.
     *
     * @var array
     * @see Smarty_Internal_CompileBase
     */
    /* public $required_attributes = array('name', 'loop'); */
    public $required_attributes = array('name');
    /**
     * Attribute definition: Overwrites base class.
     *
     * @var array
     * @see Smarty_Internal_CompileBase
     */
    /* public $shorttag_order = array('name', 'loop'); */
    public $shorttag_order = array('name');
    /**
     * Attribute definition: Overwrites base class.
     *
     * @var array
     * @see Smarty_Internal_CompileBase
     */
    public $optional_attributes = array('loop', 'start', 'step', 'max', 'show');
   
    private function pt_return( $array ) {
      
       $return = '<pre>';
       $return .= print_r ( $array , TRUE );
       $return .= '</pre>';
      
       return $return;
      
   }
    /**
     * Compiles code for the {dgc_model} tag
     *
     * @param array  $args     array with attributes from parser
     * @param object $compiler compiler object
     * @return string compiled code
     */
    public function compile($args, $compiler) {
       
        // check and get attributes
        $_attr = $this->getAttributes($compiler, $args);
       
        $this->openTag($compiler, 'dgc_model', array('dgc_model', $compiler->nocache));
        // maybe nocache because of nocache variables
        $compiler->nocache = $compiler->nocache | $compiler->tag_nocache;

        $output = "<?php ";

        $section_name = $_attr['name'];

        $output .= "if (isset(\$_smarty_tpl->tpl_vars['smarty']->value['dgc_model'][$section_name])) unset(\$_smarty_tpl->tpl_vars['smarty']->value['dgc_model'][$section_name]);\n";
        $section_props = "\$_smarty_tpl->tpl_vars['smarty']->value['dgc_model'][$section_name]";

        foreach ($_attr as $attr_name => $attr_value) {
            switch ($attr_name) {
                case 'loop':
                    $output .= "{$section_props}['loop'] = is_array(\$_loop=$attr_value) ? count(\$_loop) : max(0, (int)\$_loop); unset(\$_loop);\n";
                    break;

                case 'show':
                    if (is_bool($attr_value))
                        $show_attr_value = $attr_value ? 'true' : 'false';
                    else
                        $show_attr_value = "(bool)$attr_value";
                    $output .= "{$section_props}['show'] = $show_attr_value;\n";
                    break;

                case 'name':
                    $output .= "{$section_props}['$attr_name'] = $attr_value;\n";
                    break;

                case 'max':
                case 'start':
                    $output .= "{$section_props}['$attr_name'] = (int)$attr_value;\n";
                    break;

                case 'step':
                    $output .= "{$section_props}['$attr_name'] = ((int)$attr_value) == 0 ? 1 : (int)$attr_value;\n";
                    break;
            }
        }

        if (!isset($_attr['show']))
            $output .= "{$section_props}['show'] = true;\n";

        if (!isset($_attr['loop']))
            $output .= "{$section_props}['loop'] = 1;\n";

        if (!isset($_attr['max']))
            $output .= "{$section_props}['max'] = {$section_props}['loop'];\n";
        else
            $output .= "if ({$section_props}['max'] < 0)\n" . "    {$section_props}['max'] = {$section_props}['loop'];\n";

        if (!isset($_attr['step']))
            $output .= "{$section_props}['step'] = 1;\n";

        if (!isset($_attr['start']))
            $output .= "{$section_props}['start'] = {$section_props}['step'] > 0 ? 0 : {$section_props}['loop']-1;\n";
        else {
            $output .= "if ({$section_props}['start'] < 0)\n" . "    {$section_props}['start'] = max({$section_props}['step'] > 0 ? 0 : -1, {$section_props}['loop'] + {$section_props}['start']);\n" . "else\n" . "    {$section_props}['start'] = min({$section_props}['start'], {$section_props}['step'] > 0 ? {$section_props}['loop'] : {$section_props}['loop']-1);\n";
        }

        $output .= "if ({$section_props}['show']) {\n";
        if (!isset($_attr['start']) && !isset($_attr['step']) && !isset($_attr['max'])) {
            $output .= "    {$section_props}['total'] = {$section_props}['loop'];\n";
        } else {
            $output .= "    {$section_props}['total'] = min(ceil(({$section_props}['step'] > 0 ? {$section_props}['loop'] - {$section_props}['start'] : {$section_props}['start']+1)/abs({$section_props}['step'])), {$section_props}['max']);\n";
        }
        $output .= "    if ({$section_props}['total'] == 0)\n" . "        {$section_props}['show'] = false;\n" . "} else\n" . "    {$section_props}['total'] = 0;\n";

        $output .= "if ({$section_props}['show']):\n";
        $output .= "
            for ({$section_props}['index'] = {$section_props}['start'], {$section_props}['iteration'] = 1;
                 {$section_props}['iteration'] <= {$section_props}['total'];
                 {$section_props}['index'] += {$section_props}['step'], {$section_props}['iteration']++):\n";
        $output .= "{$section_props}['rownum'] = {$section_props}['iteration'];\n";
        $output .= "{$section_props}['index_prev'] = {$section_props}['index'] - {$section_props}['step'];\n";
        $output .= "{$section_props}['index_next'] = {$section_props}['index'] + {$section_props}['step'];\n";
        $output .= "{$section_props}['first']      = ({$section_props}['iteration'] == 1);\n";
        $output .= "{$section_props}['last']       = ({$section_props}['iteration'] == {$section_props}['total']);\n";

        $output .= "?>";
        return $output;
    }

}

/**
 * Smarty Internal Plugin Compile dgc_model_else Class
 *
 * @package Smarty
 * @subpackage Compiler
 */
class Smarty_Internal_Compile_Dgc_model_else extends Smarty_Internal_CompileBase {

    /**
     * Compiles code for the {dgc_model_else} tag
     *
     * @param array  $args     array with attributes from parser
     * @param object $compiler compiler object
     * @return string compiled code
     */
    public function compile($args, $compiler)
    {
        // check and get attributes
        $_attr = $this->getAttributes($compiler, $args);

        list($openTag, $nocache) = $this->closeTag($compiler, array('dgc_model'));
        $this->openTag($compiler, 'dgc_model_else', array('dgc_model_else', $nocache));

        return "<?php endfor; else: ?>";
    }

}

/**
 * Smarty Internal Plugin Compile Dgc_modelclose Class
 *
 * @package Smarty
 * @subpackage Compiler
 */
class Smarty_Internal_Compile_Dgc_modelclose extends Smarty_Internal_CompileBase {

    /**
     * Compiles code for the {/dgc_model} tag
     *
     * @param array  $args     array with attributes from parser
     * @param object $compiler compiler object
     * @return string compiled code
     */
    public function compile($args, $compiler)
    {
        // check and get attributes
        $_attr = $this->getAttributes($compiler, $args);

        // must endblock be nocache?
        if ($compiler->nocache) {
            $compiler->tag_nocache = true;
        }

        list($openTag, $compiler->nocache) = $this->closeTag($compiler, array('dgc_model', 'dgc_model_else'));

        if ($openTag == 'dgc_model_else') {
            return "<?php endif; ?>";
        } else {
            return "<?php endfor; endif; ?>";
        }
    }

}

?>


So usage is similar to {section}, but with that differences like loop is optional and array that I can input by loop option I will supply via php script inside this tag php script. So ...

Code:

{dgc_model name=test_name loop=$arrayName}
   {$smarty.dgc_model.test_name.index}<br />
   {$arrayName[test_name]}<br />
{dgc_model_else}
Else html code
{/dgc_model}


The problem is that I can't show {$arrayName[test_name]} value. In complied file it is using "section" string as array key instead of "dgc_model" string.

Code:

<?php echo $_smarty_tpl->tpl_vars['tablice']->value[$_smarty_tpl->getVariable('smarty')->value['section']['test_name']['index']];?>


Can some pro smarty user/developer help me with that problem?
Back to top
View user's profile Send private message
U.Tews
Administrator


Joined: 22 Nov 2006
Posts: 4631
Location: Hamburg / Germany

PostPosted: Mon Jul 02, 2012 5:51 pm    Post subject: Reply with quote

The syntax of {$arrayName[test_name]} is directly coupled with the section tag in the lexer/parser. This can't be changed.

You should just change back all references of $_smarty_tpl->tpl_vars['smarty']->value['dgc_model'] to $_smarty_tpl->tpl_vars['smarty']->value['section']
Back to top
View user's profile Send private message
Domino
Smarty Rookie


Joined: 27 Jun 2012
Posts: 12

PostPosted: Tue Jul 03, 2012 12:38 pm    Post subject: Reply Reply with quote

Ok so I will change a little philosophy of names.

Are there any contraindications that I can add my own array to loop argument in this file instead of using argument in smarty tag?
Back to top
View user's profile Send private message
U.Tews
Administrator


Joined: 22 Nov 2006
Posts: 4631
Location: Hamburg / Germany

PostPosted: Tue Jul 03, 2012 4:35 pm    Post subject: Reply with quote

Not sure what exactly want to do with your own array and how it should work...
Back to top
View user's profile Send private message
Domino
Smarty Rookie


Joined: 27 Jun 2012
Posts: 12

PostPosted: Tue Jul 03, 2012 8:38 pm    Post subject: Reply Reply with quote

I want to create my tag that will work like {section} tag. The same functionality.

Example of tag:
Code:

{my_tag name=aaa other_argument=bbb}
     {$name[aaa].title}
     {$name[aaa].text}
     {section name=xxx loop=$name[aaa].other}
          {$name[aaa].other[xxx].name}
     {/section}
{my_tag_else}
     else text
{/my_tag}


Did I put this case more clearly for you?
Back to top
View user's profile Send private message
U.Tews
Administrator


Joined: 22 Nov 2006
Posts: 4631
Location: Hamburg / Germany

PostPosted: Tue Jul 03, 2012 8:50 pm    Post subject: Reply with quote

Where does for {my_tag } the loop array come from and what is other_argument=bbb for?
Back to top
View user's profile Send private message
Domino
Smarty Rookie


Joined: 27 Jun 2012
Posts: 12

PostPosted: Tue Jul 03, 2012 9:11 pm    Post subject: Reply Reply with quote

{my_tag} loop array will be generated inside tag script after looking other tag arguments. So...
Code:

{my_tag name=x table=sql_table where="visible='1'" order='date DESC'}

It will be something like this. This example shows the philosophy of the script. I will use other names of arguments, but the simplest way to show you my idea is to use example based on sql query.

If you still don't understand me, here is other example from ExpressionEngine site.
http://expressionengine.com/user_guide/modules/channel/channel_entries.html#id18
Back to top
View user's profile Send private message
U.Tews
Administrator


Joined: 22 Nov 2006
Posts: 4631
Location: Hamburg / Germany

PostPosted: Tue Jul 03, 2012 10:40 pm    Post subject: Reply with quote

Okay, you can create compiled code for custom tags. However it might be necessary to rework the compiler modules if we make for some reason internal changes.

You should check if you can not implement similar functionallities which function or block plugins. It's more likely that these will not be that much dependent on internals.
Back to top
View user's profile Send private message
Domino
Smarty Rookie


Joined: 27 Jun 2012
Posts: 12

PostPosted: Wed Jul 04, 2012 8:20 am    Post subject: Reply Reply with quote

What I wanted to change was:
- name of the tag
- name of index in smarty tag array to {$smarty.dgc_model.test_name.index} instead of {$smarty.section.test_name.index} ( if this is big problem I will lose this idea )
- make attribute loop optional and assign to it array in php ( I want to assign to that argument array in good place, maybe with smarty assign function)
- add other optional attributes

Do you have some guidance for me about that loop attribute? Can I do it in smarty_internal_compile_dgc_model.php file? Where is best place to do this?

I did call attributes arguments earlier, sorry for that.
Back to top
View user's profile Send private message
Domino
Smarty Rookie


Joined: 27 Jun 2012
Posts: 12

PostPosted: Tue Jul 17, 2012 2:03 pm    Post subject: Reply Reply with quote

I am pin down. I did create my own tag and assign array in compiler function ( you can find it in code after comment "here is the assign for loop"). Smarty see that array but tag don't. I think that I assign that array to late. Can some on help?

Code:

<?php
/**
 * Smarty Internal Plugin Compile DGC Model
 *
 * Compiles the {dgc_model} {dgc_model_else} {/dgc_model} tags
 *
 * @package DGC
 * @subpackage Compiler
 * @author Dominik Zagrodzki zagroda@gmail.com, dominik@domino-group.eu
 */
 
 require_once BASEPATH.'core/CodeIgniter.php';

/**
 * Smarty Internal Plugin Compile DGC Model Class
 *
 * @package DGC
 * @subpackage Compiler
 */
class Smarty_Internal_Compile_Dgc_model extends Smarty_Internal_CompileBase {

    /**
     * Attribute definition: Overwrites base class.
     *
     * @var array
     * @see Smarty_Internal_CompileBase
     */
    /* public $required_attributes = array('name', 'loop'); */
    public $required_attributes = array('name','model');
    /**
     * Attribute definition: Overwrites base class.
     *
     * @var array
     * @see Smarty_Internal_CompileBase
     */
    /* public $shorttag_order = array('name', 'loop'); */
    public $shorttag_order = array('name');
    /**
     * Attribute definition: Overwrites base class.
     *
     * @var array
     * @see Smarty_Internal_CompileBase
     */
    public $optional_attributes = array('loop', 'start', 'step', 'max', 'show', 'order');
   
    /**
     * Compiles code for the {dgc_model} tag
     *
     * @param array  $args     array with attributes from parser
     * @param object $compiler compiler object
     * @return string compiled code
     */
    public function compile($args, $compiler) {
       
       $arg = self::get_args( $args );
       
       $dg =& get_instance();
       
       $tmp_data = $dg -> selector -> select_model( $arg['model'] , $arg );
       
        // here is the assign for loop
       $dg->smarty->assignGlobal( $arg['model'] , $tmp_data );
       
       $args[]['loop'] = '$_smarty_tpl->tpl_vars[\''.$arg['model'].'\']->value';
       
        // check and get attributes
        $_attr = $this->getAttributes($compiler, $args);
       
        $this->openTag($compiler, 'dgc_model', array('dgc_model', $compiler->nocache));
        // maybe nocache because of nocache variables
        $compiler->nocache = $compiler->nocache | $compiler->tag_nocache;

        $output = "<?php ";

        $section_name = $_attr['name'];

        $output .= "if (isset(\$_smarty_tpl->tpl_vars['smarty']->value['section'][$section_name])) unset(\$_smarty_tpl->tpl_vars['smarty']->value['section'][$section_name]);\n";
        $section_props = "\$_smarty_tpl->tpl_vars['smarty']->value['section'][$section_name]";
.... rest of file
Back to top
View user's profile Send private message
U.Tews
Administrator


Joined: 22 Nov 2006
Posts: 4631
Location: Hamburg / Germany

PostPosted: Tue Jul 17, 2012 6:46 pm    Post subject: Reply with quote

The following code does assign the template variable only when the templae is assigned. Is this correct?

Code:
      // here is the assign for loop
       $dg->smarty->assignGlobal( $arg['model'] , $tmp_data );


and
Code:
       $args[]['loop'] = '$_smarty_tpl->tpl_vars[\''.$arg['model'].'\']->value';


should be

       $args[] =  array('loop','$_smarty_tpl->tpl_vars[\''.$arg['model'].'\']->value');
Back to top
View user's profile Send private message
Domino
Smarty Rookie


Joined: 27 Jun 2012
Posts: 12

PostPosted: Tue Jul 17, 2012 8:52 pm    Post subject: Reply Reply with quote

To be sure that we will understand each other I will answer that way Very Happy

The following code does assign template variable only when template is already assigned (by fetch) and in this template is my tag.
Template variable is assigned on forced compile of template when tag is in that template.

And I guess you mean:
Code:

$args[] =  array('loop'=>'$_smarty_tpl->tpl_vars[\''.$arg['model'].'\']->value');

Instead of:
Code:

$args[] =  array('loop','$_smarty_tpl->tpl_vars[\''.$arg['model'].'\']->value');
Back to top
View user's profile Send private message
U.Tews
Administrator


Joined: 22 Nov 2006
Posts: 4631
Location: Hamburg / Germany

PostPosted: Wed Jul 18, 2012 1:39 am    Post subject: Reply with quote

Quote:
The following code does assign the template variable only when the templae is assigned. Is this correct?

Code:
// here is the assign for loop
$dg->smarty->assignGlobal( $arg['model'] , $tmp_data );


Should read

The following code does assign the template variable only when the template is compiled.
Code:
      // here is the assign for loop
       $dg->smarty->assignGlobal( $arg['model'] , $tmp_data );

The above code is not excuted if a already compiled template was called.
So '$_smarty_tpl->tpl_vars[\''.$arg['model'].'\']->value' will be undefined.
Is this correct?
I think you need to put something like
Code:

'$_smarty_tpl->tpl_vars[\''.$arg['model'].'\']->value = ' . export($tmp_data, true) . ';'

into the compiled code instead.





Yes, you are right I did mean:
Code:
$args[] =  array('loop'=>'$_smarty_tpl->tpl_vars[\''.$arg['model'].'\']->value');

But tht's identical to your original code.
Back to top
View user's profile Send private message
Domino
Smarty Rookie


Joined: 27 Jun 2012
Posts: 12

PostPosted: Wed Jul 18, 2012 9:29 am    Post subject: Reply Reply with quote

Quote:

The following code does assign template variable only when template is already assigned (by fetch) and in this template is my tag.
Template variable is assigned on forced compile of template when tag is in that template.

By this I mean that I did force compile, by:
Code:

$this->force_compile = true;

So array was always in smarty debug console. But for my tag it was invisible.

Your method with code:
Code:

'$_smarty_tpl->tpl_vars[\''.$arg['model'].'\']->value = ' . var_export($tmp_data, true) . ';'

did work. My tag now sees array. But compiling every time this template is good for developer and test process. When it will go to production is there a way that template will be recompiled every 10 minutes like cache?
Back to top
View user's profile Send private message
U.Tews
Administrator


Joined: 22 Nov 2006
Posts: 4631
Location: Hamburg / Germany

PostPosted: Wed Jul 18, 2012 3:20 pm    Post subject: Reply with quote

Why is there a need to recompile the template every 10 minutes?

The compiled code should be independent from data which can chance over time. It might be the wrong aproach to create the 'loop' by the compiler. I still have not full understanding what you are trying to do.
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
Goto page 1, 2  Next
Page 1 of 2

 
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