PHP Classes
Icontem

File: core/classes/Tags.class.php


  Search   All class groups All class groups   Latest entries Latest entries   Top 10 charts Top 10 charts   Newsletter Newsletter   Blog Blog   Forums Forums   Help FAQ Help FAQ  
  Login   Register  
Recommend this page to a friend! ReTweet ReTweet Stumble It! Stumble It! Bookmark in del.icio.us Bookmark in del.icio.us
  Classes of Marius Zadara  >  PAX  >  core/classes/Tags.class.php  
File: core/classes/Tags.class.php
Role: Class source
Content type: text/plain
Description: Tags class
Class: PAX
Interpret XML command scripts with PHP classes
 

Contents

Class file image Download
<?php


/**
 * Page DocBlock definition
 * @package org.zadara.marius.pax
 */

/**
 * Tags definition file.
 * This class will be responsbile with loading the tags from the definition file,
 * also for filtering (tags, tag's content).
 * 
 * @author Marius Zadara <marius@zadara.org>
 * @category Classes
 * @copyright (C) 2008-2009 Marius Zadara
 * @license Free for non-comercial use
 * @package org.zadara.marius.pax
 * @final 
 * @see File
 * @see ITags
 * @version 6.0
 * @since 5.0
 */
final class Tags extends File implements ITags  
{
	/**
	 * The tags definition file content.
	 * 
	 * @access private
	 * @var string
	 */
	private $tagsFileContent;
	
	
	/**
	 * The array with all the tags from the definition file.
	 * It is used to keep track of a tag and not search it again in the file
	 *
	 * @access private
	 * @var array
	 */
	private $tags;	
	
	/**
	 * Class constructor.
	 * 
	 * @access public
	 */
	public function __construct()
	{
		// call the parent constructor
		parent::__construct();
		
		// init the tags file content
		$this->tagsFileContent = null;
		
		// init the tags array
		$this->tags = null;
	}

