PageRenderTime 38ms CodeModel.GetById 8ms app.highlight 21ms RepoModel.GetById 2ms app.codeStats 0ms

/libraries/vendor/joomla/registry/src/Registry.php

https://gitlab.com/vitaliylukin91/idea-rating
PHP | 785 lines | 343 code | 104 blank | 338 comment | 59 complexity | 01b037b9bbc0d829a7f43ac3632227be MD5 | raw file
  1<?php
  2/**
  3 * Part of the Joomla Framework Registry Package
  4 *
  5 * @copyright  Copyright (C) 2005 - 2015 Open Source Matters, Inc. All rights reserved.
  6 * @license    GNU General Public License version 2 or later; see LICENSE
  7 */
  8
  9namespace Joomla\Registry;
 10
 11use Joomla\Utilities\ArrayHelper;
 12
 13/**
 14 * Registry class
 15 *
 16 * @since  1.0
 17 */
 18class Registry implements \JsonSerializable, \ArrayAccess, \IteratorAggregate, \Countable
 19{
 20	/**
 21	 * Registry Object
 22	 *
 23	 * @var    object
 24	 * @since  1.0
 25	 */
 26	protected $data;
 27
 28	/**
 29	 * Registry instances container.
 30	 *
 31	 * @var    array
 32	 * @since  1.0
 33	 */
 34	protected static $instances = array();
 35
 36	/**
 37	 * Path separator
 38	 *
 39	 * @var    string
 40	 * @since  1.4.0
 41	 */
 42	public $separator = '.';
 43
 44	/**
 45	 * Constructor
 46	 *
 47	 * @param   mixed  $data  The data to bind to the new Registry object.
 48	 *
 49	 * @since   1.0
 50	 */
 51	public function __construct($data = null)
 52	{
 53		// Instantiate the internal data object.
 54		$this->data = new \stdClass;
 55
 56		// Optionally load supplied data.
 57		if (is_array($data) || is_object($data))
 58		{
 59			$this->bindData($this->data, $data);
 60
 61			return;
 62		}
 63
 64		if (!empty($data) && is_string($data))
 65		{
 66			$this->loadString($data);
 67		}
 68	}
 69
 70	/**
 71	 * Magic function to clone the registry object.
 72	 *
 73	 * @return  Registry
 74	 *
 75	 * @since   1.0
 76	 */
 77	public function __clone()
 78	{
 79		$this->data = unserialize(serialize($this->data));
 80	}
 81
 82	/**
 83	 * Magic function to render this object as a string using default args of toString method.
 84	 *
 85	 * @return  string
 86	 *
 87	 * @since   1.0
 88	 */
 89	public function __toString()
 90	{
 91		return $this->toString();
 92	}
 93
 94	/**
 95	 * Count elements of the data object
 96	 *
 97	 * @return  integer  The custom count as an integer.
 98	 *
 99	 * @link    http://php.net/manual/en/countable.count.php
100	 * @since   1.3.0
101	 */
102	public function count()
103	{
104		return count(get_object_vars($this->data));
105	}
106
107	/**
108	 * Implementation for the JsonSerializable interface.
109	 * Allows us to pass Registry objects to json_encode.
110	 *
111	 * @return  object
112	 *
113	 * @since   1.0
114	 * @note    The interface is only present in PHP 5.4 and up.
115	 */
116	public function jsonSerialize()
117	{
118		return $this->data;
119	}
120
121	/**
122	 * Sets a default value if not already assigned.
123	 *
124	 * @param   string  $key      The name of the parameter.
125	 * @param   mixed   $default  An optional value for the parameter.
126	 *
127	 * @return  mixed  The value set, or the default if the value was not previously set (or null).
128	 *
129	 * @since   1.0
130	 */
131	public function def($key, $default = '')
132	{
133		$value = $this->get($key, $default);
134		$this->set($key, $value);
135
136		return $value;
137	}
138
139	/**
140	 * Check if a registry path exists.
141	 *
142	 * @param   string  $path  Registry path (e.g. joomla.content.showauthor)
143	 *
144	 * @return  boolean
145	 *
146	 * @since   1.0
147	 */
148	public function exists($path)
149	{
150		// Return default value if path is empty
151		if (empty($path))
152		{
153			return false;
154		}
155
156		// Explode the registry path into an array
157		$nodes = explode($this->separator, $path);
158
159		// Initialize the current node to be the registry root.
160		$node = $this->data;
161		$found = false;
162
163		// Traverse the registry to find the correct node for the result.
164		foreach ($nodes as $n)
165		{
166			if (is_array($node) && isset($node[$n]))
167			{
168				$node = $node[$n];
169				$found = true;
170				continue;
171			}
172
173			if (!isset($node->$n))
174			{
175				return false;
176			}
177
178			$node = $node->$n;
179			$found = true;
180		}
181
182		return $found;
183	}
184
185	/**
186	 * Get a registry value.
187	 *
188	 * @param   string  $path     Registry path (e.g. joomla.content.showauthor)
189	 * @param   mixed   $default  Optional default value, returned if the internal value is null.
190	 *
191	 * @return  mixed  Value of entry or null
192	 *
193	 * @since   1.0
194	 */
195	public function get($path, $default = null)
196	{
197		// Return default value if path is empty
198		if (empty($path))
199		{
200			return $default;
201		}
202
203		if (!strpos($path, $this->separator))
204		{
205			return (isset($this->data->$path) && $this->data->$path !== null && $this->data->$path !== '') ? $this->data->$path : $default;
206		}
207
208		// Explode the registry path into an array
209		$nodes = explode($this->separator, trim($path));
210
211		// Initialize the current node to be the registry root.
212		$node = $this->data;
213		$found = false;
214
215		// Traverse the registry to find the correct node for the result.
216		foreach ($nodes as $n)
217		{
218			if (is_array($node) && isset($node[$n]))
219			{
220				$node = $node[$n];
221				$found = true;
222
223				continue;
224			}
225
226			if (!isset($node->$n))
227			{
228				return $default;
229			}
230
231			$node = $node->$n;
232			$found = true;
233		}
234
235		if (!$found || $node === null || $node === '')
236		{
237			return $default;
238		}
239
240		return $node;
241	}
242
243	/**
244	 * Returns a reference to a global Registry object, only creating it
245	 * if it doesn't already exist.
246	 *
247	 * This method must be invoked as:
248	 * <pre>$registry = Registry::getInstance($id);</pre>
249	 *
250	 * @param   string  $id  An ID for the registry instance
251	 *
252	 * @return  Registry  The Registry object.
253	 *
254	 * @since   1.0
255	 */
256	public static function getInstance($id)
257	{
258		if (empty(self::$instances[$id]))
259		{
260			self::$instances[$id] = new self;
261		}
262
263		return self::$instances[$id];
264	}
265
266	/**
267	 * Gets this object represented as an ArrayIterator.
268	 *
269	 * This allows the data properties to be accessed via a foreach statement.
270	 *
271	 * @return  \ArrayIterator  This object represented as an ArrayIterator.
272	 *
273	 * @see     IteratorAggregate::getIterator()
274	 * @since   1.3.0
275	 */
276	public function getIterator()
277	{
278		return new \ArrayIterator($this->data);
279	}
280
281	/**
282	 * Load a associative array of values into the default namespace
283	 *
284	 * @param   array    $array      Associative array of value to load
285	 * @param   boolean  $flattened  Load from a one-dimensional array
286	 * @param   string   $separator  The key separator
287	 *
288	 * @return  Registry  Return this object to support chaining.
289	 *
290	 * @since   1.0
291	 */
292	public function loadArray($array, $flattened = false, $separator = null)
293	{
294		if (!$flattened)
295		{
296			$this->bindData($this->data, $array);
297
298			return $this;
299		}
300
301		foreach ($array as $k => $v)
302		{
303			$this->set($k, $v, $separator);
304		}
305
306		return $this;
307	}
308
309	/**
310	 * Load the public variables of the object into the default namespace.
311	 *
312	 * @param   object  $object  The object holding the publics to load
313	 *
314	 * @return  Registry  Return this object to support chaining.
315	 *
316	 * @since   1.0
317	 */
318	public function loadObject($object)
319	{
320		$this->bindData($this->data, $object);
321
322		return $this;
323	}
324
325	/**
326	 * Load the contents of a file into the registry
327	 *
328	 * @param   string  $file     Path to file to load
329	 * @param   string  $format   Format of the file [optional: defaults to JSON]
330	 * @param   array   $options  Options used by the formatter
331	 *
332	 * @return  Registry  Return this object to support chaining.
333	 *
334	 * @since   1.0
335	 */
336	public function loadFile($file, $format = 'JSON', $options = array())
337	{
338		$data = file_get_contents($file);
339
340		return $this->loadString($data, $format, $options);
341	}
342
343	/**
344	 * Load a string into the registry
345	 *
346	 * @param   string  $data     String to load into the registry
347	 * @param   string  $format   Format of the string
348	 * @param   array   $options  Options used by the formatter
349	 *
350	 * @return  Registry  Return this object to support chaining.
351	 *
352	 * @since   1.0
353	 */
354	public function loadString($data, $format = 'JSON', $options = array())
355	{
356		// Load a string into the given namespace [or default namespace if not given]
357		$handler = AbstractRegistryFormat::getInstance($format);
358
359		$obj = $handler->stringToObject($data, $options);
360		$this->loadObject($obj);
361
362		return $this;
363	}
364
365	/**
366	 * Merge a Registry object into this one
367	 *
368	 * @param   Registry  $source     Source Registry object to merge.
369	 * @param   boolean   $recursive  True to support recursive merge the children values.
370	 *
371	 * @return  Registry  Return this object to support chaining.
372	 *
373	 * @since   1.0
374	 */
375	public function merge($source, $recursive = false)
376	{
377		if (!$source instanceof Registry)
378		{
379			return false;
380		}
381
382		$this->bindData($this->data, $source->toArray(), $recursive, false);
383
384		return $this;
385	}
386
387	/**
388	 * Method to extract a sub-registry from path
389	 *
390	 * @param   string  $path  Registry path (e.g. joomla.content.showauthor)
391	 *
392	 * @return  Registry|null  Registry object if data is present
393	 *
394	 * @since   1.2.0
395	 */
396	public function extract($path)
397	{
398		$data = $this->get($path);
399
400		if (is_null($data))
401		{
402			return null;
403		}
404
405		return new Registry($data);
406	}
407
408	/**
409	 * Checks whether an offset exists in the iterator.
410	 *
411	 * @param   mixed  $offset  The array offset.
412	 *
413	 * @return  boolean  True if the offset exists, false otherwise.
414	 *
415	 * @since   1.0
416	 */
417	public function offsetExists($offset)
418	{
419		return (boolean) ($this->get($offset) !== null);
420	}
421
422	/**
423	 * Gets an offset in the iterator.
424	 *
425	 * @param   mixed  $offset  The array offset.
426	 *
427	 * @return  mixed  The array value if it exists, null otherwise.
428	 *
429	 * @since   1.0
430	 */
431	public function offsetGet($offset)
432	{
433		return $this->get($offset);
434	}
435
436	/**
437	 * Sets an offset in the iterator.
438	 *
439	 * @param   mixed  $offset  The array offset.
440	 * @param   mixed  $value   The array value.
441	 *
442	 * @return  void
443	 *
444	 * @since   1.0
445	 */
446	public function offsetSet($offset, $value)
447	{
448		$this->set($offset, $value);
449	}
450
451	/**
452	 * Unsets an offset in the iterator.
453	 *
454	 * @param   mixed  $offset  The array offset.
455	 *
456	 * @return  void
457	 *
458	 * @since   1.0
459	 */
460	public function offsetUnset($offset)
461	{
462		$this->set($offset, null);
463	}
464
465	/**
466	 * Set a registry value.
467	 *
468	 * @param   string  $path       Registry Path (e.g. joomla.content.showauthor)
469	 * @param   mixed   $value      Value of entry
470	 * @param   string  $separator  The key separator
471	 *
472	 * @return  mixed  The value of the that has been set.
473	 *
474	 * @since   1.0
475	 */
476	public function set($path, $value, $separator = null)
477	{
478		if (empty($separator))
479		{
480			$separator = $this->separator;
481		}
482
483		/**
484		 * Explode the registry path into an array and remove empty
485		 * nodes that occur as a result of a double separator. ex: joomla..test
486		 * Finally, re-key the array so they are sequential.
487		 */
488		$nodes = array_values(array_filter(explode($separator, $path), 'strlen'));
489
490		if (!$nodes)
491		{
492			return null;
493		}
494
495		// Initialize the current node to be the registry root.
496		$node = $this->data;
497
498		// Traverse the registry to find the correct node for the result.
499		for ($i = 0, $n = count($nodes) - 1; $i < $n; $i++)
500		{
501			if (is_object($node))
502			{
503				if (!isset($node->{$nodes[$i]}) && ($i != $n))
504				{
505					$node->{$nodes[$i]} = new \stdClass;
506				}
507
508				// Pass the child as pointer in case it is an object
509				$node = &$node->{$nodes[$i]};
510
511				continue;
512			}
513
514			if (is_array($node))
515			{
516				if (!isset($node[$nodes[$i]]) && ($i != $n))
517				{
518					$node[$nodes[$i]] = new \stdClass;
519				}
520
521				// Pass the child as pointer in case it is an array
522				$node = &$node[$nodes[$i]];
523			}
524		}
525
526		// Get the old value if exists so we can return it
527		switch (true)
528		{
529			case (is_object($node)):
530				$result = $node->{$nodes[$i]} = $value;
531				break;
532
533			case (is_array($node)):
534				$result = $node[$nodes[$i]] = $value;
535				break;
536
537			default:
538				$result = null;
539				break;
540		}
541
542		return $result;
543	}
544
545	/**
546	 * Append value to a path in registry
547	 *
548	 * @param   string  $path   Parent registry Path (e.g. joomla.content.showauthor)
549	 * @param   mixed   $value  Value of entry
550	 *
551	 * @return  mixed  The value of the that has been set.
552	 *
553	 * @since   1.4.0
554	 */
555	public function append($path, $value)
556	{
557		$result = null;
558
559		/**
560		 * Explode the registry path into an array and remove empty
561		 * nodes that occur as a result of a double dot. ex: joomla..test
562		 * Finally, re-key the array so they are sequential.
563		 */
564		$nodes = array_values(array_filter(explode('.', $path), 'strlen'));
565
566		if ($nodes)
567		{
568			// Initialize the current node to be the registry root.
569			$node = $this->data;
570
571			// Traverse the registry to find the correct node for the result.
572			// TODO Create a new private method from part of code below, as it is almost equal to 'set' method
573			for ($i = 0, $n = count($nodes) - 1; $i <= $n; $i++)
574			{
575				if (is_object($node))
576				{
577					if (!isset($node->{$nodes[$i]}) && ($i != $n))
578					{
579						$node->{$nodes[$i]} = new \stdClass;
580					}
581
582					// Pass the child as pointer in case it is an array
583					$node = &$node->{$nodes[$i]};
584				}
585				elseif (is_array($node))
586				{
587					if (!isset($node[$nodes[$i]]) && ($i != $n))
588					{
589						$node[$nodes[$i]] = new \stdClass;
590					}
591
592					// Pass the child as pointer in case it is an array
593					$node = &$node[$nodes[$i]];
594				}
595			}
596
597			if (!is_array($node))
598			// Convert the node to array to make append possible
599			{
600				$node = get_object_vars($node);
601			}
602
603			array_push($node, $value);
604			$result = $value;
605		}
606
607		return $result;
608	}
609
610	/**
611	 * Transforms a namespace to an array
612	 *
613	 * @return  array  An associative array holding the namespace data
614	 *
615	 * @since   1.0
616	 */
617	public function toArray()
618	{
619		return (array) $this->asArray($this->data);
620	}
621
622	/**
623	 * Transforms a namespace to an object
624	 *
625	 * @return  object   An an object holding the namespace data
626	 *
627	 * @since   1.0
628	 */
629	public function toObject()
630	{
631		return $this->data;
632	}
633
634	/**
635	 * Get a namespace in a given string format
636	 *
637	 * @param   string  $format   Format to return the string in
638	 * @param   mixed   $options  Parameters used by the formatter, see formatters for more info
639	 *
640	 * @return  string   Namespace in string format
641	 *
642	 * @since   1.0
643	 */
644	public function toString($format = 'JSON', $options = array())
645	{
646		// Return a namespace in a given format
647		$handler = AbstractRegistryFormat::getInstance($format);
648
649		return $handler->objectToString($this->data, $options);
650	}
651
652	/**
653	 * Method to recursively bind data to a parent object.
654	 *
655	 * @param   object   $parent     The parent object on which to attach the data values.
656	 * @param   mixed    $data       An array or object of data to bind to the parent object.
657	 * @param   boolean  $recursive  True to support recursive bindData.
658	 * @param   boolean  $allowNull  True to allow null values.
659	 *
660	 * @return  void
661	 *
662	 * @since   1.0
663	 */
664	protected function bindData($parent, $data, $recursive = true, $allowNull = true)
665	{
666		// Ensure the input data is an array.
667		$data = is_object($data)
668			? get_object_vars($data)
669			: (array) $data;
670
671		foreach ($data as $k => $v)
672		{
673			if (!$allowNull && !(($v !== null) && ($v !== '')))
674			{
675				continue;
676			}
677
678			if ($recursive && ((is_array($v) && ArrayHelper::isAssociative($v)) || is_object($v)))
679			{
680				if (!isset($parent->$k))
681				{
682					$parent->$k = new \stdClass;
683				}
684
685				$this->bindData($parent->$k, $v);
686
687				continue;
688			}
689
690			$parent->$k = $v;
691		}
692	}
693
694	/**
695	 * Method to recursively convert an object of data to an array.
696	 *
697	 * @param   object  $data  An object of data to return as an array.
698	 *
699	 * @return  array  Array representation of the input object.
700	 *
701	 * @since   1.0
702	 */
703	protected function asArray($data)
704	{
705		$array = array();
706
707		if (is_object($data))
708		{
709			$data = get_object_vars($data);
710		}
711
712		foreach ($data as $k => $v)
713		{
714			if (is_object($v) || is_array($v))
715			{
716				$array[$k] = $this->asArray($v);
717
718				continue;
719			}
720
721			$array[$k] = $v;
722		}
723
724		return $array;
725	}
726
727	/**
728	 * Dump to one dimension array.
729	 *
730	 * @param   string  $separator  The key separator.
731	 *
732	 * @return  string[]  Dumped array.
733	 *
734	 * @since   1.3.0
735	 */
736	public function flatten($separator = null)
737	{
738		$array = array();
739
740		if (empty($separator))
741		{
742			$separator = $this->separator;
743		}
744
745		$this->toFlatten($separator, $this->data, $array);
746
747		return $array;
748	}
749
750	/**
751	 * Method to recursively convert data to one dimension array.
752	 *
753	 * @param   string        $separator  The key separator.
754	 * @param   array|object  $data       Data source of this scope.
755	 * @param   array         &$array     The result array, it is pass by reference.
756	 * @param   string        $prefix     Last level key prefix.
757	 *
758	 * @return  void
759	 *
760	 * @since   1.3.0
761	 */
762	protected function toFlatten($separator = null, $data = null, &$array = array(), $prefix = '')
763	{
764		$data = (array) $data;
765
766		if (empty($separator))
767		{
768			$separator = $this->separator;
769		}
770
771		foreach ($data as $k => $v)
772		{
773			$key = $prefix ? $prefix . $separator . $k : $k;
774
775			if (is_object($v) || is_array($v))
776			{
777				$this->toFlatten($separator, $v, $array, $key);
778
779				continue;
780			}
781
782			$array[$key] = $v;
783		}
784	}
785}