web/lib/Zend/Config.php
changeset 64 162c1de6545a
parent 19 1c2f13fd785c
child 68 ecaf28ffe26e
equal deleted inserted replaced
63:5b37998e522e 64:162c1de6545a
       
     1 <?php
       
     2 /**
       
     3  * Zend Framework
       
     4  *
       
     5  * LICENSE
       
     6  *
       
     7  * This source file is subject to the new BSD license that is bundled
       
     8  * with this package in the file LICENSE.txt.
       
     9  * It is also available through the world-wide-web at this URL:
       
    10  * http://framework.zend.com/license/new-bsd
       
    11  * If you did not receive a copy of the license and are unable to
       
    12  * obtain it through the world-wide-web, please send an email
       
    13  * to license@zend.com so we can send you a copy immediately.
       
    14  *
       
    15  * @category   Zend
       
    16  * @package    Zend_Config
       
    17  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    18  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    19  * @version    $Id: Config.php 20096 2010-01-06 02:05:09Z bkarwin $
       
    20  */
       
    21 
       
    22 
       
    23 /**
       
    24  * @category   Zend
       
    25  * @package    Zend_Config
       
    26  * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
       
    27  * @license    http://framework.zend.com/license/new-bsd     New BSD License
       
    28  */
       
    29 class Zend_Config implements Countable, Iterator
       
    30 {
       
    31     /**
       
    32      * Whether in-memory modifications to configuration data are allowed
       
    33      *
       
    34      * @var boolean
       
    35      */
       
    36     protected $_allowModifications;
       
    37 
       
    38     /**
       
    39      * Iteration index
       
    40      *
       
    41      * @var integer
       
    42      */
       
    43     protected $_index;
       
    44 
       
    45     /**
       
    46      * Number of elements in configuration data
       
    47      *
       
    48      * @var integer
       
    49      */
       
    50     protected $_count;
       
    51 
       
    52     /**
       
    53      * Contains array of configuration data
       
    54      *
       
    55      * @var array
       
    56      */
       
    57     protected $_data;
       
    58 
       
    59     /**
       
    60      * Used when unsetting values during iteration to ensure we do not skip
       
    61      * the next element
       
    62      *
       
    63      * @var boolean
       
    64      */
       
    65     protected $_skipNextIteration;
       
    66 
       
    67     /**
       
    68      * Contains which config file sections were loaded. This is null
       
    69      * if all sections were loaded, a string name if one section is loaded
       
    70      * and an array of string names if multiple sections were loaded.
       
    71      *
       
    72      * @var mixed
       
    73      */
       
    74     protected $_loadedSection;
       
    75 
       
    76     /**
       
    77      * This is used to track section inheritance. The keys are names of sections that
       
    78      * extend other sections, and the values are the extended sections.
       
    79      *
       
    80      * @var array
       
    81      */
       
    82     protected $_extends = array();
       
    83 
       
    84     /**
       
    85      * Load file error string.
       
    86      *
       
    87      * Is null if there was no error while file loading
       
    88      *
       
    89      * @var string
       
    90      */
       
    91     protected $_loadFileErrorStr = null;
       
    92 
       
    93     /**
       
    94      * Zend_Config provides a property based interface to
       
    95      * an array. The data are read-only unless $allowModifications
       
    96      * is set to true on construction.
       
    97      *
       
    98      * Zend_Config also implements Countable and Iterator to
       
    99      * facilitate easy access to the data.
       
   100      *
       
   101      * @param  array   $array
       
   102      * @param  boolean $allowModifications
       
   103      * @return void
       
   104      */
       
   105     public function __construct(array $array, $allowModifications = false)
       
   106     {
       
   107         $this->_allowModifications = (boolean) $allowModifications;
       
   108         $this->_loadedSection = null;
       
   109         $this->_index = 0;
       
   110         $this->_data = array();
       
   111         foreach ($array as $key => $value) {
       
   112             if (is_array($value)) {
       
   113                 $this->_data[$key] = new self($value, $this->_allowModifications);
       
   114             } else {
       
   115                 $this->_data[$key] = $value;
       
   116             }
       
   117         }
       
   118         $this->_count = count($this->_data);
       
   119     }
       
   120 
       
   121     /**
       
   122      * Retrieve a value and return $default if there is no element set.
       
   123      *
       
   124      * @param string $name
       
   125      * @param mixed $default
       
   126      * @return mixed
       
   127      */
       
   128     public function get($name, $default = null)
       
   129     {
       
   130         $result = $default;
       
   131         if (array_key_exists($name, $this->_data)) {
       
   132             $result = $this->_data[$name];
       
   133         }
       
   134         return $result;
       
   135     }
       
   136 
       
   137     /**
       
   138      * Magic function so that $obj->value will work.
       
   139      *
       
   140      * @param string $name
       
   141      * @return mixed
       
   142      */
       
   143     public function __get($name)
       
   144     {
       
   145         return $this->get($name);
       
   146     }
       
   147 
       
   148     /**
       
   149      * Only allow setting of a property if $allowModifications
       
   150      * was set to true on construction. Otherwise, throw an exception.
       
   151      *
       
   152      * @param  string $name
       
   153      * @param  mixed  $value
       
   154      * @throws Zend_Config_Exception
       
   155      * @return void
       
   156      */
       
   157     public function __set($name, $value)
       
   158     {
       
   159         if ($this->_allowModifications) {
       
   160             if (is_array($value)) {
       
   161                 $this->_data[$name] = new self($value, true);
       
   162             } else {
       
   163                 $this->_data[$name] = $value;
       
   164             }
       
   165             $this->_count = count($this->_data);
       
   166         } else {
       
   167             /** @see Zend_Config_Exception */
       
   168             require_once 'Zend/Config/Exception.php';
       
   169             throw new Zend_Config_Exception('Zend_Config is read only');
       
   170         }
       
   171     }
       
   172 
       
   173     /**
       
   174      * Deep clone of this instance to ensure that nested Zend_Configs
       
   175      * are also cloned.
       
   176      *
       
   177      * @return void
       
   178      */
       
   179     public function __clone()
       
   180     {
       
   181       $array = array();
       
   182       foreach ($this->_data as $key => $value) {
       
   183           if ($value instanceof Zend_Config) {
       
   184               $array[$key] = clone $value;
       
   185           } else {
       
   186               $array[$key] = $value;
       
   187           }
       
   188       }
       
   189       $this->_data = $array;
       
   190     }
       
   191 
       
   192     /**
       
   193      * Return an associative array of the stored data.
       
   194      *
       
   195      * @return array
       
   196      */
       
   197     public function toArray()
       
   198     {
       
   199         $array = array();
       
   200         $data = $this->_data;
       
   201         foreach ($data as $key => $value) {
       
   202             if ($value instanceof Zend_Config) {
       
   203                 $array[$key] = $value->toArray();
       
   204             } else {
       
   205                 $array[$key] = $value;
       
   206             }
       
   207         }
       
   208         return $array;
       
   209     }
       
   210 
       
   211     /**
       
   212      * Support isset() overloading on PHP 5.1
       
   213      *
       
   214      * @param string $name
       
   215      * @return boolean
       
   216      */
       
   217     public function __isset($name)
       
   218     {
       
   219         return isset($this->_data[$name]);
       
   220     }
       
   221 
       
   222     /**
       
   223      * Support unset() overloading on PHP 5.1
       
   224      *
       
   225      * @param  string $name
       
   226      * @throws Zend_Config_Exception
       
   227      * @return void
       
   228      */
       
   229     public function __unset($name)
       
   230     {
       
   231         if ($this->_allowModifications) {
       
   232             unset($this->_data[$name]);
       
   233             $this->_count = count($this->_data);
       
   234             $this->_skipNextIteration = true;
       
   235         } else {
       
   236             /** @see Zend_Config_Exception */
       
   237             require_once 'Zend/Config/Exception.php';
       
   238             throw new Zend_Config_Exception('Zend_Config is read only');
       
   239         }
       
   240 
       
   241     }
       
   242 
       
   243     /**
       
   244      * Defined by Countable interface
       
   245      *
       
   246      * @return int
       
   247      */
       
   248     public function count()
       
   249     {
       
   250         return $this->_count;
       
   251     }
       
   252 
       
   253     /**
       
   254      * Defined by Iterator interface
       
   255      *
       
   256      * @return mixed
       
   257      */
       
   258     public function current()
       
   259     {
       
   260         $this->_skipNextIteration = false;
       
   261         return current($this->_data);
       
   262     }
       
   263 
       
   264     /**
       
   265      * Defined by Iterator interface
       
   266      *
       
   267      * @return mixed
       
   268      */
       
   269     public function key()
       
   270     {
       
   271         return key($this->_data);
       
   272     }
       
   273 
       
   274     /**
       
   275      * Defined by Iterator interface
       
   276      *
       
   277      */
       
   278     public function next()
       
   279     {
       
   280         if ($this->_skipNextIteration) {
       
   281             $this->_skipNextIteration = false;
       
   282             return;
       
   283         }
       
   284         next($this->_data);
       
   285         $this->_index++;
       
   286     }
       
   287 
       
   288     /**
       
   289      * Defined by Iterator interface
       
   290      *
       
   291      */
       
   292     public function rewind()
       
   293     {
       
   294         $this->_skipNextIteration = false;
       
   295         reset($this->_data);
       
   296         $this->_index = 0;
       
   297     }
       
   298 
       
   299     /**
       
   300      * Defined by Iterator interface
       
   301      *
       
   302      * @return boolean
       
   303      */
       
   304     public function valid()
       
   305     {
       
   306         return $this->_index < $this->_count;
       
   307     }
       
   308 
       
   309     /**
       
   310      * Returns the section name(s) loaded.
       
   311      *
       
   312      * @return mixed
       
   313      */
       
   314     public function getSectionName()
       
   315     {
       
   316         if(is_array($this->_loadedSection) && count($this->_loadedSection) == 1) {
       
   317             $this->_loadedSection = $this->_loadedSection[0];
       
   318         }
       
   319         return $this->_loadedSection;
       
   320     }
       
   321 
       
   322     /**
       
   323      * Returns true if all sections were loaded
       
   324      *
       
   325      * @return boolean
       
   326      */
       
   327     public function areAllSectionsLoaded()
       
   328     {
       
   329         return $this->_loadedSection === null;
       
   330     }
       
   331 
       
   332 
       
   333     /**
       
   334      * Merge another Zend_Config with this one. The items
       
   335      * in $merge will override the same named items in
       
   336      * the current config.
       
   337      *
       
   338      * @param Zend_Config $merge
       
   339      * @return Zend_Config
       
   340      */
       
   341     public function merge(Zend_Config $merge)
       
   342     {
       
   343         foreach($merge as $key => $item) {
       
   344             if(array_key_exists($key, $this->_data)) {
       
   345                 if($item instanceof Zend_Config && $this->$key instanceof Zend_Config) {
       
   346                     $this->$key = $this->$key->merge(new Zend_Config($item->toArray(), !$this->readOnly()));
       
   347                 } else {
       
   348                     $this->$key = $item;
       
   349                 }
       
   350             } else {
       
   351                 if($item instanceof Zend_Config) {
       
   352                     $this->$key = new Zend_Config($item->toArray(), !$this->readOnly());
       
   353                 } else {
       
   354                     $this->$key = $item;
       
   355                 }
       
   356             }
       
   357         }
       
   358 
       
   359         return $this;
       
   360     }
       
   361 
       
   362     /**
       
   363      * Prevent any more modifications being made to this instance. Useful
       
   364      * after merge() has been used to merge multiple Zend_Config objects
       
   365      * into one object which should then not be modified again.
       
   366      *
       
   367      */
       
   368     public function setReadOnly()
       
   369     {
       
   370         $this->_allowModifications = false;
       
   371         foreach ($this->_data as $key => $value) {
       
   372             if ($value instanceof Zend_Config) {
       
   373                 $value->setReadOnly();
       
   374             }
       
   375         }
       
   376     }
       
   377 
       
   378     /**
       
   379      * Returns if this Zend_Config object is read only or not.
       
   380      *
       
   381      * @return boolean
       
   382      */
       
   383     public function readOnly()
       
   384     {
       
   385         return !$this->_allowModifications;
       
   386     }
       
   387 
       
   388     /**
       
   389      * Get the current extends
       
   390      *
       
   391      * @return array
       
   392      */
       
   393     public function getExtends()
       
   394     {
       
   395         return $this->_extends;
       
   396     }
       
   397 
       
   398     /**
       
   399      * Set an extend for Zend_Config_Writer
       
   400      *
       
   401      * @param  string $extendingSection
       
   402      * @param  string $extendedSection
       
   403      * @return void
       
   404      */
       
   405     public function setExtend($extendingSection, $extendedSection = null)
       
   406     {
       
   407         if ($extendedSection === null && isset($this->_extends[$extendingSection])) {
       
   408             unset($this->_extends[$extendingSection]);
       
   409         } else if ($extendedSection !== null) {
       
   410             $this->_extends[$extendingSection] = $extendedSection;
       
   411         }
       
   412     }
       
   413 
       
   414     /**
       
   415      * Throws an exception if $extendingSection may not extend $extendedSection,
       
   416      * and tracks the section extension if it is valid.
       
   417      *
       
   418      * @param  string $extendingSection
       
   419      * @param  string $extendedSection
       
   420      * @throws Zend_Config_Exception
       
   421      * @return void
       
   422      */
       
   423     protected function _assertValidExtend($extendingSection, $extendedSection)
       
   424     {
       
   425         // detect circular section inheritance
       
   426         $extendedSectionCurrent = $extendedSection;
       
   427         while (array_key_exists($extendedSectionCurrent, $this->_extends)) {
       
   428             if ($this->_extends[$extendedSectionCurrent] == $extendingSection) {
       
   429                 /** @see Zend_Config_Exception */
       
   430                 require_once 'Zend/Config/Exception.php';
       
   431                 throw new Zend_Config_Exception('Illegal circular inheritance detected');
       
   432             }
       
   433             $extendedSectionCurrent = $this->_extends[$extendedSectionCurrent];
       
   434         }
       
   435         // remember that this section extends another section
       
   436         $this->_extends[$extendingSection] = $extendedSection;
       
   437     }
       
   438 
       
   439     /**
       
   440      * Handle any errors from simplexml_load_file or parse_ini_file
       
   441      *
       
   442      * @param integer $errno
       
   443      * @param string $errstr
       
   444      * @param string $errfile
       
   445      * @param integer $errline
       
   446      */
       
   447     protected function _loadFileErrorHandler($errno, $errstr, $errfile, $errline)
       
   448     {
       
   449         if ($this->_loadFileErrorStr === null) {
       
   450             $this->_loadFileErrorStr = $errstr;
       
   451         } else {
       
   452             $this->_loadFileErrorStr .= (PHP_EOL . $errstr);
       
   453         }
       
   454     }
       
   455 
       
   456     /**
       
   457      * Merge two arrays recursively, overwriting keys of the same name
       
   458      * in $firstArray with the value in $secondArray.
       
   459      *
       
   460      * @param  mixed $firstArray  First array
       
   461      * @param  mixed $secondArray Second array to merge into first array
       
   462      * @return array
       
   463      */
       
   464     protected function _arrayMergeRecursive($firstArray, $secondArray)
       
   465     {
       
   466         if (is_array($firstArray) && is_array($secondArray)) {
       
   467             foreach ($secondArray as $key => $value) {
       
   468                 if (isset($firstArray[$key])) {
       
   469                     $firstArray[$key] = $this->_arrayMergeRecursive($firstArray[$key], $value);
       
   470                 } else {
       
   471                     if($key === 0) {
       
   472                         $firstArray= array(0=>$this->_arrayMergeRecursive($firstArray, $value));
       
   473                     } else {
       
   474                         $firstArray[$key] = $value;
       
   475                     }
       
   476                 }
       
   477             }
       
   478         } else {
       
   479             $firstArray = $secondArray;
       
   480         }
       
   481 
       
   482         return $firstArray;
       
   483     }
       
   484 }