	/**
	 * Method to check if a tag is allowed.
	 *
	 * @access public
	 * @param string <b>$rootTag</b> The root tag from the definition file
	 * @param string <b>$tag</b> The searched tag
	 * @return boolean
	 */
	public function isAllowedTag($rootTag, $tag)
	{
		// if the tag has been searched before,
		// return the previous result
		if (isset($this->tags[$tag]))
			return $this->tags[$tag];

		// check the tags file content
		// try to load the tag definition file for the first tme
		if (!is_object($this->tagsFileContent))
		{			
			$this->tagsFileContent = @simplexml_load_file($this->path);
			
			// in case of failure, 
			// throw exception
			if ($this->tagsFileContent === false)
				throw new PAXException(sprintf(Messages::$MSG_033, $this->path), 33);				
		}
	
		// search the tag using an XPath expression
		$result = @$this->tagsFileContent->xPath(sprintf("/%s/%s", $rootTag, $tag));
		
		// init the tags array the first time		
		if (is_null($this->tags))
			$this->tags = array();
		
		// set the acceptance for this tag
		// if the XPath expression failed, is the same as the tag is not accepted
		$this->tags[$tag] = is_array($result) ? (sizeof($result) > 0) : false;

		// return the result
		return $this->tags[$tag];
	}
	
	
	/**
	 * Method to filter the tags according to the definition file.
	 * Throws exception if error encountered
	 *
	 * @access public
	 * @static 
	 * @param config <b>$config</b> The PAX config object
	 * @param config <b>$elements</b> The PAX elements object
	 * @param config <b>$directories</b> The PAX directories object
	 * @param config <b>$filenames</b> The PAX filenames object
	 * @param array <b>$nodes</b> The array with the current nodes 
	 * @param array <b>$namespaces</b> The array with the current namespaces
	 * @param string <b>$paxNsSeparator</b> The separator used in tag namespace definition
	 * @return void
	 */
	public static function filterTags(&$config, &$elements, $directories, $filenames, &$nodes, &$namespaces, $paxNsSeparator)
	{	
		// catch any exceptions	
		try 
		{
			// get the filter tags flag from the config object
			// set the default value to true
			$filterTags = $config->get("filterTags", true);
			
			// get the attribute name 
			// using this attribute, this filtering can be overwritten from the source itself
			$filterTagsAttributeName = $config->get("filterTagsAttributeName", "filterTags");
									
			// get the final status of the filtering 
			// either from the config or from the definition
			if (isset($nodes[0]['attributes'][$filterTagsAttributeName]))
			{
				// check to see if the attribute value is in the 'true' dictionary			
				$filterTags = Model::isInList($nodes[0]['attributes'][$filterTagsAttributeName], $elements->get("trueTexts")); 
			}
						
			
			// continue with the filtering
			// only if the status is true
			if ($filterTags)
			{		
				$allowedTags = array();
				$allowNoTags = $config->get("allowNoTags", false);
				
				// allow the source without any tag definition?
				if (!$allowNoTags)
				{
					$tags = new Tags();
					
					// get the tags path from the configuration
					$tagsPath = $directories->get("definitions", "definitions");
					$tagsPath .= $filenames->get("tags", "tags.xml");
	
					$tags->setPath($tagsPath);
										
					// validate the path
					// if any error, throw exception
					if (!$tags->exists())
						throw new PAXException(sprintf(Messages::$MSG_030, $tagsPath), 30);

					if (!$tags->isOrdinary())
						throw new PAXException(sprintf(Messages::$MSG_031, $tagsPath), 31);
						
					if (!$tags->isReadable())
						throw new PAXException(sprintf(Messages::$MSG_031, $tagsPath), 32);
				}
				
				// get the tags definition file root
				$tagsRoot = $elements->get("tagsRoot", "tags");

				// create a file object
				// this object will be used to check the node definition file
				$file = new File();				
				
				
				// parse each node from the list
				foreach ($nodes as $index => $nodeData)
				{
				    // get the namespace and tag name based on the node data
				    $names = self::extractNamesFromTag($nodeData['tag'], ":");
				    
				    // if failed ...
				    if ($names === false)
				    {
				        // mark the node as invalid and continue
				        $nodes[$index] = false;
				        continue;
				    }
				    
				    // namespace found?
				    if ($names['namespace'] !== false)
				    {
				        // declared?
    					if (!isset($namespaces[$names['namespace']]))
    						throw new PAXException(sprintf(Messages::$MSG_023, $names['namespace']), 23);

    					// update the directory using the namespace
    					$namespaceDirectory = $namespaces[$names['namespace']];						
    					$namespaceClass = $names['tagName'];
    					
						// get the file format from using the namespace
						$namespaceFileFormat = $filenames->get("namespaceClassFileFormat", "[CLASS].class.php");						
						$namespaceFile = str_ireplace("[CLASS]", $namespaceClass, $namespaceFileFormat);
    					
						// update the namespace file path
						$namespaceFile = $namespaceDirectory . $namespaceFile;

						// update the file path
						$file->setPath($namespaceFile);
						
						// check the file
						// in case of error, throw exception
						if (!$file->exists())
							throw new PAXException(sprintf(Messages::$MSG_024, $namespaceFile), 24);
						
						if (!$file->isOrdinary())
							throw new PAXException(sprintf(Messages::$MSG_025, $namespaceFile), 25);
							
						if (!$file->isReadable())
							throw new PAXException(sprintf(Messages::$MSG_026, $namespaceFile), 26);

						// load the file
						require_once $namespaceFile;
						
						// update the tag name 
						// so we eliminate the namespace (is not needed anymore, class previously loaded)
						$nodes[$index]['tag'] = $names['tagName'];
						
						unset($usedNamespace, $namespaceDirectory, $namespaceClass, $namespaceFileFormat);
				    }    		
				    else 
				    {
						// do the same validations for the non-namespace node
												
						$modelClassFileFormat = $filenames->get("modelClassFileFormat", "[CLASS].class.php");
						$modelClassFile = str_ireplace("[CLASS]", $nodeData['tag'], $modelClassFileFormat);						
						$modelClassFile = $directories->get("implementations") . $modelClassFile;

						// set the path of the file
						$file->setPath($modelClassFile);
						
						// check the file
						if (!$file->exists())
							throw new PAXException(sprintf(Messages::$MSG_027, $modelClassFile), 27);
						
						if (!$file->isOrdinary())
							throw new PAXException(sprintf(Messages::$MSG_028, $modelClassFile), 28);
							
						if (!$file->isReadable())
							throw new PAXException(sprintf(Messages::$MSG_029, $modelClassFile), 29);
						
						// load the file
						require_once $modelClassFile;	
						
						unset($modelClassFileFormat, $modelClassFile);
												
						if (!$tags->isAllowedTag($tagsRoot, $nodeData['tag']))
							$nodes[$index] = false;
				    }
				}
			}
		}
		catch (PAXException $pe)
		{
			// in case of exception, send it further
			throw $pe;
		}	
		catch (Exception $e)
		{
			// in case of exception, send it further
			throw $e;
		}
	}
	
