Changeset 2632

Show
Ignore:
Timestamp:
07/31/08 14:59:32 (5 months ago)
Author:
impl
Message:

branches/david-xml_only_config_system (refs #519): Add new namespaces for 1.0; introduce RelaxNG validation for factories.xml; implement parts of AgaviXmlConfig?(DomElement?|DomDocument?); implement the factories XML config handler; bugfixes

Location:
branches/david-xml_only_config_system
Files:
2 added
12 modified

Legend:

Unmodified
Added
Removed
  • branches/david-xml_only_config_system/samples/app/config/config_handlers.xml

    r2618 r2632  
    44  <configuration> 
    55     
    6     <!-- <handler pattern="%core.config_dir%/factories.xml" class="AgaviXmlFactoryConfigHandler" validate="%core.agavi_dir%/config/xsd/factories.xsd"> 
    7       <validation>%core.agavi_dir%/config/xsd/factories.xsd</validation> 
    8       <validation>%core.agavi_dir%/config/sch/config_handlers.sch</validation> 
     6    <handler pattern="%core.config_dir%/factories.xml" class="AgaviXmlFactoryConfigHandler"> 
     7      <validation>%core.agavi_dir%/config/rng/factories.rng</validation> 
     8      <!-- <validation>%core.agavi_dir%/config/sch/config_handlers.sch</validation> --> 
    99      <transformation>%core.agavi_dir%/config/xsl/factories.xsl</transformation> 
    10     </handler> --> 
     10    </handler> 
    1111     
    1212  </configuration> 
  • branches/david-xml_only_config_system/src/config/AgaviBaseConfigHandler.class.php

    r2511 r2632  
    3535abstract class AgaviBaseConfigHandler extends AgaviParameterHolder 
    3636{ 
    37   /** 
    38    * Retrieve the parameter node values of the given item's parameters element. 
    39    * 
    40    * @param      ConfigValueHolder The node that contains a parameters chiild. 
    41    * @param      array             As associative array of parameters that will 
    42    *                               be overwritten if appropriate. 
    43    * @param      boolean           Whether or not values should be literalized. 
    44    * 
    45    * @return     array An associative array of parameters 
    46    * 
    47    * @author     Dominik del Bondio <ddb@bitxtender.com> 
    48    * @since      0.11.0 
    49    */ 
    50   protected function getItemParameters($itemNode, $oldValues = array(), $literalize = true) 
    51   { 
    52     $data = array(); 
    53     if($itemNode->hasChildren('parameters')) { 
    54       foreach($itemNode->parameters as $node) { 
    55         if(!$node->hasAttribute('name')) { 
    56           // create a new entry in in the array and get they key of the new 
    57           // created entry (the last in the array). The value doesn't matter 
    58           // since it will be overwritten anyways 
    59           $data[] = 0; 
    60           end($data); 
    61           $name = key($data); 
    62         } else { 
    63           $name = $node->getAttribute('name'); 
    64         } 
    65         if($node->hasChildren('parameters')) { 
    66           $data[$name] = (isset($oldValues[$name]) && is_array($oldValues[$name])) ? $oldValues[$name] : array(); 
    67           $data[$name] = $this->getItemParameters($node, $data[$name], $literalize); 
    68         } else { 
    69           $data[$name] = $literalize ? AgaviToolkit::literalize($node->getValue()) : $node->getValue(); 
    70         } 
    71       } 
    72     } 
    73     // we can NOT use array_merge here, since it would break numeric keys 
    74     foreach($data as $key => $value) { 
    75       $oldValues[$key] = $value; 
    76     } 
    77     return $oldValues; 
    78   } 
    79  
    8037  /** 
    8138   * Generate the code for returning from execute(). 
  • branches/david-xml_only_config_system/src/config/AgaviConfigHandler.class.php

    r2511 r2632  
    4747   */ 
    4848  protected $parser = null; 
     49   
     50  /** 
     51   * Retrieve the parameter node values of the given item's parameters element. 
     52   * 
     53   * @param      ConfigValueHolder The node that contains a parameters chiild. 
     54   * @param      array             As associative array of parameters that will 
     55   *                               be overwritten if appropriate. 
     56   * @param      boolean           Whether or not values should be literalized. 
     57   * 
     58   * @return     array An associative array of parameters 
     59   * 
     60   * @author     Dominik del Bondio <ddb@bitxtender.com> 
     61   * @since      0.11.0 
     62   */ 
     63  protected function getItemParameters($itemNode, $oldValues = array(), $literalize = true) 
     64  { 
     65    $data = array(); 
     66    if($itemNode->hasChildren('parameters')) { 
     67      foreach($itemNode->parameters as $node) { 
     68        if(!$node->hasAttribute('name')) { 
     69          // create a new entry in in the array and get they key of the new 
     70          // created entry (the last in the array). The value doesn't matter 
     71          // since it will be overwritten anyways 
     72          $data[] = 0; 
     73          end($data); 
     74          $name = key($data); 
     75        } else { 
     76          $name = $node->getAttribute('name'); 
     77        } 
     78        if($node->hasChildren('parameters')) { 
     79          $data[$name] = (isset($oldValues[$name]) && is_array($oldValues[$name])) ? $oldValues[$name] : array(); 
     80          $data[$name] = $this->getItemParameters($node, $data[$name], $literalize); 
     81        } else { 
     82          $data[$name] = $literalize ? AgaviToolkit::literalize($node->getValue()) : $node->getValue(); 
     83        } 
     84      } 
     85    } 
     86    // we can NOT use array_merge here, since it would break numeric keys 
     87    foreach($data as $key => $value) { 
     88      $oldValues[$key] = $value; 
     89    } 
     90    return $oldValues; 
     91  } 
    4992 
    5093  /** 
  • branches/david-xml_only_config_system/src/config/AgaviConfigHandlersConfigHandler.class.php

    r2599 r2632  
    5353    // parse the config file 
    5454    $configurations = $this->orderConfigurations(AgaviConfigCache::parseConfig($config, false, $this->getValidationFile(), $this->parser)->configurations, AgaviConfig::get('core.environment')); 
    55      
     55                                                                                                                                                                              
    5656    // init our data arrays 
    5757    $handlers = array(); 
  • branches/david-xml_only_config_system/src/config/AgaviConfigParser.class.php

    r2547 r2632  
    8484  { 
    8585    foreach($nodes as $node) { 
    86       if($node->nodeType == XML_ELEMENT_NODE && (!$node->namespaceURI || $node->namespaceURI == AgaviXmlConfigParser::AGAVI_ENVELOPE_NAMESPACE_1_0)) { 
     86      if($node->nodeType == XML_ELEMENT_NODE && (!$node->namespaceURI || $node->namespaceURI == AgaviXmlConfigParser::AGAVI_ENVELOPE_NAMESPACE_0_11)) { 
    8787        $vh = new AgaviConfigValueHolder(); 
    8888        $nodeName = $this->convertEncoding($node->localName); 
     
    9191 
    9292        foreach($node->attributes as $attribute) { 
    93           if((!$attribute->namespaceURI || $attribute->namespaceURI == AgaviXmlConfigParser::AGAVI_ENVELOPE_NAMESPACE_1_0)) { 
     93          if((!$attribute->namespaceURI || $attribute->namespaceURI == AgaviXmlConfigParser::AGAVI_ENVELOPE_NAMESPACE_0_11)) { 
    9494            $vh->setAttribute($this->convertEncoding($attribute->localName), $this->convertEncoding($attribute->nodeValue)); 
    9595          } 
  • branches/david-xml_only_config_system/src/config/AgaviXmlConfigParser.class.php

    r2631 r2632  
    3232class AgaviXmlConfigParser 
    3333{ 
    34   const AGAVI_ENVELOPE_NAMESPACE_1_0 = 'http://agavi.org/agavi/1.0/config'; 
     34  const AGAVI_ENVELOPE_NAMESPACE_0_11 = 'http://agavi.org/agavi/1.0/config'; 
     35   
     36  const AGAVI_ENVELOPE_NAMESPACE_1_0 = 'http://agavi.org/agavi/config/1.0'; 
    3537   
    3638  const AGAVI_ENVELOPE_NAMESPACE_LATEST = self::AGAVI_ENVELOPE_NAMESPACE_1_0; 
     
    5355   */ 
    5456  public static $agaviEnvelopeNamespaces = array( 
     57    self::AGAVI_ENVELOPE_NAMESPACE_0_11 => 'agavi_envelope_0_11', 
    5558    self::AGAVI_ENVELOPE_NAMESPACE_1_0 => 'agavi_envelope_1_0', 
    5659  ); 
     
    104107  { 
    105108    return isset(self::$agaviEnvelopeNamespaces[$namespaceUri]); 
     109  } 
     110   
     111  /** 
     112   * Retrieves an XPath namespace prefix based on a given namespace URI. 
     113   * 
     114   * @param      string The namespace URI. 
     115   * 
     116   * @return     string The prefix for the namespace URI, or null if none 
     117   *                    exists. 
     118   * 
     119   * @author     Noah Fontes <noah.fontes@bitextender.com> 
     120   * @since      1.0.0 
     121   */ 
     122  public static function getAgaviEnvelopePrefix($namespaceUri) 
     123  { 
     124    if(self::isAgaviEnvelopeNamespace($namespaceUri)) { 
     125      return self::$agaviEnvelopeNamespaces[$namespaceUri]; 
     126    } 
     127    return null; 
    106128  } 
    107129   
     
    204226    // cleanup attempt 
    205227    unset($docs); 
     228     
     229    // set the pseudo-document URI 
     230    $retval->documentURI = $path; 
    206231     
    207232    return $retval; 
     
    397422        if($matched) { 
    398423          // if all was fine, we set the attribute. the element will then be kept in the merged result doc later 
    399           $configuration->setAttributeNS(self::AGAVI_ENVELOPE_NAMESPACE_LATEST, 'matched', 'true'); 
     424          $configuration->setAttributeNS(self::AGAVI_ENVELOPE_NAMESPACE_LATEST, 'agavi:matched', 'true'); 
    400425        } 
    401426      } 
  • branches/david-xml_only_config_system/src/config/AgaviXmlFactoryConfigHandler.class.php

    r2547 r2632  
    3131class AgaviXmlFactoryConfigHandler extends AgaviXmlConfigHandler 
    3232{ 
    33   const XML_NAMESPACE = 'http://agavi.org/agavi/1.0/config/factories'; 
     33  const NAMESPACE = 'http://agavi.org/agavi/config/factories/1.0'; 
    3434   
    3535  /** 
     
    4848  public function execute(DOMDocument $doc) 
    4949  { 
    50     echo ($doc->saveXML()); 
    51      
    52     // $xsl = new DOMDocument(); 
    53     // $xsl->load(AgaviConfig::get('core.system_config_dir') . '/../xsl/factories.xsl'); 
    54     //  
    55     // $xslt = new XSLTProcessor(); 
    56     // $xslt->importStylesheet($xsl); 
    57     //  
    58     // echo ($xslt->transformToDoc($doc)->saveXML()); 
    59     die(); 
    60      
    6150    // set up our default namespace 
    62     $doc->setDefaultNamespace(self::XML_NAMESPACE, 'factories'); 
    63      
     51    $doc->setDefaultNamespace(self::NAMESPACE, 'factories'); 
     52     
     53    $config = $doc->documentURI; 
    6454    $data = array(); 
    6555     
     
    199189    ); 
    200190     
    201     foreach($doc->getConfigurations() as $cfg) { 
     191    foreach($doc->getConfigurationElements() as $configuration) { 
    202192      foreach($factories as $factory => $info) { 
    203         if($info['required'] && isset($cfg->$factory)) { 
     193        if(is_array($info) && $info['required'] && $configuration->hasChild($factory)) { 
     194          $element = $configuration->getChild($factory); 
     195           
    204196          $data[$factory] = isset($data[$factory]) ? $data[$factory] : array('class' => null, 'params' => array()); 
    205           $data[$factory]['class'] = $cfg->$factory->getAttribute('class', $data[$factory]['class']); 
    206           $data[$factory]['params'] = $this->getItemParameters($cfg->$factory, $data[$factory]['params']); 
     197          $data[$factory]['class'] = $element->getAttribute('class', $data[$factory]['class']); 
     198          $data[$factory]['params'] = $element->getAgaviParameters($data[$factory]['params']); 
    207199        } 
    208200      } 
  • branches/david-xml_only_config_system/src/config/util/dom/AgaviXmlConfigDomDocument.class.php

    r2631 r2632  
    101101    $this->xpath = new DOMXPath($this); 
    102102     
     103    if($this->isAgaviConfiguration()) { 
     104      /* Register Agavi namespace prefixes. */ 
     105      foreach(AgaviXmlConfigParser::$agaviEnvelopeNamespaces as $namespaceUri => $prefix) { 
     106        $this->xpath->registerNamespace($prefix, $namespaceUri); 
     107      } 
     108       
     109      /* Register the default envelope namespace. */ 
     110      $this->xpath->registerNamespace('agavi_envelope_latest', AgaviXmlConfigParser::AGAVI_ENVELOPE_NAMESPACE_LATEST); 
     111    } 
     112     
    103113    return $result; 
    104114  } 
     
    142152    unset($this->xpath); 
    143153    $this->xpath = new DOMXPath($this); 
     154     
     155    if($this->isAgaviConfiguration()) { 
     156      /* Register Agavi namespace prefixes. */ 
     157      foreach(AgaviXmlConfigParser::$agaviEnvelopeNamespaces as $namespaceUri => $prefix) { 
     158        $this->xpath->registerNamespace($prefix, $namespaceUri); 
     159      } 
     160       
     161      /* Register the default envelope namespace. */ 
     162      $this->xpath->registerNamespace('agavi_envelope_latest', AgaviXmlConfigParser::AGAVI_ENVELOPE_NAMESPACE_LATEST); 
     163    } 
    144164     
    145165    return $result; 
  • branches/david-xml_only_config_system/src/config/util/dom/AgaviXmlConfigDomElement.class.php

    r2487 r2632  
    3434    // what to return here? name with prefix? no. 
    3535    // but... element name, or with ns prefix? 
     36    return $this->nodeName; 
    3637  } 
    3738   
     
    5556  { 
    5657    // should only pull elements from the default ns 
    57     // remember to handle special case where we are the document element and an agavi config - must find <configuration> elements from the envelope ns here 
    58     return $this->ownerDocument->getXpath()->query('child::element()', $this); 
    59   } 
    60    
    61   public function hasChildren($defaultNamespaceOnly = false) 
     58    $prefix = $this->ownerDocument->getDefaultNamespacePrefix(); 
     59    if($prefix) { 
     60      return $this->ownerDocument->getXpath()->query(sprintf('child::%s:element()', $prefix), $this); 
     61    } else { 
     62      return $this->ownerDocument->getXpath()->query('child::element()', $this); 
     63    } 
     64  } 
     65   
     66  protected function singularize($name) 
     67  { 
     68    $names = preg_split('#([_\-\.])#', $name, -1, PREG_SPLIT_DELIM_CAPTURE); 
     69    $names[count($names) - 1] = AgaviInflector::singularize(end($names)); 
     70    return implode('', $names); 
     71  } 
     72   
     73  public function countChildren($name, $namespaceUri = null) 
    6274  { 
    6375    // check for child elements(!) using XPath 
    6476    // if arg is true, then only check for elements from our default namespace 
    65     // remember to handle special case where we are the document element and an agavi config - must find <configuration> elements from the envelope ns here 
    66   } 
    67    
    68   public function getChildren($defaultNamespaceOnly = false) 
     77    $namespaceUri = ($namespaceUri === null ? $this->ownerDocument->getDefaultNamespaceUri() : $namespaceUri); 
     78    $singularName = $this->singularize($name); 
     79     
     80    $xpath = $this->ownerDocument->getXpath(); 
     81    if($namespaceUri) { 
     82      return (int)$xpath->evaluate(sprintf('count(child::*[local-name() = "%2$s" and namespace-uri() = "%3$s"]) + count(child::*[local-name() = "%1$s" and namespace-uri() = "%3$s"]/*[local-name() = "%2$s" and namespace-uri() = "%3$s"])', $name, $singularName, $namespaceUri), $this); 
     83    } else { 
     84      return (int)$xpath->evaluate(sprintf('count(%2$s) + count(%1$s/%2$s)', $name, $singularName), $this); 
     85    } 
     86  } 
     87   
     88  public function hasChildren($name, $namespaceUri = null) 
     89  { 
     90    return $this->countChildren($name, $namespaceUri) !== 0; 
     91  } 
     92   
     93  public function getChildren($name, $namespaceUri = null) 
    6994  { 
    7095    // check for child elements(!) using XPath 
    7196    // if arg is true, then only check for elements from our default namespace 
    72     // remember to handle special case where we are the document element and an agavi config - must find <configuration> elements from the envelope ns here 
     97    // if namespace uri is null, use default ns. if empty string, use no ns 
     98    $namespaceUri = ($namespaceUri === null ? $this->ownerDocument->getDefaultNamespaceUri() : $namespaceUri); 
     99    $singularName = $this->singularize($name); 
     100     
     101    $xpath = $this->ownerDocument->getXpath(); 
     102    if($namespaceUri) { 
     103      return $xpath->query(sprintf('child::*[local-name() = "%2$s" and namespace-uri() = "%3$s"] | child::*[local-name() = "%1$s" and namespace-uri() = "%3$s"]/*[local-name() = "%2$s" and namespace-uri() = "%3$s"]', $name, $singularName, $namespaceUri), $this); 
     104    } else { 
     105      return $xpath->query(sprintf('%1$s/%2$s | %2$s', $name, $singularName), $this); 
     106    } 
    73107  } 
    74108   
     
    76110  { 
    77111    // if namespace uri is null, use default ns. if empty string, use no ns 
    78     // remember to handle special case where we are the document element and an agavi config - must find <configuration> elements from the envelope ns here 
     112    return $this->countChildren($name) === 1; 
     113     
     114    // XXX: not necessary for single elements? 
    79115    // remember singular/plural support 
    80116  } 
    81117   
     118  /** 
     119   * Returns a single child element with a given name. 
     120   * 
     121   * @param      string The name of the element. 
     122   * @param      string The namespace URI. If null, the document default 
     123   *                    namespace will be used. If an empty string, no namespace 
     124   *                    will be used. 
     125   * 
     126   * @return     DOMElement The child element, or null if none xists. 
     127   * 
     128   * @author     Noah Fontes <noah.fontes@bitextender.com> 
     129   * @since      1.0.0 
     130   */ 
    82131  public function getChild($name, $namespaceUri = null) 
    83132  { 
    84     // if namespace uri is null, use default ns. if empty string, use no ns 
    85     // remember to handle special case where we are the document element and an agavi config - must find <configuration> elements from the envelope ns here 
     133    $list = $this->getChildren($name, $namespaceUri); 
     134     
     135    if($list->length > 0) { 
     136      return $list->item(0); 
     137    } 
     138    return null; 
    86139  } 
    87140   
     
    141194  } 
    142195   
    143   public function getAgaviParameters() 
    144   { 
    145     return $this->ownerDocument->xpath->query('child::aens:parameters | child::aens:parameter'); 
     196  public function getAgaviParameters(array $existing = array()) 
     197  { 
     198    if($this->ownerDocument->isAgaviConfiguration()) { 
     199      $elements = $this->getChildren('parameters', AgaviXmlConfigParser::AGAVI_ENVELOPE_NAMESPACE_LATEST); 
     200      $result = array(); 
     201       
     202      foreach($elements as $element) { 
     203        if($element->hasChildren('parameters', AgaviXmlConfigParser::AGAVI_ENVELOPE_NAMESPACE_LATEST)) { 
     204          $result[$element->getAttribute('name')] = $element->getAgaviParameters(); 
     205        } else { 
     206          $result[$element->getAttribute('name')] = $element->getValue(); 
     207        } 
     208      } 
     209       
     210      return array_merge($existing, $result); 
     211    } else { 
     212      return $existing; 
     213    } 
    146214  } 
    147215} 
  • branches/david-xml_only_config_system/src/config/util/xsl/AgaviXmlConfigXsltProcessor.class.php

    r2631 r2632  
    4545   * @param      DOMNode The node to transform. 
    4646   * 
    47    * @return     DOMDocument The resulting DOMDocument. 
     47   * @return     AgaviXmlConfigDomDocument The resulting DOMDocument. 
    4848   * 
    4949   * @author     Noah Fontes <noah.fontes@bitextender.com> 
  • branches/david-xml_only_config_system/src/config/xsl/_common.xsl

    r2475 r2632  
    33  version="1.0" 
    44  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    5   xmlns:agavi10="http://agavi.org/agavi/1.0/config" 
    6 > 
     5  xmlns:envelope_0_11="http://agavi.org/agavi/1.0/config" 
     6  xmlns:envelope_1_0="http://agavi.org/agavi/config/1.0"> 
    77   
    8   <xsl:template match="agavi10:configurations | agavi10:configuration | agavi10:sandbox | agavi10:parameters | agavi10:parameter"> 
    9     <xsl:element name="{local-name()}" namespace="{namespace-uri()}"> 
     8  <xsl:variable name="envelope_0_11" select="'http://agavi.org/agavi/1.0/config'" /> 
     9  <xsl:variable name="envelope_1_0" select="'http://agavi.org/agavi/config/1.0'" /> 
     10   
     11  <xsl:template match="envelope_0_11:configurations | envelope_0_11:configuration | envelope_0_11:sandbox | envelope_0_11:parameters | envelope_0_11:parameter"> 
     12    <xsl:element name="{local-name()}" namespace="{$envelope_1_0}"> 
    1013      <xsl:copy-of select="@*" /> 
    1114      <xsl:apply-templates /> 
  • branches/david-xml_only_config_system/src/config/xsl/factories.xsl

    r2475 r2632  
    33  version="1.0" 
    44  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    5   xmlns:agavi10="http://agavi.org/agavi/1.0/config" 
    6   xmlns:factories10="http://agavi.org/agavi/1.0/config/factories" 
    7   xmlns:factories11="http://agavi.org/agavi/1.1/config/factories" 
     5  xmlns:envelope_0_11="http://agavi.org/agavi/1.0/config" 
     6  xmlns:factories_1_0="http://agavi.org/agavi/config/factories/1.0" 
    87> 
    9  
     8  <!--xmlns:factories_1_1="http://agavi.org/agavi/1.1/config/factories"--> 
     9   
     10  <xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes" /> 
     11   
    1012  <xsl:include href="_common.xsl" /> 
    11  
    12   <xsl:variable name="agavi10" select="'http://agavi.org/agavi/1.0/config'" /> 
    13   <xsl:variable name="factories10" select="'http://agavi.org/agavi/1.0/config/factories'" /> 
    14   <xsl:variable name="factories11" select="'http://agavi.org/agavi/1.1/config/factories'" /> 
    15  
    16   <xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes" /> 
     13   
     14  <xsl:variable name="factories_1_0" select="'http://agavi.org/agavi/config/factories/1.0'" /> 
     15  <!--<xsl:variable name="factories11" select="'http://agavi.org/agavi/1.1/config/factories'" />--> 
    1716   
    1817  <!-- pre-1.0 backwards compatibility for 1.0 --> 
    1918  <!-- non-"envelope" elements are copied to the 1.0 factories namespace --> 
    20   <xsl:template match="agavi10:*"> 
    21     <xsl:element name="{local-name()}" namespace="{$factories10}"> 
     19  <xsl:template match="envelope_0_11:*"> 
     20    <xsl:element name="{local-name()}" namespace="{$factories_1_0}"> 
    2221      <xsl:copy-of select="@*" /> 
    2322      <xsl:apply-templates /> 
     
    2726  <!-- 1.0 BC for 1.1 --> 
    2827  <!-- namespace is simply changed to 1.1 for all elements except <storage> --> 
    29   <xsl:template match="factories10:*"> 
     28  <!-- <xsl:template match="factories10:*"> 
    3029    <xsl:element name="{local-name()}" namespace="{$factories11}"> 
    3130      <xsl:copy-of select="@*" /> 
     
    3736      <xsl:apply-templates /> 
    3837    </factories11:storage_manager> 
    39   </xsl:template> 
     38  </xsl:template> --> 
    4039   
    4140</xsl:stylesheet>