Page 1 of 1

Modified template functions

Posted: Tue Sep 02, 2003 9:26 am
by Xore
after searching thru template.php and finding that the answer to my problem did not exist ( *sniffle* ) i set out to fix it.

It was surprisingly easy... only took me about a half hour, all told...

So, what is this? basically, i find it somewhat of a pain that block vars must be all assigned simultaneously. so, i added to the assign_block_vars an increment supresser so that if this flag is set, it will add the changes to the last block, rather than creating a new one

the other change was to the assign_var_from handle ... which is incapable of assigning values to block variables. so i changed that also (along with the supress_increment thingy.

i'm not so very knowledgeable in the way the assign_var_from_handle works... it might inherently be incapable of working from inside a loop, but i haven't had the opportunity to test.

i would like people's opinons on this, if possible, and the consequences thereof (note: this code is untested, it should work tho, it's 2:30 am right now tho and i'm not up for some pressure testing atm)

Code: Select all

	/**
	 * Inserts the uncompiled code for $handle as the
	 * value of $varname in the root-level. This can be used
	 * to effectively include a template in the middle of another
	 * template.
	 * Note that all desired assignments to the variables in $handle should be done
	 * BEFORE calling this function.
	 */
	function assign_var_from_handle($varname, $handle,$supress_block_increment = false)
	{
		if (!$this->loadfile($handle))
		{
			die("Template->assign_var_from_handle(): Couldn't load template file for handle $handle");
		}

		// Compile it, with the "no echo statements" option on.
		$_str = "";
		$code = $this->compile($this->uncompiled_code[$handle], true, '_str');

		// evaluate the variable assignment.
		eval($code);
		// assign the value of the generated variable to the given varname.
		if (strstr($varname, '.'))
		{
			$lastposition = strrpos($varname,'.');
			$blockname = substr($varname,0,$lastposition);
			$varname = substr($varname,$lastposition+1);
			$this->assign_block_vars($blockname,array($varname => $_str),$supress_block_increment);
		}
		else
		{
			$this->assign_var($varname, $_str);
		}

		return true;
	}
/*
//
// Old function:
//
	function assign_var_from_handle($varname, $handle)
	{
		if (!$this->loadfile($handle))
		{
			die("Template->assign_var_from_handle(): Couldn't load template file for handle $handle");
		}

		// Compile it, with the "no echo statements" option on.
		$_str = "";
		$code = $this->compile($this->uncompiled_code[$handle], true, '_str');

		// evaluate the variable assignment.
		eval($code);
		// assign the value of the generated variable to the given varname.
		$this->assign_var($varname, $_str);

		return true;
	}
*/

Code: Select all

	/**
	 * Block-level variable assignment. Adds a new block iteration with the given
	 * variable assignments. Note that this should only be called once per block
	 * iteration.
	 */
	function assign_block_vars($blockname, $vararray, $surpress_increment = false)
	{
		if ( !$surpress_increment )
		{
			if (strstr($blockname, '.'))
			{
				// Nested block.
				$blocks = explode('.', $blockname);
				$blockcount = sizeof($blocks) - 1;
				$str = '$this->_tpldata';
				for ($i = 0; $i < $blockcount; $i++)
				{
					$str .= '[\'' . $blocks[$i] . '.\']';
					eval('$lastiteration = sizeof(' . $str . ') - 1;');
					$str .= '[' . $lastiteration . ']';
				}
				// Now we add the block that we're actually assigning to.
				// We're adding a new iteration to this block with the given
				// variable assignments.
				$str .= '[\'' . $blocks[$blockcount] . '.\'][] = $vararray;';

				// Now we evaluate this assignment we've built up.
				eval($str);
			}
			else
			{
				// Top-level block.
				// Add a new iteration to this block with the variable assignments
				// we were given.
				$this->_tpldata[$blockname . '.'][] = $vararray;
			}
		}
		else
		{
			if (strstr($blockname, '.'))
			{
				// Nested block.
				$blocks = explode('.', $blockname);
				$blockcount = sizeof($blocks);
				$str = '$this->_tpldata';
				for ($i = 0; $i < $blockcount; $i++)
				{
					$str .= '[\'' . $blocks[$i] . '.\']';
					eval('$lastiteration = sizeof(' . $str . ') - 1;');
					$str .= '[' . $lastiteration . ']';
				}
				// Now we add the block that we're actually assigning to.
				reset ($vararray);
				while (list($key,$val) = each($vararray))
				{
					$current_string = $str . '[$key] = $val';
					// Now we evaluate this assignment we've built up.
					eval($current_string);
				}
			}
			else
			{
				// Top-level block.
				// Add a new iteration to this block with the variable assignments
				// we were given.
				$lastiteration = sizeof($this->_tpldata[$blockname . '.']) - 1;
				reset ($vararray);
				while (list($key,$val) = each($vararray))
				{
					$this->_tpldata[$blockname . '.'][$lastiteration][$key] = $val;
				}
			}
		}

		return true;
	}
/*
//
// Old function:
//
	function assign_block_vars($blockname, $vararray)
	{
		if (strstr($blockname, '.'))
		{
			// Nested block.
			$blocks = explode('.', $blockname);
			$blockcount = sizeof($blocks) - 1;
			$str = '$this->_tpldata';
			for ($i = 0; $i < $blockcount; $i++)
			{
				$str .= '[\'' . $blocks[$i] . '.\']';
				eval('$lastiteration = sizeof(' . $str . ') - 1;');
				$str .= '[' . $lastiteration . ']';
			}
			// Now we add the block that we're actually assigning to.
			// We're adding a new iteration to this block with the given
			// variable assignments.
			$str .= '[\'' . $blocks[$blockcount] . '.\'][] = $vararray;';

			// Now we evaluate this assignment we've built up.
			eval($str);
		}
		else
		{
			// Top-level block.
			// Add a new iteration to this block with the variable assignments
			// we were given.
			$this->_tpldata[$blockname . '.'][] = $vararray;
		}

		return true;
	}
*/
Edit: added some reset()s

Posted: Tue Sep 02, 2003 10:15 am
by Xore
Ok, well i did some testing...

this 3rd function is necessary for clearing data when you (while in loop) re-include the same file, as it otherwise will continue accumulating data in rows, such that each pass will include both that loop's data, as well as the last loops data. this is a problem, so here is the fix...

Code: Select all

	/**
	 * Block-level variable clearing. Removes a block of data so it can be re-written
	 * fresh (for iterative file handled arrays, when different data is needed)
	 */
	function clear_block_vars($blockname)
	{
		if (strstr($blockname, '.'))
		{
			// i don't know how the heck this would be used, if ever.
			// i can't think of a situation where it would be useful personally
			// but, who knows... Only the top-level block makes sense to me
			// Nested block.
			$blocks = explode('.', $blockname);
			$blockcount = sizeof($blocks) - 1;
			$str = '$this->_tpldata';
			for ($i = 0; $i < $blockcount; $i++)
			{
				$str .= '[\'' . $blocks[$i] . '.\']';
				eval('$lastiteration = sizeof(' . $str . ') - 1;');
				$str .= '[' . $lastiteration . ']';
			}
			// Now we add the block that we're actually assigning to.
			// We're adding a new iteration to this block with the given
			// variable assignments.
			$str .= '[\'' . $blocks[$blockcount] . '.\'] = array();';

			// Now we evaluate this assignment we've built up.
			eval($str);
		}
		else
		{
			// Top-level block.
			// Add a new iteration to this block with the variable assignments
			// we were given.
			$this->_tpldata[$blockname . '.'] = array();
		}

		return true;
	}
[/code]

Posted: Tue Sep 02, 2003 10:29 am
by Xore
If a developer sees this.. is it possible that such functionality could be included in phpbb2.2 ? I looked through the most recent snapshot and it didn't have assign_var_from_handle() ... i haven't looked at 2.2 templates yet, so i don't know if this could be an issue or not, or if a similar functionality is now going by a different name.

cheers :-)

