Smarty Forum Index Smarty
WARNING: All discussion is moving to https://reddit.com/r/smarty, please go there! This forum will be closing soon.

blocks in smarty

 
This forum is locked: you cannot post, reply to, or edit topics.   This topic is locked: you cannot edit posts or make replies.    Smarty Forum Index -> Tips and Tricks
View previous topic :: View next topic  
Author Message
BloodRath
Smarty Rookie


Joined: 06 Jul 2003
Posts: 23
Location: France

PostPosted: Thu Apr 22, 2004 9:46 am    Post subject: blocks in smarty Reply with quote

Hello i ve come back with my old idea of a block handling ability in smarty
here is the problem
i have a cms engine
in some user function i have some which display some article or some picture accroding to certain param like this

{boucle_photo id="photo_1" classement="date" ordre="ASC" vide="photo_1_vide"}

the content is diplayed in an html div.

The problem which exist with some test i could made in smarty is that if for any reason i couldn't show the result (no photo by example) , i wanna delete the whole "block of info displayed" by example if i have some word who introduced the photo album before writing the smarty template function, i would delete those word too

example:

<div id="photo">
The photo displayed here are copyrighted by me Blood...
{boucle_photo id="photo_1" classement="date" ordre="ASC" vide="photo_1_vide"}
</div>


the solution i find is to create a compiler function block
which store the block of HTML before display them and react to some action : show, delete, merge...

which could give this template code


<div id="photo">
{block id="photo_1"}
The photo displayed here are copyrighted by me Blood...
{boucle_photo id="photo_1" classement="date" ordre="ASC" vide="photo_1_vide"}
{/boucle_photo}
{/block}

{block id="photo_1_vide"}
Sorry no pictures are in DBase
{/block}
</div>

thus the boucle photo code could specify to delete block whose id = the boucle photo id when no result are found else it delete the vide [french for empty] block

to achieve this here is my code if anybody find it intersting....

1 -- add those ligne to your smarty definition (i usually extends smarty)

// global stack
$this -> $_plugins_stack = array();
//block function
includelib("plugins/blocks.plugins.lib.php"); /* just a personnal function for smart include path independant */
$this -> register_compiler_function("block" ,"_compile_block");
$this -> register_compiler_function("/block" ,"_compile_block_end");


2 -- add those ligne for compiler function (in example in block.plugin.php)
function _compile_block($tag_attrs, &$compiler){
$_params = $compiler->_parse_attrs($tag_attrs);
// check params
if (!isset($_params['id'])) {
$compiler->_syntax_error("_compile_block : missing 'id' parameter", E_USER_ERROR, __FILE__, __LINE__);
return;
}
$_output = "";
$_output.= sprintf("echo\"<!-- block [%s]-->\\n\";\n",$_params['id']);
// could be extracted and put in smarty when blocks are authorized ... to speed up
$_output.= "if(!is_array(\$this->_plugins_stack['block']))\n";
$_output.= "\t\$this->_plugins_stack['block'] = array();\n";
$local_props = "\$this->_plugins_stack['block'][{$_params['id']}]";
$_output.= "if(is_array({$local_props}))\n";
$_output.= "\tprintf(\"a block with same name was already defined\");\n";
$_output.= "{$local_props} = array();\n";
$_output.= "{$local_props}['id'] = {$_params['id']};\n";
$_output.= "{$local_props}['content'] = null;\n";
$_output.= "{$local_props}['action'] = 'show';\n";
$_output.= "ob_start();\n";
return $_output;
}
function _compile_block_end($tag_attrs, &$compiler){
$_output = "";
// last in first out
$_output.= "\$buffer = array_pop(\$this->_plugins_stack['block']);\n";
$_output.= "if(is_null(\$buffer))\n";
$_output.= "\tprintf(\"a block end was found but there is no more block in stack\");";
// does it was better to clean before or in the switch ?
//$_output.= "\$buffer['content'] = ob_get_contents();ob_end_clean();\n";
$_output.= "switch(\$buffer['action']){\n";
$_output.= "case 'delete' : \n";
$_output.= "\t\$buffer['content'] = ob_end_clean();\n";
$_output.= "\techo sprintf(\"<!-- block [%s] was deleted -->\\n\",\$buffer['id']);\n";
$_output.= "\tunset(\$buffer);\n";
$_output.= "break;\n";
$_output.= "case 'show' : \n";
$_output.= "\t\$buffer['content'] = ob_get_contents();ob_end_clean();\n";
$_output.= "\techo \$buffer['content'];\n";
$_output.= "break;\n";
$_output.= "default :\n";
$_output.= "\t\$this->trigger_error(sprintf(\"block action [%s] sended by block [%s], is unknow\",\$buffer['action'],\$buffer['id']), E_USER_ERROR);\n";
$_output.= "break;\n";
$_output.= "}//end of switch\n";
$_output.= "echo sprintf(\"<!-- /block ['%s']-->\\n\",\$buffer['id']);\n";
return $_output;
}

