Source for file TemplateParser.php

Documentation is available at TemplateParser.php

  1. <?php
  2.     /**
  3.      * Template Parser Class
  4.      *
  5.      * @copyright Copyright (c) 2003-2007 Mirchev Ideas Ltd. All rights reserved.
  6.      * @package MIPHPF
  7.      */
  8.     
  9.     /**
  10.      * Template parser section
  11.      * @copyright Copyright (c) 2003-2007 Mirchev Ideas Ltd. All rights reserved.
  12.      * @package MIPHPF
  13.      */
  14.     {
  15.         public $_sectionName;
  16.         public $_iterationsCount;
  17.         public $_values;
  18.         
  19.         /**
  20.          * Associative array with the subsections. The key is the subsection name
  21.          */
  22.         public $_subsections = array();
  23.         
  24.         /**
  25.          * Constructs the object
  26.          * All params are optional
  27.          *
  28.          * @see setSectionInfo for an example
  29.          * @param string $sectionName the name of the section as named in the template
  30.          * @param int $iterationsCount the number of times this section will be repeated
  31.          * @param array $values array of arrays with the values
  32.          */
  33.         public function __construct($sectionName ''$iterationsCount 1$values array())
  34.         {
  35.             $this->setSectionInfo($sectionName$iterationsCount$values);
  36.         }
  37.         
  38.         /**
  39.          * Sets up the section
  40.          * 
  41.          * Example:
  42.          * <code>
  43.          * $values = array(
  44.          *     'VariableName' => 'VariableValue',
  45.          *     'VariableName2' => 'VariableValue2',
  46.          *     'VariableName3' => array('Value1', 'Value2', 'Value3', 'Value4'),
  47.          * );
  48.          * setSectionInfo('testSection', 4, $values);
  49.          * </code>
  50.          * 
  51.          * @param string $sectionName the name of the section as named in the template
  52.          * @param int $iterationsCount the number of times this section will be repeated
  53.          * @param array $values array of arrays with the values
  54.          */
  55.         public function setSectionInfo($sectionName$iterationsCount$values array())
  56.         {
  57.             $this->_sectionName = $sectionName;
  58.             $this->_iterationsCount = $iterationsCount;
  59.             $this->_values = $values;
  60.         }
  61.         
  62.         /**
  63.          * Sets the section name
  64.          *  
  65.          * @param string $sectionName the name of the section as named in the template
  66.          */
  67.         public function setSectionName($sectionName)
  68.         {
  69.             $this->_sectionName = $sectionName;
  70.         }
  71.         
  72.         /**
  73.          * Set the number of times this section will be repated
  74.          * 
  75.          * @param int $iterationsCount the number of times this section will be repeated
  76.          */
  77.         public function setIterationsCount($iterationsCount)
  78.         {
  79.             $this->_iterationsCount = $iterationsCount;
  80.         }
  81.         
  82.         /**
  83.          * Sets the section values
  84.          * 
  85.          * @see setSectionInfo for more info
  86.          * @param array $values array of arrays with the values
  87.          */
  88.         public function setValues($values)
  89.         {
  90.             $this->_values = $values;
  91.         }
  92.         
  93.         /**
  94.          * Adds section values
  95.          * 
  96.          * @see setSectionInfo for more info
  97.          * @param array $values array of arrays with the values
  98.          */
  99.         public function addValues($values)
  100.         {
  101.             $this->_values = $this->_values + $values;
  102.         }
  103.         
  104.         /**
  105.          * Adds a subsection to this section.
  106.          * In the template the subsection must be inside this section
  107.          * 
  108.          * @param miTemplateParserSectionInfo $subsection 
  109.          */
  110.         public function addSubsection(miTemplateParserSectionInfo $subsection)
  111.         {
  112.             $this->_subsections[$subsection->_sectionName$subsection;
  113.         }
  114.         
  115.         /**
  116.          * Adds subsections array
  117.          * The number of subsections must match the number of iterations of the outer section
  118.          * 
  119.          * @param string $subsectionName 
  120.          * @param array $subsections 
  121.          */
  122.         public function addSubsectionsArray($subsectionName$subsections)
  123.         {
  124.             $this->_subsections[$subsectionName$subsections;
  125.         }
  126.     }
  127.     
  128.     
  129.     /**
  130.      * Parses templates
  131.      * 
  132.      * Usage:
  133.      * 1. create a template parser object
  134.      * 2. add template parser section infos (optional step)
  135.      * 3. use readTemplate() ot setContents()
  136.      * 4. assign template variables
  137.      * 5. parse the template
  138.      *
  139.      * @copyright Copyright (c) 2003-2006 Mirchev Ideas Ltd. All rights reserved.
  140.      * @package MIPHPF
  141.      */
  142.     class miTemplateParser {
  143.         const TEMPLATE_PARSER_START_TAG '<mi:section name="';
  144.         const TEMPLATE_PARSER_START_TAG_LEN '18';
  145.         const TEMPLATE_PARSER_START_TAG2 '">';
  146.         const TEMPLATE_PARSER_START_TAG2_LEN '2';
  147.         const TEMPLATE_PARSER_END_TAG '</mi:section>';
  148.         const TEMPLATE_PARSER_END_TAG_LEN '13';
  149.         const TEMPLATE_PARSER_SECTION_TAG 'mi:section';
  150.     
  151.         const TEMPLATE_PARSER_PREPROCESS_AT_ITERATIONS 5;
  152.  
  153.         
  154.         /**
  155.          * Array with sections
  156.          * 
  157.          * @access protected
  158.          */
  159.         protected $_sectionInfos = array();
  160.         
  161.         /**
  162.          * Array with sections
  163.          * 
  164.          * @access protected
  165.          */
  166.         protected $_templateSections = array();
  167.                 
  168.         /**
  169.          * Associative array of template variables
  170.          * They will be used after all sections have been parsed
  171.          * 
  172.          * @access protected
  173.          */
  174.         protected $_templateVars = array();
  175.         
  176.         
  177.         /**
  178.          * The contents of the template file
  179.          * 
  180.          * @access protected
  181.          */
  182.         protected $_templateFileContents = '';
  183.         
  184.  
  185.         /**
  186.          * Reads the template file
  187.          *
  188.          * @access public
  189.          * @param String $filename 
  190.          */
  191.         public function readTemplate($filename)
  192.         {
  193.             $pathname miSettings::singleton()->get('MI_TEMPLATE_BASEDIR'$filename;
  194.             $fd fopen($pathname'rb');
  195.             $this->_templateFileContents = fread($fdfilesize($pathname));
  196.             fclose($fd);
  197.             
  198.             $this->parseSections();
  199.         }
  200.         
  201.         
  202.         /**
  203.          * Sets the contents of the template from string
  204.          * Alternative to reading it from file
  205.          * 
  206.          * @access public
  207.          * @param string $contents 
  208.          */
  209.         public function setContents($contents)
  210.         {
  211.             $this->_templateFileContents = $contents;
  212.             $this->parseSections();
  213.         }
  214.         
  215.         
  216.         /**
  217.          * Parses the template and returns the result
  218.          *
  219.          * @access public
  220.          * @return string the parsed contents
  221.          */
  222.         public function templateParse()
  223.         {
  224.             $html $this->templateParseSubsection($this->_templateSections$this->_sectionInfos);
  225.             return strtr($html$this->_templateVars);
  226.         }
  227.         
  228.         /**
  229.          * Shows the parsed template
  230.          * 
  231.          * @access public
  232.          */
  233.         public function templateShow()
  234.         {            
  235.             echo $this->templateParse();
  236.         }
  237.         
  238.         /**
  239.          * Parses a subsection
  240.          * 
  241.          * @param array $templateSections 
  242.          * @param array $sectionInfos 
  243.          * @param int $subsectionIndex (optional)
  244.          * @return string the parsed string
  245.          */
  246.         protected function templateParseSubsection($templateSections$sectionInfos$subsectionIndex 0)
  247.         {
  248.             $html '';
  249.             foreach ($templateSections as $templateSection{
  250.                 $name $templateSection['name'];
  251.                 
  252.                 // If it is an end just add the contents
  253.                 if ($name == 'END'{
  254.                     $html .= $templateSection['contents'];
  255.                     continue;
  256.                 }
  257.                 
  258.                 $html .= $templateSection['prefix'];
  259.                 
  260.                 // Find the section info
  261.                 if (empty($sectionInfos[$name]))
  262.                     continue;
  263.                 $sectionInfo $sectionInfos[$name];
  264.                 if (is_array($sectionInfo)) {
  265.                     $sectionInfo $sectionInfo[$subsectionIndex];
  266.                 }
  267.                 
  268.                 // Check if we have subsections that are arrays
  269.                 $hasSubsectionsArray false;
  270.                 foreach ($sectionInfo->_subsections as $subsection{
  271.                     if (is_array($subsection)) {
  272.                         $hasSubsectionsArray true;
  273.                         break;
  274.                     }
  275.                 }
  276.                 
  277.                 if (!$hasSubsectionsArray{
  278.                     if (isset($templateSection['subsections']))
  279.                         $contents $this->templateParseSubsection($templateSection['subsections']$sectionInfo->_subsections);
  280.                     else
  281.                         $contents $templateSection['contents'];
  282.                 else
  283.                     $contents '';
  284.                 
  285.                 if ($sectionInfo->_iterationsCount self::TEMPLATE_PARSER_PREPROCESS_AT_ITERATIONS{
  286.                     // If more than 5 iterations do preprocessing -
  287.                     // split the array variables from normal variables
  288.                     $arrayValues $arrayKeys $normalValues $normalKeys array();
  289.                     foreach ($sectionInfo->_values as $key => $r{
  290.                         if (is_array($r)) {
  291.                             $arrayValues[$r;
  292.                             $arrayKeys[$key;
  293.                         else {
  294.                             $normalValues[$r;
  295.                             $normalKeys[$key;
  296.                         }
  297.                     }
  298.                     $search array_merge($normalKeys$arrayKeys);
  299.                     
  300.                     for ($i 0$i $sectionInfo->_iterationsCount$i++{
  301.                         
  302.                         $replace $normalValues;
  303.                         foreach ($arrayValues as $r)
  304.                             $replace[$r[$i];
  305.                         
  306.                         if ($hasSubsectionsArray)
  307.                             $contents $this->templateParseSubsection($templateSection['subsections']$sectionInfo->_subsections$i);
  308.                         $html .= str_replace($search$replace$contents);
  309.                     }
  310.                 else {
  311.                     $search array_keys($sectionInfo->_values);
  312.                     for ($i 0$i $sectionInfo->_iterationsCount$i++{
  313.                         
  314.                         $replace array();
  315.                         foreach ($sectionInfo->_values as $r)
  316.                             $replace[is_array($r$r[$i$r;
  317.                         
  318.                         if ($hasSubsectionsArray and isset($templateSection['subsections']))
  319.                             $contents $this->templateParseSubsection($templateSection['subsections']$sectionInfo->_subsections$i);
  320.                         $html .= str_replace($search$replace$contents);
  321.                     }
  322.                 }
  323.             }
  324.             
  325.             return $html;
  326.         }
  327.         
  328.         
  329.         /**
  330.          * Parse the template file sections
  331.          * 
  332.          * @access protected
  333.          */
  334.         protected function parseSections()
  335.         {
  336.             $this->_templateSections = array();
  337.             $this->parseSingleSection(00$this->_templateSections);
  338.         }
  339.         
  340.         /**
  341.          * Parse a template section recursive method
  342.          * 
  343.          * @param int $lastTagEnd 
  344.          * @param int $startPos 
  345.          * @param array $sections 
  346.          * @access protected
  347.          */
  348.         protected function parseSingleSection($lastTagEnd$startPos&$sections)
  349.         {
  350.             $theTemplateContents &$this->_templateFileContents;
  351.             
  352. //            $nameStart = 0; // name start
  353. //            $nameEnd = 0; // This is start of end of the start tag
  354. //            $nextTagStart = 0; // The points to the current tag beginning - to the mi:section
  355. //            $pos = 0;    // The end of the last tag
  356.             
  357.             $pos $startPos;
  358.             $inSection false;
  359.             $section array();
  360.  
  361.             do {
  362.                 // Next tag start
  363.                 $nextTagStart strpos($theTemplateContentsself::TEMPLATE_PARSER_SECTION_TAG$pos);
  364.                 if ($nextTagStart === false{
  365.                     $section['name''END';
  366.                     $section['contents'substr($theTemplateContents$pos);
  367.                     $sections[$section;
  368.                     break;
  369.                 }
  370.                 
  371.                 // Check if it is an end tag
  372.                 if (($nextTagStart >= 2and substr_compare($theTemplateContentsself::TEMPLATE_PARSER_END_TAG$nextTagStart-2self::TEMPLATE_PARSER_END_TAG_LEN== 0{
  373.                     
  374.                     if ($inSection{
  375.                         $section['contents'substr($theTemplateContents$pos$nextTagStart-$pos);
  376.                         $sections[$section;
  377.                         $section array();
  378.                         
  379.                         $inSection false;
  380.                         $lastTagEnd $nextTagStart-self::TEMPLATE_PARSER_END_TAG_LEN;
  381.                         $pos $lastTagEnd;
  382.                     else {
  383.                         $section['name''END';
  384.                         $section['contents'substr($theTemplateContents$pos$nextTagStart-$pos);
  385.                         $sections[$section;
  386.                         
  387.                         return $nextTagStart-2;
  388.                     }
  389.                     continue;
  390.                 }
  391.                 
  392.                 // Check if it is a start tag
  393.                 if (($nextTagStart >= 1and substr_compare($theTemplateContentsself::TEMPLATE_PARSER_START_TAG$nextTagStart-1self::TEMPLATE_PARSER_START_TAG_LEN== 0{
  394.                     
  395.                     if ($inSection{
  396.                         // Do subcall
  397.                         $section['subsections'array();
  398.                         $pos $this->parseSingleSection($pos$nextTagStart-1$section['subsections']);
  399.                         $sections[$section;
  400.                         $section array();
  401.                         
  402.                         // Skip past the end tag that had the subcall return
  403.                         $inSection false;
  404.                         $lastTagEnd $pos self::TEMPLATE_PARSER_END_TAG_LEN;
  405.                         $pos $lastTagEnd;
  406.                     else {
  407.                         $inSection true;
  408.                         
  409.                         $nameStart $nextTagStart-1+self::TEMPLATE_PARSER_START_TAG_LEN;
  410.                         $nameEnd strpos($theTemplateContentsself::TEMPLATE_PARSER_START_TAG2$nameStart);
  411.                         if ($nameEnd === false{
  412.                             break;    // Exception
  413.                         }
  414.  
  415.                         $name substr($theTemplateContents$nameStart$nameEnd $nameStart);
  416.                         $section['name'$name;
  417.                         $section['prefix'substr($theTemplateContents$lastTagEnd$nextTagStart-$lastTagEnd);
  418.                         
  419.                         $pos $nameEnd self::TEMPLATE_PARSER_START_TAG2_LEN;
  420.                     }
  421.                     continue;
  422.                 }
  423.                 
  424.                 // not a tag
  425.                 $pos $nextTagStart+1;
  426.             while (true);
  427.             
  428.             return $pos;
  429.         }
  430.         
  431.         /**
  432.          * Set the section infos. Clears all previous section infos
  433.          * 
  434.          * @access public
  435.          * @param array $sectionInfos 
  436.          */
  437.         public function setSectionInfos($sectionInfos)
  438.         {
  439.             $this->_sectionInfos = array();
  440.             foreach ($sectionInfos as $sectionInfo)
  441.                 $this->_sectionInfos[$sectionInfo->_sectionName$sectionInfo;
  442.         }
  443.         
  444.         /**
  445.          * Add new section info.
  446.          * If a previous section info with the same name exists it will be overwritten.
  447.          * 
  448.          * @access public
  449.          * @param miTemplateParserSectionInfo $sectionInfo 
  450.          */
  451.         public function addSectionInfo($sectionInfo)
  452.         {
  453.             $this->_sectionInfos[$sectionInfo->_sectionName$sectionInfo;
  454.         }        
  455.         
  456.         /**
  457.          * Returns the section info with the requested name
  458.          * 
  459.          * @param string $sectionInfoName 
  460.          * @return miTemplateParserSectionInfo|falsethe section info object, or false if not found
  461.          */
  462.         public function getSectionInfo($sectionInfoName)
  463.         {
  464.             if (isset($this->_sectionInfos[$sectionInfoName]))
  465.                 return $this->_sectionInfos[$sectionInfoName];
  466.             return false;
  467.         }
  468.         
  469.         /**
  470.          * Assigns a variable to be replaced
  471.          *
  472.          * @access public
  473.          * @param string $name variable name, usually %%VAR_NAME%%
  474.          * @param string $value the contents of the variable. usually escaped with htmlenities()
  475.          */
  476.         public function assign($name$value)
  477.         {
  478.             $this->_templateVars[$name$value;
  479.         }
  480.         
  481.         /**
  482.          * Assigns a array of variables to be replaced
  483.          *
  484.          * @access public
  485.          * @param array $pairs variable name is the key, the contents is the value
  486.          */
  487.         public function assignArray($pairs)
  488.         {
  489.             $this->_templateVars = array_merge($this->_templateVars$pairs);
  490.         }
  491.         
  492.         /**
  493.          * Assigns a list of variables. Both array should have equal sizes, as counted by count()
  494.          * The first variable in the list is assigned the first value, the second variable, the seoncd value, and so on
  495.          * 
  496.          * @access public
  497.          * @param array $keys the keys with the variable names
  498.          * @param array $values the values
  499.          */
  500.         public function assignList($keys$values)
  501.         {
  502.             reset($values);
  503.             foreach ($keys as $key{
  504.                 $value each($values);
  505.                 $this->_templateVars[$key$value[1];
  506.             }
  507.         }
  508.  
  509.         /**
  510.          * Retrieves an assigned variable value
  511.          *
  512.          * @access public
  513.          * @param string $name the name of the variable
  514.          * @return mixed the value of the variable
  515.          */
  516.         public function &get($name)
  517.         {
  518.             return $this->_templateVars[$name];
  519.         }
  520.     }
  521. ?>

Documentation generated on Thu, 08 May 2008 16:57:49 +0300 by phpDocumentor 1.4.1