📜 ⬆️ ⬇️

Pattern Inheritance in Smarty

Once upon a time, I had to use the well-known Smarty template engine. At first, I, of course, was indignant and shouted, how disgusting is this filler fish Smarty, and then "tasted" and got involved. Those amenities that he gave more than compensated for the thought that there are faster template engines.

I used to build templates using inclusions: at the beginning, header.tpl was connected, at the end - footer.tpl, in the middle something else was needed. In general, the markup was pretty neat, but the feeling that something important was missing was not passing. The final understanding of this something appeared when I happened to write a simple application on Django. And this “something”, as everyone understood, turned out to be an inheritance of patterns . Simple, as well as all ingenious, idea allowed to simplify the templates and get rid of duplicate blocks.


')
The solution turned out to be no more difficult than the very idea of ​​inheritance, which, I remind you, was simple, like everything ingenious :)
Note: in order not to produce things, I will not retell the article about the inheritance of templates in Django , but I recommend reading it in order to understand what is waiting for us and so that you can understand what they do
Contrary to popular belief, one of the main tasks of Smarty is not a trivial replacement of <?php echo $var ?> By more laconic {$var} , but an extension of the basic functionality of plugins. In particular, Smarty allows you to define your own block functions. This is what we use.
Note: unlike Django, here not the single {% extend %} tag will be used, but the {extends}...{/extends} block, within which the inherited blocks will be located. This was done, firstly, because of the simplicity of the implementation, secondly - this approach makes it possible to inherit different templates (well, this is bad - another question; in extreme cases, no one forces to use several {extends} blocks in one template) .
The syntax of the inheritance patterns will be something like this:
parent.tpl:
 <html> <head> <title> Inherit it! </title> </head> <body> <p>Just a paragraph</p> <p>{block name="foo"}It's a parent{/block}</p> </body> </html></pre> 

child.tpl:
 {extends template="parent.tpl"} {block name="foo"}It's a child{/block} {/extends} 

index.php:
 <?php $smarty->display('child.tpl'); ?> 
Especially, I think, it is not necessary to explain anything: before compiling the template, the block {extends} is replaced with the contents of the template, which is specified in the template parameter of the block. All named blocks that were defined inside {extends} overlap the corresponding blocks in the parent template.

And the result of the work looks like this:
 <html> <head> <title> Inherit it! </title> </head> <body> <p>Just a paragraph</p> <p>It's a child</p> </body> </html> 
The idea in brief is as follows: inside the template object, we introduce an associative array, the keys of which are the names of the inherited blocks, and the corresponding values ​​are arrays containing the textual contents of these blocks, stored in the order of their (blocks) call. I agree, the phrase turned out to be abstruse, so it's easier to show in the previous example:
 Array ( [foo] => Array ( [0] => It's a parent [1] => It's a child ) ) 
I hope everything is simple. Now it remains when calling the block in the “get” template from this storage the last element and display it in place of the tags :)

As I wrote above, for the implementation we need to register 2 blocks with the names extends and block , as well as enter the value store.

Let {extends}{/extends} block {extends}{/extends} be responsible for obtaining the source code of the parent template, and {block}{/block} for creating and redefining inherited blocks.

The manual will help us create block plugins:
block.extends.php:
 <?php /** * ,   * * @param array $params  ,     * @param string $content    {extends}..{/extends} * @param mySmarty $smarty    Smarty */ function smarty_block_extends($params, $content, mySmarty $smarty) { /**   .  ! */ if (false === array_key_exists('template', $params)) { $smarty->trigger_error(' ,   !'); } return $smarty->fetch($params['template']); } ?> 
block.block.php:
 <?php /** *       * * @param array $params  ,     * @param string $content    {extends}..{/extends} * @param mySmarty $smarty    Smarty */ function smarty_block_block($params, $content, mySmarty $smarty) { if (array_key_exists('name', $params) === false) { $smarty->trigger_error('   '); } $name = $params['name']; if ($content) { $smarty->setBlock($name, $content); } return $smarty->getBlock($name); } 
Here it must be said that setBlock () and getBlock () are the templates of the template engine, which respectively place and get the text values ​​of the inherited blocks from the stack, which was mentioned above. Expand the Smarty class by entering the stack array and methods:

mySmarty.class.php
 <?php class mySmarty extends Smarty { /** *      * * @var array */ protected $_blocks = array(); /** *   * * @param void * @return void */ public function __construct() { $this->Smarty(); } /** *     * * @param string $key * @param string $value * @return void */ public function setBlock($key, $value) { if (array_key_exists($key, $this->_blocks) === false) { $this->_blocks[$key] = array(); } if (in_array($value, $this->_blocks[$key]) === false) { array_push($this->_blocks[$key], $value); } } /** *       * * @param string $key * @return string */ public function getBlock($key) { if (array_key_exists($key, $this->_blocks)) { return $this->_blocks[$key][count($this->_blocks[$key])-1]; } return ''; } } ?> 


Now, by connecting mySmarty.class.php , you can create an object of class mySmarty and use the charms of template inheritance.

Lazy people can download a ready-made example of templates and touch on in practice (the archive weighs 2.2 kb, Smarty is not included in the package, of course).

Thanks for attention :)

Source: https://habr.com/ru/post/37962/


All Articles