3 -- Create some compiler function which use the block ability

feel free to ask me for more info and please excuse me if i left any french comments in code
Wink
_________________
froggies forever.... Wink
Back to top
View user's profile Send private message
BloodRath
Smarty Rookie


Joined: 06 Jul 2003
Posts: 23
Location: France

PostPosted: Mon Apr 26, 2004 9:46 am    Post subject: Code corrections Reply with quote

I' ve change some part of code

1 -- Global array in my_smarty object
$this -> _plugins_stack = array();
$this -> _plugins_stack['block_action'] = array();
// blocks
$this -> register_compiler_function("block" ,"_compile_block");
$this -> register_compiler_function("/block" ,"_compile_block_end");

//edito
$this -> register_compiler_function("boucle_edito" ,"_compile_magazine_boucle_edito");
$this -> register_compiler_function("/boucle_edito" ,"_compile_magazine_fin_boucle_edito");


2 -- blocks function

function _compile_block($tag_attrs, &$compiler){
$_params = $compiler->_parse_attrs($tag_attrs);
// check params
if (!isset($_params['id'])) {
$compiler->_syntax_error("_compile_block : missing 'id' parameter", E_USER_ERROR, __FILE__, __LINE__);
return;
}
$_output = "";
$_output.= sprintf("echo\"<!-- block [%s]-->\\n\";\n",$_params['id']);
// could be extracted and put in smarty when blocks are authorized ... to speed up
$_output.= "if(isset(\$this->_plugins_stack['block']) && !is_array(\$this->_plugins_stack['block']))\n";
$_output.= "\t\$this->_plugins_stack['block'] = array();\n";
$_output.= "\$this->_plugins_stack['block'][] = array();\n";
$_output.= "\$_aSize = count(\$this->_plugins_stack['block'])-1;\n";
$_output.= "\$this->_plugins_stack['block'][\$_aSize]['id'] = {$_params['id']};\n";
$_output.= "\$this->_plugins_stack['block'][\$_aSize]['content']= null;\n";
$_output.= "\$this->_plugins_stack['block'][\$_aSize]['action'] = 'show';\n";
$_output.= "ob_start();\n";
return $_output;
}
function _compile_block_end($tag_attrs, &$compiler){
$_output = "";
// last in first out
// debug $_output.= "print fancy_vardump(\$this->_plugins_stack);";
$_output.= "\$buffer = array_pop(\$this->_plugins_stack['block']);\n";
$_output.= "if(is_null(\$buffer))\n";
$_output.= "\tprintf(\"a block end was found but there is no more block in stack\");\n";
// does it was better to clean before or in the switch ?
$_output.= "\$buffer['content'] = ob_get_contents();ob_end_clean();\n";
/* need to check the needed action in the array action of block
* $this->_plugins_stack['block_action']
* the data are organized in this way :
* [1] the name of the block to proceed
* [2] the action to do
* [3] the id of the order giver
*/
$_output.= "if (\$this->_plugins_stack['block_action']){\n";
$_output.= "\tforeach (\$this->_plugins_stack['block_action'] as \$k=>\$v){\n";
$_output.= "\t\t if (!strcmp(\$buffer['id'],\$v[0])){\n";
$_output.= "\t\t\t \$buffer['action'] = \$v[1];\n";
$_output.= "\t\t\t \$buffer['action_sender'] = \$v[2];\n";
$_output.= "\t\t}\n";
$_output.= "\t}\n";
$_output.= "}\n";
$_output.= "switch(\$buffer['action']){\n";
$_output.= "case 'delete' : \n";
//$_output.= "\t\$buffer['content'] = ob_end_clean();\n";
$_output.= "\techo sprintf(\"<!-- block [%s] was deleted by [%s] -->\\n\",\$buffer['id'],\$buffer['action_sender']);\n";
$_output.= "break;\n";
$_output.= "case 'show' : \n";
//$_output.= "\t\$buffer['content'] = ob_get_contents();ob_end_clean();\n";
$_output.= "\techo \$buffer['content'];\n";
$_output.= "break;\n";
$_output.= "default :\n";
$_output.= "\t\$this->trigger_error(sprintf(\"block action [%s] sended by block [%s], is unknow\",\$buffer['action'],\$buffer['id']), E_USER_ERROR);\n";
$_output.= "}//end of switch\n";
$_output.= "echo sprintf(\"<!-- /block ['%s']-->\\n\",\$buffer['id']);\n";
$_output.= "\tunset(\$buffer);\n";
return $_output;
}

