⬆️ ⬇️

Native template engine

I have been using native templates for quite some time, but for some reason, many people associate native templates with constructs like:



$title = 'My title' ; include( 'templates/index.html' ); * This source code was highlighted with Source Code Highlighter .
  1. $title = 'My title' ; include( 'templates/index.html' ); * This source code was highlighted with Source Code Highlighter .
  2. $title = 'My title' ; include( 'templates/index.html' ); * This source code was highlighted with Source Code Highlighter .
$title = 'My title' ; include( 'templates/index.html' ); * This source code was highlighted with Source Code Highlighter .


  1. < html > < head > < title > <? php echo $ title ? > </ title > </ head >
  2. <! - ... ->
* This source code was highlighted with Source Code Highlighter .




That is, the variable was determined and clicked on the html file. I think this is a completely wrong approach. Why?

')

First, all the variables passed to the template must be stored in one place (the property of the template engine class).

Secondly, in the template engine there should not be access to variables that are not passed to it, and to functions that are not defined in it.

Thirdly, the set of functions necessary for work should be defined.



Thus, I came to the conclusion that the template engine is needed, but it should not be a sophisticated Smarty-type brake.

The ideology of block template engines (XTemplate, for example) is not appealing to me because there are no branches as such, there are only cycles.



Because I wrote my own.



Let's start with the fact that we need to deal with error handling. I use exceptions for this purpose, therefore we define an exception class:



  1. class STempException extends Exception {}
* This source code was highlighted with Source Code Highlighter .


Here we do not need anything else. Moving on to the template maker itself (what the methods do is briefly written in the comments, I will describe it in more detail below):



  1. class STemp
  2. {
  3. / **
  4. * Directory names templates are located.
  5. *
  6. * @var string.
  7. * @access private.
  8. * /
  9. private $ path;
  10. / **
  11. * Name of the template.
  12. *
  13. * @var string.
  14. * @access private.
  15. * /
  16. private $ template;
  17. / **
  18. * Where assigned template vars are kept.
  19. *
  20. * @var array.
  21. * @access private.
  22. * /
  23. private $ variables = array ();
  24. / **
  25. * Parameters of the template engine.
  26. *
  27. * @var array.
  28. * @access private
  29. * /
  30. private $ params = array (
  31. 'xss_protection' => true
  32. 'exit_after_display' => true
  33. 'endofline_to_br' => false
  34. );
  35. / **
  36. * File that include in template.
  37. *
  38. * @var string.
  39. * @access private.
  40. * /
  41. private $ include_file;
  42. / **
  43. * The class constructor. Set where the templates are located.
  44. *
  45. * @param where the templates are located, the default 'templates /'.
  46. * @access public.
  47. * /
  48. public function __construct ($ path = 'templates /' )
  49. {
  50. $ this -> path = $ path;
  51. }
  52. / **
  53. * Set parameters of template engine.
  54. *
  55. * @param string $ param name of the parameter.
  56. * @param bool $ value value of the parameter.
  57. * @return bool TRUE if parameter set, FALSE if didn't set.
  58. * @access public.
  59. * /
  60. public function setParam ($ param, $ value )
  61. {
  62. if (isset ($ this -> params [$ param])) {
  63. $ this -> params [$ param] = $ value ;
  64. return true ;
  65. }
  66. return false ;
  67. }
  68. / **
  69. *
  70. * @param string $ include_file path to include file.
  71. * @access public.
  72. * /
  73. public function setIncludeFile ($ include_file)
  74. {
  75. $ this -> include_file = $ this -> path. $ include_file;
  76. if (! file_exists ($ this -> path. $ include_file))
  77. throw new STempException ( 'Include file' . $ this -> include_file. 'not exitst' );
  78. }
  79. / **
  80. * Assigns values ​​to template variables.
  81. *
  82. * @param string $ name the template variable name.
  83. * @param mixed $ value.
  84. * @access public.
  85. * /
  86. public function assign ($ name, $ value )
  87. {
  88. $ this -> variables [$ name] = $ value ;
  89. }
  90. / **
  91. * Executes and displays the template results.
  92. *
  93. * @param string $ template the template name.
  94. * @access public.
  95. * /
  96. public function display ($ template)
  97. {
  98. $ this -> template = $ this -> path. $ template;
  99. if (! file_exists ($ this -> template))
  100. throw new STempException ( 'Template file' . $ template. 'not exitst' );
  101. require_once ($ this -> template);
  102. if ($ this -> params [ 'exit_after_display' ])
  103. exit;
  104. }
  105. / **
  106. * Get value of template variable.
  107. *
  108. * @param string $ name the template variable name.
  109. * @return mixed variable FALSE if variable not set.
  110. * @access private.
  111. * /
  112. private function __get ($ name)
  113. {
  114. if (isset ($ this -> variables [$ name])) {
  115. $ variable = $ this -> variables [$ name];
  116. if ($ this -> params [ 'xss_protection' ])
  117. $ variable = $ this -> xssProtection ($ variable);
  118. if ($ this -> params [ 'endofline_to_br' ])
  119. $ variable = $ this -> endoflineToBr ($ variable);
  120. return $ variable;
  121. }
  122. return NULL;
  123. }
  124. / **
  125. * Include file
  126. *
  127. * @access private
  128. * /
  129. private function includeFile ()
  130. {
  131. if (! file_exists ($ this -> include_file))
  132. throw new STempException ( 'Include file' . $ this -> include_file. 'not found' );
  133. require_once ($ this -> include_file);
  134. }
  135. / **
  136. * For the formation of endings of words.
  137. *
  138. * @param int $ value number.
  139. * @param string $ word0 word in the singular.
  140. * @param string $ word1 word in the plural (2, 3).
  141. * @param string $ word2 word in the plural.
  142. * @param string $ separator separator, default ''.
  143. * @return string formed words
  144. * @access private.
  145. * /
  146. private function morph ($ value , $ word0, $ word1, $ word2, $ separator = '' )
  147. {
  148. if (preg_match ( '/ 1 \ d $ /' , $ value ))
  149. return $ value . $ separator. $ word2;
  150. elseif (preg_match ( '/ 1 $ /' , $ value ))
  151. return $ value . $ separator. $ word0;
  152. elseif (preg_match ( '/ (2 | 3 | 4) $ /' , $ value ))
  153. return $ value . $ separator. $ word1;
  154. else
  155. return $ value . $ separator. $ word2;
  156. }
  157. / **
  158. * For protection from XSS.
  159. *
  160. * @param mixed $ variable data for protection.
  161. * @return mixed protected data.
  162. * @access private.
  163. * /
  164. private function xssProtection ($ variable)
  165. {
  166. if (is_array ($ variable)) {
  167. $ protected = array ();
  168. foreach ($ variable as $ key => $ value )
  169. $ protected [$ key] = $ this -> xssProtection ($ value );
  170. return $ protected ;
  171. }
  172. return htmlspecialchars ($ variable);
  173. }
  174. / **
  175. * Inserts HTML line breaks before all newlines in a string.
  176. *
  177. * @param mixed $ variable data for protection.
  178. * @return mixed data where string with <br /> inserted before all newlines.
  179. * @access private.
  180. * /
  181. private function endoflineToBr ($ variable)
  182. {
  183. if (is_array ($ variable)) {
  184. $ protected = array ();
  185. foreach ($ variable as $ key => $ value )
  186. $ protected [$ key] = $ this -> endoflineToBr ($ value );
  187. return $ protected ;
  188. }
  189. return nl2br ($ variable);
  190. }
  191. }
