942 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			942 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| 
 | |
| /**
 | |
|  * Part of the Joomla Framework Registry Package
 | |
|  *
 | |
|  * @copyright  Copyright (C) 2013 Open Source Matters, Inc.
 | |
|  * @license    GNU General Public License version 2 or later; see LICENSE
 | |
|  */
 | |
| 
 | |
| namespace Joomla\Registry;
 | |
| 
 | |
| use Joomla\Utilities\ArrayHelper;
 | |
| 
 | |
| /**
 | |
|  * Registry class
 | |
|  *
 | |
|  * @since  1.0.0
 | |
|  * @since  2.0.0  `Registry::getInstance()` was removed. Instantiate a new Registry instance instead.
 | |
|  */
 | |
| class Registry implements \JsonSerializable, \ArrayAccess, \IteratorAggregate, \Countable
 | |
| {
 | |
|     /**
 | |
|      * Registry Object
 | |
|      *
 | |
|      * @var    \stdClass
 | |
|      * @since  1.0.0
 | |
|      */
 | |
|     protected $data;
 | |
| 
 | |
|     /**
 | |
|      * Flag if the Registry data object has been initialized
 | |
|      *
 | |
|      * @var    boolean
 | |
|      * @since  1.5.2
 | |
|      */
 | |
|     protected $initialized = false;
 | |
| 
 | |
|     /**
 | |
|      * Path separator
 | |
|      *
 | |
|      * @var    string
 | |
|      * @since  1.4.0
 | |
|      */
 | |
|     protected $separator = '.';
 | |
| 
 | |
|     /**
 | |
|      * Constructor
 | |
|      *
 | |
|      * @param  mixed   $data       The data to bind to the new Registry object.
 | |
|      * @param  string  $separator  The path separator, and empty string will flatten the registry.
 | |
|      *
 | |
|      * @since   1.0.0
 | |
|      */
 | |
|     public function __construct($data = null, string $separator = '.')
 | |
|     {
 | |
|         $this->separator = $separator;
 | |
| 
 | |
|         // Instantiate the internal data object.
 | |
|         $this->data = new \stdClass();
 | |
| 
 | |
|         // Optionally load supplied data.
 | |
|         if ($data instanceof self) {
 | |
|             $this->merge($data);
 | |
|         } elseif (\is_array($data) || \is_object($data)) {
 | |
|             $this->bindData($this->data, $data);
 | |
|         } elseif (!empty($data) && \is_string($data)) {
 | |
|             $this->loadString($data);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Magic function to clone the registry object.
 | |
|      *
 | |
|      * @return  void
 | |
|      *
 | |
|      * @since   1.0.0
 | |
|      */
 | |
|     public function __clone()
 | |
|     {
 | |
|         $this->data = \unserialize(\serialize($this->data));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Magic function to render this object as a string using default args of toString method.
 | |
|      *
 | |
|      * @return  string
 | |
|      *
 | |
|      * @since   1.0.0
 | |
|      */
 | |
|     public function __toString()
 | |
|     {
 | |
|         return $this->toString();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Count elements of the data object
 | |
|      *
 | |
|      * @return  integer  The custom count as an integer.
 | |
|      *
 | |
|      * @link    https://www.php.net/manual/en/countable.count.php
 | |
|      * @since   1.3.0
 | |
|      */
 | |
|     #[\ReturnTypeWillChange]
 | |
|     public function count()
 | |
|     {
 | |
|         return \count(\get_object_vars($this->data));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Implementation for the JsonSerializable interface.
 | |
|      * Allows us to pass Registry objects to json_encode.
 | |
|      *
 | |
|      * @return  object
 | |
|      *
 | |
|      * @since   1.0.0
 | |
|      * @note    The interface is only present in PHP 5.4 and up.
 | |
|      */
 | |
|     #[\ReturnTypeWillChange]
 | |
|     public function jsonSerialize()
 | |
|     {
 | |
|         return $this->data;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Sets a default value if not already assigned.
 | |
|      *
 | |
|      * @param  string  $key      The name of the parameter.
 | |
|      * @param  mixed   $default  An optional value for the parameter.
 | |
|      *
 | |
|      * @return  mixed  The value set, or the default if the value was not previously set (or null).
 | |
|      *
 | |
|      * @since   1.0.0
 | |
|      */
 | |
|     public function def($key, $default = '')
 | |
|     {
 | |
|         $value = $this->get($key, $default);
 | |
|         $this->set($key, $value);
 | |
| 
 | |
|         return $value;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Check if a registry path exists.
 | |
|      *
 | |
|      * @param  string  $path  Registry path (e.g. joomla.content.showauthor)
 | |
|      *
 | |
|      * @return  boolean
 | |
|      *
 | |
|      * @since   1.0.0
 | |
|      */
 | |
|     public function exists($path)
 | |
|     {
 | |
|         // Return default value if path is empty
 | |
|         if (empty($path)) {
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         // Explode the registry path into an array
 | |
|         if ($this->separator === null || $this->separator === '') {
 | |
|             $nodes = [$path];
 | |
|         } else {
 | |
|             $nodes = \explode($this->separator, $path);
 | |
|         }
 | |
| 
 | |
|         // Initialize the current node to be the registry root.
 | |
|         $node  = $this->data;
 | |
|         $found = false;
 | |
| 
 | |
|         // Traverse the registry to find the correct node for the result.
 | |
|         foreach ($nodes as $n) {
 | |
|             if (\is_array($node) && isset($node[$n])) {
 | |
|                 $node  = $node[$n];
 | |
|                 $found = true;
 | |
| 
 | |
|                 continue;
 | |
|             }
 | |
| 
 | |
|             if (!isset($node->$n)) {
 | |
|                 return false;
 | |
|             }
 | |
| 
 | |
|             $node  = $node->$n;
 | |
|             $found = true;
 | |
|         }
 | |
| 
 | |
|         return $found;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Get a registry value.
 | |
|      *
 | |
|      * @param  string  $path     Registry path (e.g. joomla.content.showauthor)
 | |
|      * @param  mixed   $default  Optional default value, returned if the internal value is null.
 | |
|      *
 | |
|      * @return  mixed  Value of entry or null
 | |
|      *
 | |
|      * @since   1.0.0
 | |
|      */
 | |
|     public function get($path, $default = null)
 | |
|     {
 | |
|         // Return default value if path is empty
 | |
|         if (empty($path)) {
 | |
|             return $default;
 | |
|         }
 | |
| 
 | |
|         if ($this->separator === null || $this->separator === '' || !\strpos($path, $this->separator)) {
 | |
|             return (isset($this->data->$path) && $this->data->$path !== null && $this->data->$path !== '')
 | |
|                 ? $this->data->$path
 | |
|                 : $default;
 | |
|         }
 | |
| 
 | |
|         // Explode the registry path into an array
 | |
|         $nodes = \explode($this->separator, \trim($path));
 | |
| 
 | |
|         // Initialize the current node to be the registry root.
 | |
|         $node  = $this->data;
 | |
|         $found = false;
 | |
| 
 | |
|         // Traverse the registry to find the correct node for the result.
 | |
|         foreach ($nodes as $n) {
 | |
|             if (\is_array($node) && isset($node[$n])) {
 | |
|                 $node  = $node[$n];
 | |
|                 $found = true;
 | |
| 
 | |
|                 continue;
 | |
|             }
 | |
| 
 | |
|             if (!isset($node->$n)) {
 | |
|                 return $default;
 | |
|             }
 | |
| 
 | |
|             $node  = $node->$n;
 | |
|             $found = true;
 | |
|         }
 | |
| 
 | |
|         if (!$found || $node === null || $node === '') {
 | |
|             return $default;
 | |
|         }
 | |
| 
 | |
|         return $node;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Gets this object represented as an ArrayIterator.
 | |
|      *
 | |
|      * This allows the data properties to be accessed via a foreach statement.
 | |
|      *
 | |
|      * @return  \ArrayIterator  This object represented as an ArrayIterator.
 | |
|      *
 | |
|      * @see     \IteratorAggregate::getIterator()
 | |
|      * @since   1.3.0
 | |
|      */
 | |
|     #[\ReturnTypeWillChange]
 | |
|     public function getIterator()
 | |
|     {
 | |
|         return new \ArrayIterator($this->data);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Load an associative array of values into the default namespace
 | |
|      *
 | |
|      * @param  array    $array      Associative array of value to load
 | |
|      * @param  boolean  $flattened  Load from a one-dimensional array
 | |
|      * @param  string   $separator  The key separator
 | |
|      *
 | |
|      * @return  $this
 | |
|      *
 | |
|      * @since   1.0.0
 | |
|      * @since   2.0.0  The parameter `$array` is now type hinted as `array`. Before 2.0.0, the type was not enforced.
 | |
|      */
 | |
|     public function loadArray(array $array, $flattened = false, $separator = null)
 | |
|     {
 | |
|         if (!$flattened) {
 | |
|             $this->bindData($this->data, $array);
 | |
| 
 | |
|             return $this;
 | |
|         }
 | |
| 
 | |
|         foreach ($array as $k => $v) {
 | |
|             $this->set($k, $v, $separator);
 | |
|         }
 | |
| 
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Load the public variables of the object into the default namespace.
 | |
|      *
 | |
|      * @param  object  $object  The object holding the publics to load
 | |
|      *
 | |
|      * @return  $this
 | |
|      *
 | |
|      * @since   1.0.0
 | |
|      */
 | |
|     public function loadObject($object)
 | |
|     {
 | |
|         $this->bindData($this->data, $object);
 | |
| 
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Load the contents of a file into the registry
 | |
|      *
 | |
|      * @param  string  $file     Path to file to load
 | |
|      * @param  string  $format   Format of the file [optional: defaults to JSON]
 | |
|      * @param  array   $options  Options used by the formatter
 | |
|      *
 | |
|      * @return  $this
 | |
|      *
 | |
|      * @since   1.0.0
 | |
|      * @since   2.0.0  The parameter `$options` is now type hinted as `array`. Before 2.0.0, the type was not enforced.
 | |
|      */
 | |
|     public function loadFile($file, $format = 'JSON', array $options = [])
 | |
|     {
 | |
|         $data = \file_get_contents($file);
 | |
| 
 | |
|         return $this->loadString($data, $format, $options);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Load a string into the registry
 | |
|      *
 | |
|      * @param  string  $data     String to load into the registry
 | |
|      * @param  string  $format   Format of the string
 | |
|      * @param  array   $options  Options used by the formatter
 | |
|      *
 | |
|      * @return  $this
 | |
|      *
 | |
|      * @since   1.0.0
 | |
|      * @since   2.0.0  The parameter `$options` is now type hinted as `array`. Before 2.0.0, the type was not enforced.
 | |
|      */
 | |
|     public function loadString($data, $format = 'JSON', array $options = [])
 | |
|     {
 | |
|         // Load a string into the given namespace [or default namespace if not given]
 | |
|         $obj = Factory::getFormat($format, $options)->stringToObject($data, $options);
 | |
| 
 | |
|         // If the data object has not yet been initialized, direct assign the object
 | |
|         if (!$this->initialized) {
 | |
|             $this->data        = $obj;
 | |
|             $this->initialized = true;
 | |
| 
 | |
|             return $this;
 | |
|         }
 | |
| 
 | |
|         $this->loadObject($obj);
 | |
| 
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Merge a Registry object into this one
 | |
|      *
 | |
|      * @param  Registry  $source     Source Registry object to merge.
 | |
|      * @param  boolean   $recursive  True to support recursive merge the children values.
 | |
|      *
 | |
|      * @return  $this
 | |
|      *
 | |
|      * @since   1.0.0
 | |
|      * @since   2.0.0  The parameter `$source` is now type hinted as `Registry`. Before 2.0.0, `Registry::merge()` just
 | |
|      *          returned `false` if `$source` was not a `Registry`.
 | |
|      */
 | |
|     public function merge(Registry $source, $recursive = false)
 | |
|     {
 | |
|         $this->bindData($this->data, $source->toArray(), $recursive, false);
 | |
| 
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Method to extract a sub-registry from path
 | |
|      *
 | |
|      * @param  string  $path  Registry path (e.g. joomla.content.showauthor)
 | |
|      *
 | |
|      * @return  Registry  Registry object (empty if no data is present)
 | |
|      *
 | |
|      * @since   1.2.0
 | |
|      * @since   2.0.0  `Registry:extract()` now always returns a `Registry` object. Before 2.0.0, `null` was returned
 | |
|      *          if there was no data for the key.
 | |
|      */
 | |
|     public function extract($path)
 | |
|     {
 | |
|         $data = $this->get($path);
 | |
| 
 | |
|         return new Registry($data);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Checks whether an offset exists in the iterator.
 | |
|      *
 | |
|      * @param  mixed  $offset  The array offset.
 | |
|      *
 | |
|      * @return  boolean  True if the offset exists, false otherwise.
 | |
|      *
 | |
|      * @since   1.0.0
 | |
|      */
 | |
|     #[\ReturnTypeWillChange]
 | |
|     public function offsetExists($offset)
 | |
|     {
 | |
|         return $this->exists($offset);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Gets an offset in the iterator.
 | |
|      *
 | |
|      * @param  mixed  $offset  The array offset.
 | |
|      *
 | |
|      * @return  mixed  The array value if it exists, null otherwise.
 | |
|      *
 | |
|      * @since   1.0.0
 | |
|      */
 | |
|     #[\ReturnTypeWillChange]
 | |
|     public function offsetGet($offset)
 | |
|     {
 | |
|         return $this->get($offset);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Sets an offset in the iterator.
 | |
|      *
 | |
|      * @param  mixed  $offset  The array offset.
 | |
|      * @param  mixed  $value   The array value.
 | |
|      *
 | |
|      * @return  void
 | |
|      *
 | |
|      * @since   1.0.0
 | |
|      */
 | |
|     #[\ReturnTypeWillChange]
 | |
|     public function offsetSet($offset, $value)
 | |
|     {
 | |
|         $this->set($offset, $value);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Unsets an offset in the iterator.
 | |
|      *
 | |
|      * @param  mixed  $offset  The array offset.
 | |
|      *
 | |
|      * @return  void
 | |
|      *
 | |
|      * @since   1.0.0
 | |
|      */
 | |
|     #[\ReturnTypeWillChange]
 | |
|     public function offsetUnset($offset)
 | |
|     {
 | |
|         $this->remove($offset);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Set a registry value.
 | |
|      *
 | |
|      * @param  string  $path       Registry Path (e.g. joomla.content.showauthor)
 | |
|      * @param  mixed   $value      Value of entry
 | |
|      * @param  string  $separator  The key separator. Will be removed in version 4.
 | |
|      *
 | |
|      * @return  mixed  The value of the that has been set.
 | |
|      *
 | |
|      * @since   1.0.0
 | |
|      */
 | |
|     public function set($path, $value, $separator = null)
 | |
|     {
 | |
|         if ($separator === null) {
 | |
|             $separator = $this->separator;
 | |
|         } else {
 | |
|             \trigger_deprecation(
 | |
|                 'joomla/registry',
 | |
|                 '__DEPLOY_VERSION__',
 | |
|                 'The $separator parameter will be removed in version 4.',
 | |
|                 self::class,
 | |
|                 self::class
 | |
|             );
 | |
|         }
 | |
| 
 | |
|         /*
 | |
|          * Explode the registry path into an array and remove empty
 | |
|          * nodes that occur as a result of a double separator. ex: joomla..test
 | |
|          * Finally, re-key the array so they are sequential.
 | |
|          */
 | |
|         if ($separator === null || $separator === '') {
 | |
|             $nodes = [$path];
 | |
|         } else {
 | |
|             $nodes = \array_values(\array_filter(\explode($separator, $path), 'strlen'));
 | |
|         }
 | |
| 
 | |
|         if (!$nodes) {
 | |
|             return null;
 | |
|         }
 | |
| 
 | |
|         // Initialize the current node to be the registry root.
 | |
|         $node = $this->data;
 | |
| 
 | |
|         // Traverse the registry to find the correct node for the result.
 | |
|         for ($i = 0, $n = \count($nodes) - 1; $i < $n; $i++) {
 | |
|             if (\is_object($node)) {
 | |
|                 if (!isset($node->{$nodes[$i]})) {
 | |
|                     $node->{$nodes[$i]} = new \stdClass();
 | |
|                 }
 | |
| 
 | |
|                 // Pass the child as pointer in case it is an object
 | |
|                 $node = &$node->{$nodes[$i]};
 | |
| 
 | |
|                 continue;
 | |
|             }
 | |
| 
 | |
|             if (\is_array($node)) {
 | |
|                 if (!isset($node[$nodes[$i]])) {
 | |
|                     $node[$nodes[$i]] = new \stdClass();
 | |
|                 }
 | |
| 
 | |
|                 // Pass the child as pointer in case it is an array
 | |
|                 $node = &$node[$nodes[$i]];
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // Get the old value if exists so we can return it
 | |
|         switch (true) {
 | |
|             case (\is_object($node)):
 | |
|                 $result             = $node->{$nodes[$i]} ?? null;
 | |
|                 $node->{$nodes[$i]} = $value;
 | |
|                 break;
 | |
| 
 | |
|             case (\is_array($node)):
 | |
|                 $result           = $node[$nodes[$i]] ?? null;
 | |
|                 $node[$nodes[$i]] = $value;
 | |
|                 break;
 | |
| 
 | |
|             default:
 | |
|                 $result = null;
 | |
|                 break;
 | |
|         }
 | |
| 
 | |
|         return $result;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Append value to a path in registry
 | |
|      *
 | |
|      * @param  string  $path   Parent registry Path (e.g. joomla.content.showauthor)
 | |
|      * @param  mixed   $value  Value of entry
 | |
|      *
 | |
|      * @return  mixed  The value of the that has been set.
 | |
|      *
 | |
|      * @since   1.4.0
 | |
|      */
 | |
|     public function append($path, $value)
 | |
|     {
 | |
|         $result = null;
 | |
| 
 | |
|         /*
 | |
|          * Explode the registry path into an array and remove empty
 | |
|          * nodes that occur as a result of a double dot. ex: joomla..test
 | |
|          * Finally, re-key the array so they are sequential.
 | |
|          */
 | |
|         if ($this->separator === null || $this->separator === '') {
 | |
|             $nodes = [$path];
 | |
|         } else {
 | |
|             $nodes = \array_values(\array_filter(\explode($this->separator, $path), 'strlen'));
 | |
|         }
 | |
| 
 | |
|         if ($nodes) {
 | |
|             // Initialize the current node to be the registry root.
 | |
|             $node = $this->data;
 | |
| 
 | |
|             // Traverse the registry to find the correct node for the result.
 | |
|             // TODO Create a new private method from part of code below, as it is almost equal to 'set' method
 | |
|             for ($i = 0, $n = \count($nodes) - 1; $i <= $n; $i++) {
 | |
|                 if (\is_object($node)) {
 | |
|                     if (!isset($node->{$nodes[$i]}) && ($i !== $n)) {
 | |
|                         $node->{$nodes[$i]} = new \stdClass();
 | |
|                     }
 | |
| 
 | |
|                     // Pass the child as pointer in case it is an array
 | |
|                     $node = &$node->{$nodes[$i]};
 | |
|                 } elseif (\is_array($node)) {
 | |
|                     if (($i !== $n) && !isset($node[$nodes[$i]])) {
 | |
|                         $node[$nodes[$i]] = new \stdClass();
 | |
|                     }
 | |
| 
 | |
|                     // Pass the child as pointer in case it is an array
 | |
|                     $node = &$node[$nodes[$i]];
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             if (!\is_array($node)) {
 | |
|                 // Convert the node to array to make append possible
 | |
|                 $node = \get_object_vars($node);
 | |
|             }
 | |
| 
 | |
|             $node[] = $value;
 | |
|             $result = $value;
 | |
|         }
 | |
| 
 | |
|         return $result;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Delete a registry value
 | |
|      *
 | |
|      * @param  string  $path  Registry Path (e.g. joomla.content.showauthor)
 | |
|      *
 | |
|      * @return  mixed  The value of the removed node or null if not set
 | |
|      *
 | |
|      * @since   1.6.0
 | |
|      */
 | |
|     public function remove($path)
 | |
|     {
 | |
|         // Cheap optimisation to direct remove the node if there is no separator
 | |
|         if ($this->separator === null || $this->separator === '' || !\strpos($path, $this->separator)) {
 | |
|             $result = (isset($this->data->$path) && $this->data->$path !== null && $this->data->$path !== '')
 | |
|                 ? $this->data->$path
 | |
|                 : null;
 | |
| 
 | |
|             unset($this->data->$path);
 | |
| 
 | |
|             return $result;
 | |
|         }
 | |
| 
 | |
|         /*
 | |
|          * Explode the registry path into an array and remove empty
 | |
|          * nodes that occur as a result of a double separator. ex: joomla..test
 | |
|          * Finally, re-key the array so they are sequential.
 | |
|          */
 | |
|         $nodes = \array_values(\array_filter(\explode($this->separator, $path), 'strlen'));
 | |
| 
 | |
|         if (!$nodes) {
 | |
|             return null;
 | |
|         }
 | |
| 
 | |
|         // Initialize the current node to be the registry root.
 | |
|         $node   = $this->data;
 | |
|         $parent = null;
 | |
| 
 | |
|         // Traverse the registry to find the correct node for the result.
 | |
|         for ($i = 0, $n = \count($nodes) - 1; $i < $n; $i++) {
 | |
|             if (\is_object($node)) {
 | |
|                 if (!isset($node->{$nodes[$i]})) {
 | |
|                     continue;
 | |
|                 }
 | |
| 
 | |
|                 $parent = &$node;
 | |
|                 $node   = $node->{$nodes[$i]};
 | |
| 
 | |
|                 continue;
 | |
|             }
 | |
| 
 | |
|             if (\is_array($node)) {
 | |
|                 if (!isset($node[$nodes[$i]])) {
 | |
|                     continue;
 | |
|                 }
 | |
| 
 | |
|                 $parent = &$node;
 | |
|                 $node   = $node[$nodes[$i]];
 | |
| 
 | |
|                 continue;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // Get the old value if exists so we can return it
 | |
|         switch (true) {
 | |
|             case \is_object($node):
 | |
|                 $result = $node->{$nodes[$i]} ?? null;
 | |
|                 unset($parent->{$nodes[$i]});
 | |
|                 break;
 | |
| 
 | |
|             case \is_array($node):
 | |
|                 $result = $node[$nodes[$i]] ?? null;
 | |
|                 unset($parent[$nodes[$i]]);
 | |
|                 break;
 | |
| 
 | |
|             default:
 | |
|                 $result = null;
 | |
|                 break;
 | |
|         }
 | |
| 
 | |
|         return $result;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Transforms a namespace to an array
 | |
|      *
 | |
|      * @return  array  An associative array holding the namespace data
 | |
|      *
 | |
|      * @since   1.0.0
 | |
|      */
 | |
|     public function toArray()
 | |
|     {
 | |
|         return $this->asArray($this->data);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Transforms a namespace to an object
 | |
|      *
 | |
|      * @return  object   An an object holding the namespace data
 | |
|      *
 | |
|      * @since   1.0.0
 | |
|      */
 | |
|     public function toObject()
 | |
|     {
 | |
|         return $this->data;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Get a namespace in a given string format
 | |
|      *
 | |
|      * @param  string  $format   Format to return the string in
 | |
|      * @param  array   $options  Parameters used by the formatter, see formatters for more info
 | |
|      *
 | |
|      * @return  string   Namespace in string format
 | |
|      *
 | |
|      * @since   1.0.0
 | |
|      */
 | |
|     public function toString($format = 'JSON', array $options = [])
 | |
|     {
 | |
|         return Factory::getFormat($format, $options)->objectToString($this->data, $options);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Method to recursively bind data to a parent object.
 | |
|      *
 | |
|      * @param  object   $parent     The parent object on which to attach the data values.
 | |
|      * @param  mixed    $data       An array or object of data to bind to the parent object.
 | |
|      * @param  boolean  $recursive  True to support recursive bindData.
 | |
|      * @param  boolean  $allowNull  True to allow null values.
 | |
|      *
 | |
|      * @return  void
 | |
|      *
 | |
|      * @since   1.0.0
 | |
|      */
 | |
|     protected function bindData($parent, $data, $recursive = true, $allowNull = true)
 | |
|     {
 | |
|         // The data object is now initialized
 | |
|         $this->initialized = true;
 | |
| 
 | |
|         // Ensure the input data is an array.
 | |
|         $data = \is_object($data) ? \get_object_vars($data) : (array) $data;
 | |
| 
 | |
|         foreach ($data as $k => $v) {
 | |
|             if (!$allowNull && !(($v !== null) && ($v !== ''))) {
 | |
|                 continue;
 | |
|             }
 | |
| 
 | |
|             if ($recursive && ((\is_array($v) && ArrayHelper::isAssociative($v)) || \is_object($v))) {
 | |
|                 if (!isset($parent->$k)) {
 | |
|                     $parent->$k = new \stdClass();
 | |
|                 }
 | |
| 
 | |
|                 $this->bindData($parent->$k, $v);
 | |
| 
 | |
|                 continue;
 | |
|             }
 | |
| 
 | |
|             $parent->$k = $v;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Method to recursively convert an object of data to an array.
 | |
|      *
 | |
|      * @param  object  $data  An object of data to return as an array.
 | |
|      *
 | |
|      * @return  array  Array representation of the input object.
 | |
|      *
 | |
|      * @since   1.0.0
 | |
|      */
 | |
|     protected function asArray($data)
 | |
|     {
 | |
|         $array = [];
 | |
| 
 | |
|         if (\is_object($data)) {
 | |
|             $data = \get_object_vars($data);
 | |
|         }
 | |
| 
 | |
|         foreach ($data as $k => $v) {
 | |
|             if (\is_object($v) || \is_array($v)) {
 | |
|                 $array[$k] = $this->asArray($v);
 | |
| 
 | |
|                 continue;
 | |
|             }
 | |
| 
 | |
|             $array[$k] = $v;
 | |
|         }
 | |
| 
 | |
|         return $array;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Dump to one dimension array.
 | |
|      *
 | |
|      * @param  string  $separator  The key separator.
 | |
|      *
 | |
|      * @return  string[]  Dumped array.
 | |
|      *
 | |
|      * @since   1.3.0
 | |
|      */
 | |
|     public function flatten($separator = null)
 | |
|     {
 | |
|         $array = [];
 | |
| 
 | |
|         if (empty($separator)) {
 | |
|             $separator = $this->separator;
 | |
|         }
 | |
| 
 | |
|         $this->toFlatten($separator, $this->data, $array);
 | |
| 
 | |
|         return $array;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Method to recursively convert data to one dimension array.
 | |
|      *
 | |
|      * @param  string        $separator  The key separator.
 | |
|      * @param  array|object  $data       Data source of this scope.
 | |
|      * @param  array         $array      The result array, it is passed by reference.
 | |
|      * @param  string        $prefix     Last level key prefix.
 | |
|      *
 | |
|      * @return  void
 | |
|      *
 | |
|      * @since   1.3.0
 | |
|      * @since   2.0.0  The parameter `$array` is now type hinted as `array`. Before 2.0.0, the type was not enforced.
 | |
|      */
 | |
|     protected function toFlatten($separator = null, $data = null, array &$array = [], $prefix = '')
 | |
|     {
 | |
|         $data = (array) $data;
 | |
| 
 | |
|         if (empty($separator)) {
 | |
|             $separator = $this->separator;
 | |
|         }
 | |
| 
 | |
|         foreach ($data as $k => $v) {
 | |
|             $key = $prefix ? $prefix . $separator . $k : $k;
 | |
| 
 | |
|             if (\is_object($v) || \is_array($v)) {
 | |
|                 $this->toFlatten($separator, $v, $array, $key);
 | |
| 
 | |
|                 continue;
 | |
|             }
 | |
| 
 | |
|             $array[$key] = $v;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Magic method to access separator property.
 | |
|      *
 | |
|      * @param  string  $name  The name of the property.
 | |
|      *
 | |
|      * @return string|null A value if the property name is valid, null otherwise.
 | |
|      *
 | |
|      * @since       __DEPLOY_VERSION__
 | |
|      * @deprecated  3.0  This is a B/C proxy for deprecated read accesses
 | |
|      */
 | |
|     public function __get($name)
 | |
|     {
 | |
|         switch ($name) {
 | |
|             case 'separator':
 | |
|                 \trigger_deprecation(
 | |
|                     'joomla/registry',
 | |
|                     '__DEPLOY_VERSION__',
 | |
|                     'The $separator parameter will be removed in version 3.',
 | |
|                     self::class,
 | |
|                     self::class
 | |
|                 );
 | |
| 
 | |
|                 return $this->separator;
 | |
| 
 | |
|             default:
 | |
|                 if (property_exists($this, $name)) {
 | |
|                     throw new \RuntimeException(
 | |
|                         \sprintf(
 | |
|                             'Cannot access protected or private property %s::$%s',
 | |
|                             __CLASS__,
 | |
|                             $name
 | |
|                         )
 | |
|                     );
 | |
|                 }
 | |
| 
 | |
|                 $trace = \debug_backtrace();
 | |
|                 \trigger_error(
 | |
|                     \sprintf(
 | |
|                         'Undefined property via __get(): %1$s in %2$s on line %3$s',
 | |
|                         $name,
 | |
|                         $trace[0]['file'],
 | |
|                         $trace[0]['line']
 | |
|                     ),
 | |
|                     E_USER_NOTICE
 | |
|                 );
 | |
| 
 | |
|                 return null;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Magic method to access separator property.
 | |
|      *
 | |
|      * @param  string  $name   The name of the property.
 | |
|      * @param  mixed   $value  The value of the property.
 | |
|      *
 | |
|      * @return void
 | |
|      *
 | |
|      * @since       __DEPLOY_VERSION__
 | |
|      * @deprecated  3.0  This is a B/C proxy for deprecated read accesses
 | |
|      */
 | |
|     public function __set($name, $value)
 | |
|     {
 | |
|         switch ($name) {
 | |
|             case 'separator':
 | |
|                 \trigger_deprecation(
 | |
|                     'joomla/registry',
 | |
|                     '__DEPLOY_VERSION__',
 | |
|                     'The $separator parameter will be removed in version 3.',
 | |
|                     self::class,
 | |
|                     self::class
 | |
|                 );
 | |
| 
 | |
|                 $this->separator = $value;
 | |
|                 break;
 | |
| 
 | |
|             default:
 | |
|                 if (property_exists($this, $name)) {
 | |
|                     throw new \RuntimeException(
 | |
|                         \sprintf(
 | |
|                             'Cannot access protected or private property %s::$%s',
 | |
|                             __CLASS__,
 | |
|                             $name
 | |
|                         )
 | |
|                     );
 | |
|                 }
 | |
| 
 | |
|                 \trigger_deprecation(
 | |
|                     'joomla/registry',
 | |
|                     '__DEPLOY_VERSION__',
 | |
|                     'Creating a property will be removed in version 3.',
 | |
|                     self::class,
 | |
|                     self::class
 | |
|                 );
 | |
| 
 | |
|                 $this->$name = $value;
 | |
|                 break;
 | |
|         }
 | |
|     }
 | |
| }
 |