	/**
	 * Method to filter the tag content.
	 * Throws exception in case of error.
	 *
	 * @access public
	 * @static 
	 * @param config <b>$config</b> The PAX config object
	 * @param config <b>$elements</b> The PAX elements object
	 * @param array <b>$nodes</b> The PAX nodes array
	 * @return void
	 */
	public static function filterTagContent(&$config, $elements, &$nodes)
	{
		// catch any exceptions
		try 
		{
			// load the filtering status from the config
			$filterTagContent = $config->get("filterTagContent", true);			
			
			// load the filtering status from the file
			$filterTagContentAttributeName = $config->get("filterTagContentAttributeName", "filterTagContent");
											
			if (isset($nodes[0]['attributes'][$filterTagContentAttributeName]))
			{
				// if the attribute exists, 
				// update the config value with the value from attribute
				// in order to continue filtering, the value must be in the 'true texts' dictionary				
				$filterTagContent = Model::isInList($nodes[0]['attributes'][$filterTagContentAttributeName], $elements->get("trueTexts"));
			}			
			
			// continue with the filtering
			if ($filterTagContent)
			{
				// get the separator used in tag namespace definition
				$paxNsSeparator = $elements->get("paxNsSeparator", ":");
				
				// get the validation method name
				// this method, if foun in the tag class, will be called to filter the content
				$validationMethodName = $elements->get("tagContentValidationMethodName", "validateContent");				
				
				// parse the nodes list
				foreach ($nodes as $index => $nodeData)
				{
					// if invalid node, skip
					if ($nodeData === false)
						continue;
					
					// if node is closed, continue 
					// (closed nodes don't have content attached)
					if ($nodeData['type'] == 'close')
						continue;
						
					// skip the nodes without a content
					if (!isset($nodeData['value']))
						continue;

					// get the position of the separator in the tag name
					// in order to get the class name
					$paxNsSepPos = strpos($nodeData['tag'], $paxNsSeparator);												
						
					if ($paxNsSepPos !== false)
						$currentNodeName = substr($nodeData['tag'], $paxNsSepPos + 1);
					else
						$currentNodeName = $nodeData['tag']; 
					
					// beautify the class name
					$currentNodeName = ucfirst($currentNodeName);

					// at this point, the class should already exists (loaded at filtering nodes method)
					// if not found, throw exception
					if (!class_exists($currentNodeName))
						throw new PAXException(sprintf(Messages::$MSG_038, $currentNodeName), 38);						
					
					// if the method does not exists in the class definition, 
					// skip filtering
					if (!method_exists($currentNodeName, $validationMethodName))
						continue;
						
					// create the filtering content evaluation string	
					$evalString = sprintf("\$newValue = %s::%s('%s');", $currentNodeName, $validationMethodName, $nodeData['value']);

					// if could not evaluate the string, 
					// throw exception
					if (@eval($evalString) === false)
						throw new PAXException(sprintf(Messages::$MSG_040, $currentNodeName, $nodeData['value']), 40);	
					
					// update the tag content value with the new value
					// the function should return null in case of invalid content
					$nodes[$index]['value'] = is_null($newValue) ? false : $newValue; 
				}
			}
		}
		catch (PAXException $pe)
		{
			// in case of exception, throw it further
			throw $pe;		
		}				
		catch (Exception $e)
		{
			// in case of exception, throw it futher
			throw $e;
		}
	}
	
	
	/**
	 * Method to compile the instructions.
	 *
	 * @access public
	 * @param config <b>$instructions</b> The PAX instructions
	 * @param array <b>$nodes</b> The nodes list
	 * @return void
	 */
	public function compileInstructions(&$instructions, &$nodes)
	{
		if (is_null($instructions))
			return;

		// create the pattern
		$pattern = new Pattern();
		$instructionExtractor = new InstructionExtractor();
		$instructionEvaluator = new InstructionEvaluator();
		$currentInstructions = array();	
			
		$startDelimiter = $instructions->get("startDelimiter", "!#");
		$endDelimiter = $instructions->get("endDelimiter", "#!");
		
		// parse each node
		foreach ($nodes as $nodeIndex => $nodeData)
		{
			if ($nodeData === false)
				continue;
				
			if (!isset($nodeData['value']))
				continue;
			
			try
			{
				// try to extract the instructions from the content of the node
				$currentInstructions = $instructionExtractor->extract($nodeData['value'], $startDelimiter, $endDelimiter);
			}
			catch (PAXException $pe)
			{
				// if exception, throw it further
				throw $pe;
			}
			catch (Exception $e)
			{
				// if exception, throw it further
				throw $e;
			}
			
			// validate the instructions
			if ($currentInstructions === false)
				continue;
				
			// compile each instruction
			// and replace it by its value
			foreach ($currentInstructions as $instruction)
			{
				$replacePattern = $pattern->makeInstructionReplacePattern($instruction, $startDelimiter, $endDelimiter);
				$nodes[$nodeIndex]['value'] = InstructionReplacer::replace($replacePattern, $instructionEvaluator->evaluate($instruction), $nodes[$nodeIndex]['value']);
			}
		}	
	}
	