Posted: Tue Sep 02, 2003 2:48 pm
by Arty
Hi,

As you told in thread for eXtreme Styles mod this code has conflicts with my mod. So here is modified code that works with ALL versions of template.php and it is much faster than your code:

function assign_var_from_handle:

Code: Select all

	function assign_var_from_handle($varname, $handle, $surpress_block_increment = false)
	{
		ob_start();
		$res = $this->pparse($handle);
		if ($pos = strpos($varname, '.') !== false) 
		{
			$blockname = substr($varname, 0, $pos); 
			$varname = substr($varname, $pos + 1); 
			$this->assign_block_vars($blockname, array($varname => ob_get_contents()), $surpress_block_increment);
		}
		else
		{
			$this->_tpldata['.'][0][$varname] = ob_get_contents();
		}
		ob_end_clean();
		return $res;
	}
here is modified assign_block_vars:

Code: Select all

	function assign_block_vars($blockname, $vararray, $surpress_increment = false) 
	{
		if (strstr($blockname, '.'))
		{
			// Nested block.
			$blocks = explode('.', $blockname);
			$blockcount = sizeof($blocks) - 1;

			$str = &$this->_tpldata; 
			for($i = 0; $i < $blockcount; $i++) 
			{ 
				$str = &$str[$blocks[$i].'.']; 
				$str = &$str[sizeof($str)-1]; 
			} 
			// Now we add the block that we're actually assigning to. 
			// We're adding a new iteration to this block with the given 
			//	variable assignments. 
			if($surpress_increment)
			{
				$str = &$str[$blocks[$blockcount].'.'];
				$count = sizeof($str) - 1;
				if($count >= 0)
				{
					// adding only if there is at least one item
					$str[$count] = array_merge($str[$count], $vararray);
				}
			}
			else
			{
				$str[$blocks[$blockcount].'.'][] = $vararray;
			}
		}
		else
		{
			// Top-level block.
			// Add a new iteration to this block with the variable assignments
			// we were given.
			if($surpress_increment)
			{
				$str = &$this->_tpldata[$blockname.'.'];
				$count = sizeof($str) - 1;
				if($count >= 0)
				{
					// adding only if there is at least one item
					$str[$count] = array_merge($str[$count], $vararray);
				}
			}
			else
			{
				$this->_tpldata[$blockname.'.'][] = $vararray;
			}
		}
		return true;
	}
