Bug 502 - [Chameleon] Recursive preprocessing enhancement
: [Chameleon] Recursive preprocessing enhancement
Status: NEW
: Chameleon
Core
: 1.99
: PC Linux
: P2 enhancement
: FUTURE
Assigned To:
:
:
:
:
:
  Show dependency treegraph
 
Reported: 2004-07-07 13:57 by
Modified: 2004-11-03 09:29 (History)


Attachments


Note

You need to log in before you can comment on or make changes to this bug.


Description From 2004-07-07 13:57:28
Currently, Chameleon preprocessor do the parsing of [##] tags and then [$$]
tags. So you can't include [$$] tags in [##].

pxniw from the list suggest a patch that will do [$$], [##] and again [$$]:

// Start ADDED by PXNIW (Wanted to parse $$ tags
before ## tags
// replace all [$something$] to the correct url var
value
// This is duplicate code from below so $$ parses
before ##
        $nPos = strpos($this->mszTemplate, "[$");
        while($nPos !== false)
        {
            $nEndPos = strpos($this->mszTemplate,
"$]", $nPos);
            $szTag = substr($this->mszTemplate, $nPos,
$nEndPos-$nPos+2);

            if
(isset($oApp->moHttpFormVars->maszVars[strtoupper(substr($szTag,
2, -2))]))
                $this->mszTemplate =&
str_replace($szTag, 
                       
$oApp->moHttpFormVars->maszVars[strtoupper(substr($szTag,
2, -2))],
                        $this->mszTemplate);
            $nPos = strpos($this->mszTemplate, "[$",
$nPos+2);
        }
// END ADDED by PXNIW

        // First, include all files to include.
        $nPos = strpos($this->mszTemplate, "[#");
        while ($nPos !== false)
        {
            $nEndPos = strpos($this->mszTemplate,
"#]");

            if ($nEndPos === false)
                break;

            $szTemplateName =
substr($this->mszTemplate, $nPos+2, $nEndPos-$nPos-2);

            // Make a copy of the current teplate
            $szTemplate = $this->mszTemplate;

            $oApp->CWCLoadTemplate($szTemplateName);

            $this->mszTemplate =&
str_replace("[#$szTemplateName#]", $oApp->mszTemplate,
$szTemplate);

            $nPos = strpos($this->mszTemplate, "[#");
        }

        // Then, replace all [$something$] to the
correct url var value
        $nPos = strpos($this->mszTemplate, "[$");
        while($nPos !== false)
        {
            $nEndPos = strpos($this->mszTemplate,
"$]", $nPos);
            $szTag = substr($this->mszTemplate, $nPos,
$nEndPos-$nPos+2);

            if
(isset($oApp->moHttpFormVars->maszVars[strtoupper(substr($szTag,
2, -2))]))
                $this->mszTemplate =&
str_replace($szTag, 
                       
$oApp->moHttpFormVars->maszVars[strtoupper(substr($szTag,
2, -2))],
                        $this->mszTemplate);
            $nPos = strpos($this->mszTemplate, "[$",
$nPos+2);
        }

        if (strlen($this->mszTemplate) == 0)
            return 0;

        $this->maszElements = array();
        $this->maszPlaceholders = array();

        $this->mszTemplate = preg_replace_callback(
$this->mszPattern,
                    array( &$this, "ParseCallback" ),
$this->mszTemplate );

        return $this->NumElements();
    }
------- Comment #1 From 2004-07-07 13:58:18 -------
Suggestion from Paul:

Julien, sorry, I didn't really follow this thread too closely so I am not
entirely sure what the patch does ...  here is my interpretation:

1. process [$$] replacements  << added by pxniw
2. process [##] includes
3. process [$$] replacements

if this is right, then I have some comments ...

* if we are allowing multiple passes, should we run the include process twice
(i.e. pages included using [##] could include [##] inside them?

* simply adding more steps isn't going to solve the recursive cases ...

* there is a lot of code duplication

I suggest a more robust implementation that takes the code and divides it into
two functions

/**
 * Replace text in target by searching for blocks delimited by the start
 * and end delimiters.  The caller provides a method that takes a text
 * string and returns the value to be inserted in place of the tag, or
 * false if no tag replacement is possible.  This method returns the
 * number of replacements that actually happened.
 *
 * A note on fReplacement.  It can be a string (name of function to
 * call) or an array.  If it is an array, it must contain 2 elements,
 * the first element is the name of the function to call.  The second
 * element is either the name of a class, in which case the function
 * is called as a static method of the class using call_user_func, or
 * it is an object and is called using call_user_method.
 *
 * @param fReplacer a function that returns the text to be inserted
 * @param szText  the text to be scanned for replacements
 * @param szStart a text string that defines the start of a replacement
 *        block
 * @param szEnd a text string that defines the end of a replacement
 *        block
 * @return the number of replacements that happened.
 */
ProcessReplacements( $fReplacement, $szText, $szStart = "[$", $szEnd = "$]" )
{
  $nReplacements = 0;
  ... search for start and end tags, assign to $szKey ... in loop
  //start loop
  {
    if (is_array($fReplacement) &&
        isset($fReplacement[1]))
    {
        if (is_object($fReplacement[1]))
        {
        //use call_user_method
            $szReplacement = call_user_method($fReplacement[0],
                             $fReplacement[1],
                             $szKey );
        }
        else
        {
            //use call_user_func, assume that array is in
            $szReplacement = call_user_func( $fReplacement, $szKey );
     }
     else
     {
       //this would be an error
     }
   }
   else
   {
        //use call_user_func, assume that array is in
        $szReplacement = call_user_func( $fReplacement, $szKey );
   }
   if ($szReplacment !=== false)
   {
       //process replacement now
       $nReplacements ++;
   }
   else
   {
      //leave text alone, no replacement to happen.
   }
  //end loop
  return $nReplacements;
}


Then in the TemplateParser code, we would use something like the following block

$nReplacements = 1;  //just to get us into the loop
$nLevel = 10;
while ($nReplacements > 0 && $nLevel > 0)
{
  $nReplacements = 0;
  $nReplacements = $this->ProcessReplacements(
          array( "GetReplacement", $this ), $this->mszTemplate );
          "[$", "$]" );
  $nReplacements += $this->ProcessReplacements(
          array( "GetInclude", $this ), $this->mszTemplate,
          "[#", "#]" );
  $nLevel ++;
}

And we would add the following methods to the TemplateParser

/*
 * return a value from the URL using the passed value as the key.
 * If the key is not present, return false, otherwise return the
 * value.
 */
GetReplacement( $szTextToReplace )
{
  ....
}

/*
 * return the contents of a file based on the file name passed.
 * If the file does not exist, return false, otherwise return the
 * contents of the file.
 */
GetInclude( $szFileToInclude )
{
  ....
}

Cheers,

Paul 
------- Comment #2 From 2004-07-07 14:16:38 -------
To avoid to much performance hit we can also do a linear parsing. I mean do the
replacement and in the include step, take the file to include and do the
replacement on only its content, not the whole Chameleon template 2-3 times.

What do you think?

function ProcessReplacement($szTextToReplace)
{
    $szTextToReplace = preg_replace_callback("/(\\[$(.*?)$\\])/",
"GetReplacement", $szTextToReplace);

    $szTextToReplace = preg_replace_callback("/(\\[#(.*?)#\\])/", "GetInclude",
$szTextToReplace);

    return $szTextToReplace;
}

GetReplacement( $szTextToReplace )
{
  ....
}

GetInclude( $aszTextToReplace )
{
    // Get the file to include
    $szTemplateName = $aszTextToReplace[2];
    $szTemplate = implode("\n", file($szTemplateName));

    // Reprocess only the file to include
    $szTemplate = ProcessReplacement($szTemplate);

    return 
}
------- Comment #3 From 2004-07-07 15:26:38 -------
yes I agree.  So in the ProcessReplacement function, for each result coming from
an include, you would actually call ProcessReplacement on the result before
pasting it into the original text?  This could require some changes to the
approach I suggested.
------- Comment #4 From 2004-07-07 15:36:41 -------
Wow it's nice to see how short my thought can be summarized. However we won't be
able to do things like:

[$[#file/to/[$include$].txt#]$]

But I think this is OK. We should not let users do things like that. ;)
------- Comment #5 From 2004-07-07 23:29:02 -------
I think this is a reasonable limitation :)
------- Comment #6 From 2004-07-08 13:25:23 -------
Changed target to 1.99 Final. 

Paul, is it reasonable to get this done for 1.99?
------- Comment #7 From 2004-08-10 15:37:33 -------
Changing Version to 1.99 (2.0 not being worked on yet).
------- Comment #8 From 2004-08-10 20:49:42 -------
Changed Severity to normal.
------- Comment #9 From 2004-11-03 09:29:02 -------
future enhancement