	/**
	 * Method to extract the namespace and tag name based on the node data.
	 * 
	 * @access public
	 * @static 
	 * @param string <b>$tagName</b> The name of the tag as appears in the node data
	 * @param string <b>$namespaceSep</b> The separator used for delimiting the namespace and the tag name
	 * @return mixed False if invalid separator or array('namespace' => namespace, 'tagName' => name of the tag)
	 */
	public static function extractNamesFromTag($tagName, $namespaceSep)
	{
	    // assume the worst
	    $names = false;
	    
        $tagName = trim($tagName);
        
        if ($tagName == "")
            return $names;
        
        // init the return object as array         
        $names = array();                
            
        // get the separator position
        $namespaceSepPos = stripos($tagName, $namespaceSep);
        
        // if the separator has not been found,
        // create the return array as containing only the tag name
        if ($namespaceSepPos === false)
        {
            $names['namespace'] = false;
            $names['tagName'] = $tagName;            
        }
        else 
        {
            // else get both the namespace and the tag name
            // using substrings and separator position
            $names['namespace'] = substr($tagName, 0, $namespaceSepPos);
            $names['tagName'] = substr($tagName, $namespaceSepPos + 1);                       
        }
            
        // return the data collected so far
        return $names;
	}
	
	
	
	/**
	 * Class destructor.
	 * 
	 * @access private
	 */
	function __destruct()
	{
	}
}


?>

 
  Advertise on this site Advertise on this site   Site map Site map   Statistics Statistics   Site tips Site tips   Privacy policy Privacy policy   Contact Contact  

For more information send a message to :
info at phpclasses dot org.
Copyright (c) Icontem 1999-2009 PHP Classes - PHP Class Scripts
  PHP Book Reviews - Reviews of books and other products