3 -- example of code which use the block functionnality ALA spip (www.uzine.net/spip)

function _compile_magazine_boucle_edito($tag_attrs, &$compiler){
$_params = $compiler->_parse_attrs($tag_attrs);
// check params
if (!isset($_params['id'])) {
$compiler->_syntax_error("_compile_magazine_boucle_edito : missing 'id' parameter", E_USER_ERROR, __FILE__, __LINE__);
return;
}
if (!isset($_params['vide'])) {
$compiler->_syntax_error("_compile_magazine_boucle_edito : missing 'vide' parameter", E_USER_ERROR, __FILE__, __LINE__);
return;
}
// 1 -- DB Extraction
global $application;
$modulePath = getPath().$application['path']['modules']."magazine";
include_once "$modulePath/class/edito.class.php";
$editoH = new edito_handler();
$sClassement = "";
$sOrdre = "";
switch($_params['classement']){
case "'index'":
$sClassement = $editoH->_table."."."id_edito";
break;
case "'date'":
$sClassement = $editoH->_table."."."date";;
break;
default:
$compiler->_syntax_error("_compile_magazine_boucle_edito : Unknow value {$_params['classement']} for param 'classement'", E_USER_ERROR, __FILE__, __LINE__);
} // switch
switch($_params['ordre']){
case "'croissant'":
$sOrdre = "ASC";
break;
case "'decroissant'":
$sOrdre = "DESC";
break;
default:
$compiler->_syntax_error("_compile_magazine_boucle_edito : Unknow value {$_params['ordre']} for param 'ordre' must be croissant|decroissant", E_USER_ERROR, __FILE__, __LINE__);
} // switch

$aEdito = array();
$_req_where[] = "1";
isset($_params['index']) ? $_req_where[] = "AND ".$editoH->_table.".id_edito={$_params['index']}" : "";
// calculate mag old age param is in day
$age = substr($_params['age_max'], 1, -1);
$now = getdate();
isset($_params['age_max']) ? $_req_where[] = sprintf("AND UNIX_TIMESTAMP(".$editoH->_table.".date)>=%d",$now[0]-($age*60*60*24)) : "";
$_req_order[] = $sClassement." ".$sOrdre;
$_req_limit = null;
isset($_params['borne']) ? $_req_limit = sprintf("LIMIT %s",substr($_params['borne'],1,-1)) : null;
$aEdito = $editoH->getList4Display($_req_where,$_req_order,$_req_limit);
$_sTmp = "a".substr($_params['id'], 1, -1);
$compiler -> assign($_sTmp, $aEdito);

// html_return

$_output = sprintf("echo\"<!-- magazine_boucle_edito [%s]-->\\n\";\n",$_params['id']);
$_output.= "if (!isset(\$this->_plugins_stack) || count(\$this->_plugins_stack)==0) \n";
$_output.= "\tprintf('_compile_phototheque_boucle_edito has a big problem, no block where defined before');\n";
$_output.= "if (isset(\$this->_sections[{$_params['id']}])) \n";
$_output.= "\tunset(\$this->_sections[{$_params['id']}]);\n";
$_output.= "\$this->_sections[{$_params['id']}]['loop'] = is_array(\$_loop=\$this->_tpl_vars['".$_sTmp."']) ? count(\$_loop) : max(0, (int)\$_loop);";
$_output.= "unset(\$_loop);\n";
$_output.= "\$this->_sections[{$_params['id']}]['name'] = {$_params['id']};\n";
$_output.= "\$this->_sections[{$_params['id']}]['show'] = ".((count($aEdito)>0) ? "true" : "false").";\n";
$_output.= "\$this->_sections[{$_params['id']}]['block'] = \$this->_plugins_stack['block'][count(\$this->_plugins_stack['block'])-1];\n";
$_output.= "\$this->_sections[{$_params['id']}]['max'] = \$this->_sections[{$_params['id']}]['loop'];\n";
$_output.= "if (!\$this->_sections[{$_params['id']}]['show']) \n";
// need to destroy the $_params['id'] block
$_output.= "\t\$this->_plugins_stack['block_action'][] = array({$_params['id']},'delete',{$_params['id']});\n";
$_output.= "else if (\$this->_sections[{$_params['id']}]['show']) :\n";
// need to destroy the $_params['vide'] block
$_output.= "\t\$this->_plugins_stack['block_action'][] = array({$_params['vide']},'delete',{$_params['id']});\n";
$_output.= "\t for(\$this->_sections[{$_params['id']}]['index']=0;\n";
$_output.= "\t\$this->_sections[{$_params['id']}]['index']<\$this->_sections[{$_params['id']}]['max'];\n";
$_output.= "\t\$this->_sections[{$_params['id']}]['index']++) :\n";


return $_output;
}
function _compile_magazine_fin_boucle_edito($tag_attrs, &$compiler){
// html_return
$_output = "";
$_output.= "endfor;endif;\n";
$_output.= "echo \"<!-- /magazine_boucle_edito -->\\n\";\n";
return $_output;
}