and here is faster version of clear_block_vars:

Code: Select all

	//
	// clears block vars
	//
	function clear_block_vars($blockname) 
	{
		if (strstr($blockname, '.'))
		{
			// Nested block.
			$blocks = explode('.', $blockname);
			$blockcount = sizeof($blocks) - 1;

			$str = &$this->_tpldata; 
			for($i = 0; $i < $blockcount; $i++) 
			{ 
				$str = &$str[$blocks[$i].'.']; 
				$str = &$str[sizeof($str)-1]; 
			} 
			$str[$blocks[$blockcount].'.'] = array();
		}
		else
		{
			$this->_tpldata[$blockname.'.'] = array();
		}
		return true;
	}
I haven't tested this, but 90% that it is error-free. Please test it with your mod.

Posted: Tue Sep 02, 2003 2:54 pm
by Xore
much appreciated :-)

i'll probably be putting some stuff together later today

Posted: Tue Sep 02, 2003 3:30 pm
by Arty
..actually there is one bug - in both your and mine versions.

if function assign_var_from_handle is called with variable name that contains more than one dot then function will detect blockname incorrectly. instead of searching for first dot in string we should search for last one.

here is fixed function:

Code: Select all

	function assign_var_from_handle($varname, $handle, $surpress_block_increment = false)
	{
		ob_start();
		$res = $this->pparse($handle);
		$varrev = strrev($varname);
		if ($pos = strpos($varrev, '.') !== false) 
		{
			$blockname = strrev(substr($varrev, $pos + 1)); 
			$varname = strrev(substr($varrev, 0, $pos)); 
			$this->assign_block_vars($blockname, array($varname => ob_get_contents()), $surpress_block_increment);
		}
		else
		{
			$this->_tpldata['.'][0][$varname] = ob_get_contents();
		}
		ob_end_clean();
		return $res;
	}

Posted: Tue Sep 02, 2003 8:04 pm
by Daijoubu
Why use

Code: Select all

if ($pos = strpos($varname, '.') !== false)
I tried once and got some weird behavior, better simply use

Code: Select all

if ($pos = strpos($varname, '.') === true)

Posted: Tue Sep 02, 2003 8:48 pm
by Xore
CyberAlien wrote: ..actually there is one bug - in both your and mine versions.

if function assign_var_from_handle is called with variable name that contains more than one dot then function will detect blockname incorrectly. instead of searching for first dot in string we should search for last one.


Actually, if you look closely at my code, you'll notice that i used the strrpos() function rather than the strpos() function, which returns the last instance, rather than the first instance of needle in haystack

Code: Select all

$lastposition = strrpos($varname,'.');

Posted: Tue Sep 02, 2003 8:59 pm
by Arty
Ohh... then its just my error. Sorry about that.
Daijoubu wrote: if ($pos = strpos($varname, '.') === true)

This won't work - strpos returns number or false. So your if() will never be valid. And if you use == instead of === then your if will work but only when pos is > 0.