* This source code was highlighted with Source Code Highlighter .




In the constructor, we can specify the path to the templates directory (temlates / by default).



Using the setParam method, we can set the template parameters. There are only three of them (that's enough for me, if necessary, you can add parameters). The first parameter - xss_protection - as the name implies, is needed to protect against the xss vulnerability. If the parameter value is set to true, all variables that we use in the template are automatically processed by the htmlspecialchars function (including array elements) before returning. The second parameter - exit_after_display - is needed so that, if necessary, we can stop the execution of the script after the template is displayed. The third parameter, endofline_to_br, processes all variables before return (including array elements) with the nl2br function.



With the setIncludeFile method, we can set the plugin pattern. The common template index.tpl.php is very often used, and a changeable part is connected to it, depending on the conditions. This is the way to automate this process. If the included file does not exist, an exception is thrown.



The assign method is used to transfer variables to a template.



The display method displays a pattern. If the template file does not exist, an exception is thrown. If the exit_after_display parameter is set to true, this method also terminates the script (almost always the display of the template is the last action).



The magic method __get returns the value of the variable passed to the template. If the variable is not defined, returns NULL. Depending on the parameters, variables before return can be processed.



The includeFile method includes the file assigned by the setIncludeFile method and throws an exception if this file is not found.



The morph method, not quite “template-like”, is used to form the correct ending of words relating to numerals. That is, 1 comment, 2 comments, 5 comments. In the method you need to pass the number itself, three different options and, optionally, a word delimiter (by default, non-breaking space).



The xssProtection method processes data by the htmlspecialchars function. If an array is input, then it is recursively searched and all its elements are processed.



The endoflineToBr method processes data using the nl2br function. If the array is input, then, as in the previous method, it recursively enumerates and processes all its elements.



How does it look in practice? Suppose we need to print an article and comments to it. Data on the article in the $ article array, comments - in $ comments.



Controller:

  1. $ stemp = new STemp ();
  2. $ stemp-> assign ( "title" , $ article [ 'title' ]);
  3. $ stemp-> assign ( "article" , $ article);
  4. $ stemp-> assign ( "comments" , $ comments);
  5. try {
  6. $ stemp-> setIncludeFile ( "article.tpl.php" );
  7. $ stemp-> display ( "index.tpl.php" );
  8. } catch (STempException $ e) {
  9. die ( 'STemp error:' . $ e-> getMessage ());
  10. }
* This source code was highlighted with Source Code Highlighter .




Template index.tpl.php:

  1. < html >
  2. < head >
  3. < title > <? php echo $ this- > title? > </ title >
  4. </ head >
  5. < body >
  6. <? php $ this- > includeFile ()? >
  7. </ body >
  8. </ html >
* This source code was highlighted with Source Code Highlighter .




Template article.tpl.php:

  1. < h1 > <? php echo $ this- > article ['title']? > </ h1 >
  2. <? php $ this- > setParam ('xss_protection', false); $ this- > setParam ('endofline_to_br', true)? >
  3. < div class = "content" >
  4. <? php echo $ this- > article ['content']? >
  5. </ div >
  6. < p > <? php echo $ this- > morph (count ($ this- > comments), 'comment', 'comment', 'comments')? > : </ p >
  7. <? php $ this- > setParam ('xss_protecttion', true)? >
  8. <? php foreach ($ this- > comments as $ key = > $ value) {? >
  9. < p class = "user" > <? php echo $ value [ 'username' ]? > : </ p >
  10. < p class = "comment" > <? php echo $ value [ 'text' ]? > </ p >
  11. <? php }? >
* This source code was highlighted with Source Code Highlighter .




Download class .



The use of the class in personal needs is allowed without restrictions. When reprinting an article or source code, including, in part, a link to me (to my site ) is required.

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



All Articles