4 - in the template

{block id="e_1"}
<div id="edito">
<h3><span>edito :</span></h3>
{boucle_edito id="edito" classement="date" ordre="croissant" vide="edito_vide" borne="0,1" age_max="30"}
titre : {$aedito[edito].titre}<br />
date : {$aedito[edito].date}<br />
maj : {$aedito[edito].maj}<br />
texte : {$aedito[edito].texte}<br />
{/boucle_edito}
</div>
{/block}

{block id="edito_vide"}
<div id="edito">
<h3><span>edito :</span></h3>
Sorry no edito for this month
</div>
{/block}

Sorry for any french comments or text in code ...
_________________
froggies forever.... Wink
Back to top
View user's profile Send private message
webadept
Smarty Regular


Joined: 09 Mar 2004
Posts: 41

PostPosted: Wed Jun 30, 2004 4:26 pm    Post subject: Reply with quote

Hi,

This is cool and has helped me understand some of the pre-complier bits that I've only taken a side long glance at.. and I know I have this slight problem in seeing the world too simplisticlly .. but.. .couldn't the same effect be gained by using an if-then-else in the template? If the image exists, show this, else show that? Maybe I'm missing the world here behind my shaded eyes (probably, and it won't be the first time either Razz ). But I can't help feeling that this is over kill for, (what i believe) is a simple problem.. is precompiling really giving such a great advantage to the code, that an if-else would not render?

<curious>


webadept
Back to top
View user's profile Send private message
smartknight
Smarty n00b


Joined: 15 Nov 2004
Posts: 4

PostPosted: Mon Nov 15, 2004 7:04 pm    Post subject: Reply with quote

This is really Cool Way !

smartknight
Back to top
View user's profile Send private message
mohrt
Administrator


Joined: 16 Apr 2003
Posts: 7368
Location: Lincoln Nebraska, USA

PostPosted: Mon Nov 15, 2004 8:31 pm    Post subject: Reply with quote

Another way of doing this and keeping the template code minimal is to build the template rendering into the function and separate the photo display to another template. So example, add a "template" parameter to your function call:

Code:
{boucle_photo id="photo_1" classement="date" ordre="ASC" vide="photo_1_vide" template="display_photo.tpl"}


Your function would internally assign the $display_photo variable depending on the db results, then return the contents of $smarty->fetch($template). Here is an example of the display_photo.tpl file:

display_photo.tpl
------------------------

Code:
{if $display_photo}
   The photo displayed here are copyrighted by me Blood...
   // show photo here
{else}
   Sorry no pictures are in DBase
{/if}
Back to top
View user's profile Send private message Visit poster's website
Display posts from previous:   
This forum is locked: you cannot post, reply to, or edit topics.   This topic is locked: you cannot edit posts or make replies.    Smarty Forum Index -> Tips and Tricks 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