The macro Prefilter

Copy this contents and past it to ./smarty/plugins/prefilter.macro.php

<?php
/**
 * A prefilter for macros in a smarty-template.
 * @internal ANSI-Chars: @
 * @internal coding:ISO-8859-1
 * @author Stowasser Harald, Freinet GmBH, Germany. <stowasser@freinet.de>
 * @since 14.09.07 16:07
 * @version 0.3
 * @example ../../www-htdocs/test/form/formular.html
 * @package smarty.plugins
 *
 * With this prefilter You can set macros in a smarty-Template.
 * the macros will be replaced before the smarty-compiler does his work
 * The Filter can also handle macros with content.
 * examples:
 *
 *
 *<b>This defines an output for your error-variable</b>
 *<code>
 *  {set_macro error}
 *    <b class="error">{$error}</b>
 *  {/set_macro error}
 *</code>
 *so this call:
 *<code>
 *  {if $ding|has_error}{get_macro error}{/if}
 *</code>
 *will be replaced to:
 *<code>
 *  {if $ding|has_error}<b class="error">{$error}</b>{/if}
 *</code>
 *
 *<b>The examlpe for my label is a litle bit harder:
 *The {$content}-Tag will be replaced with the text between  {get_macro label} and {/get_macro label}</b>
 *<code>
 *  {set_macro label}
 *    {if $form_last_element|is_required}
 *      <label class="pflicht" for="{$form_last_element}">{$content}*</label>
 *    {else}
 *      <label class="normal" for="{$form_last_element}">{$content}</label>
 *    {/if}
 *  {/set_macro label}
 *
 *  {assign var='form_last_element' value='adr_forename'}
 *  {get_macro label}Forename:{/get_macro label}
 *  <input type="text" name="{$form_last_element}" value="{$adresse->getForename()}"/>
 *</code>
 *
 *
 *<b>You cann also define a file from wich macros should be loaded.</b>
 *<code>
 *  {load_macro file='standard_macros.tpl'}
 *</code>
 */

/**
 * Reads a set_macro from text
 * @since 0.2 (14.09.07 16:07)
 * @param String $text The string 2 get the macro
 * @return Array a set with Macros. [0][0]=The hole Macrodef,[0][1]=The Macro name,[0][2]=The Macro text
 */

function prefilter_macro_read_macros( $text ) {
  $macroset = array( );
  $pattern = "/[{] *set_macro .*?[}](.*?)[{] *\/ *set_macro ([\w]*)?.*?[}]/s";
  preg_match_all( $pattern, $text, $macroset );
  return $macroset;
}

/**
 * Merges 2 Macrosets.
 * @see prefilter_macro_read_macros
 * @since 0.2 (14.09.07 16:07)
 * @param Array $arr1 The Array wich will be extended
 * @param Array $arr2 The other Array.
 */
function prefilter_macro_merge_macroset( &$arr1, $arr2 ) {
  if ( count( $arr1 ) != 3 ) {
    $arr1 = $arr2;
  } else {
    $arr1[0]=array_merge( $arr1[0], $arr2[0] );
    $arr1[1]=array_merge( $arr1[1], $arr2[1] );
    $arr1[2]=array_merge( $arr1[2], $arr2[2] );
  }
}

/**
 * Serarch for Macrodefinitions, and replace them.
 * @since 0.2 (14.09.07 16:07)
 * @param string $tpl_source The Source-Code of the Smarty.
 * @param Smarty &$smarty      The Smarty wich has called this filter
 * @throws Exception if File not found in load_macro command.
 * @return string The changed Source-Code.
 */
function smarty_prefilter_macro( $tpl_source, &$smarty ) {
  $macroset = array( );
  // Search for a load_macro-tag:
  $macroload = array( );

  $pattern = "/[{] *load_macro (.*?)[}]/";
  preg_match_all( $pattern, $tpl_source, $macroload );
  // And then delete it from the template:danach die set_macro-tags entfernen
  $tpl_source = preg_replace( "/[{] *load_macro .*?[}]/", "", $tpl_source );
  // Search teh file in the template-path open it and read the macros.
  if ( count( $macroload ) == 2 ) {
    $anz = count( $macroload[1] );
    for ( $i = 0; $i < $anz; $i++ ) {
      preg_match( '/file *= *["\'](.*)["\']/', $macroload[1][$i], $file );
      $file = $file[1];
      $path = $file;
      if ( !file_exists( $path ) ) {
        $path = $smarty->template_dir . $file;
      }
      if ( !file_exists( $path ) ) {
        $path = $smarty->template_dir . '../default-templates/' . $file;
      }
      if ( !file_exists( $path ) ) {
        throw new Exception( "load_macro file:" . $file . " not found" );
      }
      $handle = fopen( $path, "r" );
      $contents = fread( $handle, filesize( $path ) );
      fclose( $handle );
      prefilter_macro_merge_macroset( &$macroset, prefilter_macro_read_macros( $contents ) );
    }
  }
  // Search for a set_macro-tag:
  prefilter_macro_merge_macroset( &$macroset, prefilter_macro_read_macros( $tpl_source ) );

  // And then delete it from the template:danach die set_macro-tags entfernen
  $tpl_source = preg_replace( "/[{] *set_macro .*?[}].*?[{] *\/ *set_macro .*?[}]/s", "", $tpl_source );
  // Now replace the get_macro-tags
  if ( count( $macroset ) == 3 ) {
    $anz = count( $macroset[2] );
    for ( $i = 0; $i < $anz; $i++ ) {
      // is this a macro with content?
      $content = array( );
      $macrotext = $macroset[1][$i];
      $macro = 'get_macro ' . $macroset[2][$i];
      $pattern = "/[{]\\s*" . $macro . "\\s*[}](.*?)[{]\\s*\/ *" . $macro . "\\s*[}]/s";

      preg_match_all( $pattern, $tpl_source, $content );
      if ( count( $content ) > 0 ) {
        // then replace the Content
        $anz2 = count( $content[1] );
        for ( $j = 0; $j < $anz2; $j++ ) {
          $neutext = preg_replace( "/[{] *[$]content.*?[}]/", $content[1][$j], $macrotext );
          $tpl_source = str_replace( $content[0][$j], $neutext, $tpl_source );
        }
      } else {
      }
      //If there is no closing tag just do a replace.
      $macrotext = preg_replace( "/[{]\\s*[$]content.*?[}]/", "", $macrotext );
      $tpl_source = preg_replace( "/[{]\\s*" . $macro . "\\s*[}]/", $macrotext, $tpl_source );
    }
  }
  return $tpl_source;
}
?>