Location: PHPKode > projects > Open Power Template > lib/Opt/Instruction/Snippet.php
<?php
/*
 *  OPEN POWER LIBS <http://www.invenzzia.org>
 *
 * This file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE. It is also available through
 * WWW at this URL: <http://www.invenzzia.org/license/new-bsd>
 *
 * Copyright (c) Invenzzia Group <http://www.invenzzia.org>
 * and other contributors. See website for details.
 *
 */

/**
 * The snippet instruction processor.
 */
	class Opt_Instruction_Snippet extends Opt_Compiler_Processor
	{
		/**
		 * The processor name required by the parent.
		 * @internal
		 * @var string
		 */
		protected $_name = 'snippet';
		/**
		 * The list of available snippets.
		 * @internal
		 * @var array
		 */
		protected $_snippets = array();

		/**
		 * The currently inserted snippet stack used for detecting the infinite recursion.
		 * @internal
		 * @var array
		 */
		protected $_current = array();

		/**
		 * Configures the instruction processor.
		 *
		 * @internal
		 */
		public function configure()
		{
			$this->_addInstructions(array('opt:snippet', 'opt:insert', 'opt:parent'));
			$this->_addAttributes(array('opt:use'));
		} // end configure();

		/**
		 * Resets the processor after the finished compilation and frees the
		 * memory taken by the snippets.
		 *
		 * @internal
		 */
		public function reset()
		{
			foreach($this->_snippets as &$snippetList)
			{
				foreach($snippetList as $snippet)
				{
					$snippet->dispose();
				}
			}
			$this->_snippets = array();
			$this->_current = array();
		} // end reset();
	/*
		public function processNode(Opt_Xml_Node $node)
		{
			$name = '_process'.ucfirst($node->getName());
			$this->$name($node);
		} // end processNode();
		
		public function postprocessNode(Opt_Xml_Node $node)
		{
			$name = '_postprocess'.ucfirst($node->getName());
			$this->$name($node);
		} // end postprocessNode();
	*/
		/**
		 * Processes the opt:use attribute.
		 *
		 * @internal
		 * @param Opt_Xml_Node $node The node the attribute is added to
		 * @param Opt_Xml_Attribute $attr The found attribute.
		 */
		public function processAttribute(Opt_Xml_Node $node, Opt_Xml_Attribute $attr)
		{
			if(isset($this->_snippets[$attr->getValue()]))
			{
				array_push($this->_current, $attr->getValue());
				$snippet = &$this->_snippets[$attr->getValue()];
				
				// Move all the stuff to the fake node.
				if($node->hasChildren())
				{
					$newNode = new Opt_Xml_Element('opt:_');
					$newNode->moveChildren($node);				
					
					$size = sizeof($snippet);
					$snippet[$size] = $newNode;

					$attr->set('snippetObj', $snippet);
					$attr->set('size', $size);
				}
				$node->removeChildren();
				
				// Process the snippets
				$node->set('escaping', $this->_compiler->get('escaping'));
				$this->_compiler->set('escaping', $snippet[0]->get('escaping'));
				foreach($snippet[0] as $subnode)
				{
					$node->appendChild(clone $subnode);
				}

				$node->set('call:use', $attr->getValue());
				$attr->set('postprocess', true);				
			}
		} // end processAttribute();

		/**
		 * A postprocessing routine for opt:use
		 * @internal
		 * @param Opt_Xml_Node $node
		 * @param Opt_Xml_Attribute $attr
		 */
		public function postprocessAttribute(Opt_Xml_Node $node, Opt_Xml_Attribute $attr)
		{
			if(!is_null($attr->get('size')))
			{
				$snippet = $attr->get('snippetObj');
				unset($snippet[$attr->get('size')]);
			}
			// Restore the original escaping state
			$this->_compiler->set('escaping', $node->get('escaping'));
			array_pop($this->_current);
		} // end postprocessAttribute();

		/**
		 * Processes the opt:snippet element.
		 * @internal
		 * @param Opt_Xml_Element $node The found snippet.
		 */
		public function _processSnippet(Opt_Xml_Element $node)
		{
			$params = array(
				'name' => array(0 => self::REQUIRED, self::ID)		
			);
			$this->_extractAttributes($node, $params);
			
			// Assign this snippet					
			if(!isset($this->_snippets[$params['name']]))
			{
				$this->_snippets[$params['name']] = array(0 => $node);
				$current = 0;
			}
			else
			{
				$current = sizeof($this->_snippets[$params['name']]);

				$this->_snippets[$params['name']][] = $node;
			}
			if($node->getParent()->removeChild($node) == 0)
			{
				throw new Opl_Debug_Exception();
			}
			// Remember the template state of escaping for this snippet.
			// This is necessary to make per-template escaping work with
			// the inheritance.
			$node->set('escaping', $this->_compiler->get('escaping'));
				
			// Link "opt:parent" with the parent
			$parentTags = $node->getElementsByTagNameNS('opt', 'parent');
			foreach($parentTags as $parent)
			{
				$parent->set('snippetName', $params['name']);
				$parent->set('snippetId', $current + 1);
			}
		} // end _processSnippet();

		/**
		 * Processes the opt:parent element.
		 * @internal
		 * @param Opt_Xml_Element $node The found element.
		 */
		public function _processParent(Opt_Xml_Element $node)
		{
			$n = $node->get('snippetName');
			$i = $node->get('snippetId');
			// If there is a parent, append it here and execute.
			if(isset($this->_snippets[$n][$i]))
			{
				$node->set('escaping', $this->_compiler->get('escaping'));
				$node->set('single', false);
				$this->_compiler->set('escaping', $this->_snippets[$n][$i]->get('escaping'));

				$master = $node->getParent();

				foreach($this->_snippets[$n][$i] as $subnode)
				{
					$master->insertBefore($cloned = clone $subnode, $node);
					$this->_enqueue($cloned);
				}

				$master->removeChild($node);
				$node->set('postprocess', true);
			}
		} // end _processParent();

		/**
		 * A postprocessing routine for opt:parent
		 * @internal
		 * @param Opt_Xml_Element $node The found element
		 */
		public function _postprocessParent(Opt_Xml_Element $node)
		{
			$this->_compiler->set('escaping', $node->get('escaping'));
		} // end _postprocessParent();

		/**
		 * Processes the opt:insert element.
		 * @internal
		 * @param Opt_Xml_Element $node The found element
		 */
		public function _processInsert(Opt_Xml_Element $node)
		{
			// A support for the dynamically chosen part captured by opt:capture
			if($node->getAttribute('captured') !== NULL)
			{
				$params = array(
					'captured' => array(0 => self::REQUIRED, self::EXPRESSION)
				);
				$this->_extractAttributes($node, $params);
				if($node->hasChildren())
				{
					$node->addBefore(Opt_Xml_Buffer::TAG_BEFORE, 'if(!isset(self::$_capture['.$params['captured'].'])){ ');
					$node->addAfter(Opt_Xml_Buffer::TAG_AFTER, '} else { echo self::$_capture['.$params['captured'].']; } ');
					$this->_process($node);
				}
				else
				{
					$node->addBefore(Opt_Xml_Buffer::TAG_BEFORE, 'if(isset(self::$_capture['.$params['captured'].'])){ echo self::$_capture['.$params['captured'].']; } ');
				}
			}
			else
			{
			// Snippet insertion
				$params = array(
					'snippet' => array(0 => self::REQUIRED, self::ID),
					'ignoredefault' => array(0 => self::OPTIONAL, self::BOOL, false)
				);
				$this->_extractAttributes($node, $params);

				if(in_array($params['snippet'], $this->_current))
				{
					array_push($this->_current, $params['snippet']);
					$err = new Opt_SnippetRecursion_Exception($params['snippet']);
					throw $err->setData($this->_current);
				}
				if(isset($this->_snippets[$params['snippet']]))
				{
					array_push($this->_current, $params['snippet']);
					$snippet = &$this->_snippets[$params['snippet']];

					// Move all the stuff to the fake node.
					if($node->hasChildren() && $params['ignoredefault'] == false)
					{
						$newNode = new Opt_Xml_Element('opt:_');
						$newNode->set('escaping', $this->_compiler->get('escaping'));
						$newNode->moveChildren($node);
						$size = sizeof($snippet);
						$snippet[$size] = $newNode;
						$node->set('insertSize', $size);
					}
					// We must do the cleaning for the inserted node.
					$node->removeChildren();

					// Process the snippets
					$node->set('escaping', $this->_compiler->get('escaping'));
					$this->_compiler->set('escaping', $snippet[0]->get('escaping'));

					foreach($snippet[0] as $subnode)
					{
						$node->appendChild(clone $subnode);
					}
					$this->_process($node);
					$node->set('insertSnippet', $params['snippet']);
					$node->set('postprocess', true);
				}
				else
				{
					// Processing the default content - snippet not found.
					$this->_process($node);
				}
			}
		} // end _processInsert();

		/**
		 * Postprocesses the opt:insert element.
		 * @internal
		 * @param Opt_Xml_Element $node The found element.
		 */
		public function _postprocessInsert(Opt_Xml_Element $node)
		{
			// Freeing the fake node, if necessary.
			if(!is_null($node->get('insertSize')))
			{
				$this->_snippets[$node->get('insertSnippet')][$node->get('insertSize')]->dispose();
				unset($this->_snippets[$node->get('insertSnippet')][$node->get('insertSize')]);
			}

			// Restore the original escaping state
			$this->_compiler->set('escaping', $node->get('escaping'));
			
			array_pop($this->_current);
		} // end _postprocessInsert();

		/**
		 * Returns true, if the snippet with the given name is defined.
		 * @param string $name The snippet name
		 * @return boolean
		 */
		public function isSnippet($name)
		{
			return isset($this->_snippets[$name]);
		} // end isSnippet();		
	} // end Opt_Instruction_Snippet;
Return current item: Open Power Template