PHP Classes

File: core/classes/Tags.class.php

Recommend this page to a friend!
  Classes of Marius Zadara   PAX   core/classes/Tags.class.php   Download  
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
Author: By
Last change: Version update
Date: 15 years ago
Size: 15,727 bytes
 

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() { } } ?>