mirror of
https://github.com/getgrav/grav.git
synced 2026-03-05 03:51:50 +01:00
Add ArrayObject and make Object not to implement ArrayAccess interface. Remove Toolbox dependency.
This commit is contained in:
69
system/src/Grav/Framework/Object/ArrayObject.php
Normal file
69
system/src/Grav/Framework/Object/ArrayObject.php
Normal file
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Grav\Framework\Object
|
||||
*
|
||||
* @copyright Copyright (C) 2014 - 2017 RocketTheme, LLC. All rights reserved.
|
||||
* @license MIT License; see LICENSE file for details.
|
||||
*/
|
||||
|
||||
namespace Grav\Framework\Object;
|
||||
|
||||
/**
|
||||
* Object class.
|
||||
*
|
||||
* @package Grav\Framework\Object
|
||||
*/
|
||||
class ArrayObject extends Object implements \ArrayAccess
|
||||
{
|
||||
/**
|
||||
* Whether or not an offset exists.
|
||||
*
|
||||
* @param mixed $offset An offset to check for.
|
||||
* @return bool Returns TRUE on success or FALSE on failure.
|
||||
*/
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
if (strpos($offset, '.') !== false) {
|
||||
$test = new \stdClass();
|
||||
return $this->getProperty($offset, $test) !== $test;
|
||||
}
|
||||
|
||||
return $this->__isset($offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value at specified offset.
|
||||
*
|
||||
* @param mixed $offset The offset to retrieve.
|
||||
* @return mixed Can return all value types.
|
||||
*/
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
return $this->getProperty($offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns a value to the specified offset.
|
||||
*
|
||||
* @param mixed $offset The offset to assign the value to.
|
||||
* @param mixed $value The value to set.
|
||||
*/
|
||||
public function offsetSet($offset, $value)
|
||||
{
|
||||
$this->setProperty($offset, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsets an offset.
|
||||
*
|
||||
* @param mixed $offset The offset to unset.
|
||||
*/
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
if (strpos($offset, '.') !== false) {
|
||||
$this->setProperty($offset, null);
|
||||
} else {
|
||||
$this->__unset($offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,9 +8,6 @@
|
||||
|
||||
namespace Grav\Framework\Object;
|
||||
|
||||
use RocketTheme\Toolbox\ArrayTraits\Export;
|
||||
use RocketTheme\Toolbox\ArrayTraits\NestedArrayAccessWithGetters;
|
||||
|
||||
/**
|
||||
* Object class.
|
||||
*
|
||||
@@ -18,10 +15,126 @@ use RocketTheme\Toolbox\ArrayTraits\NestedArrayAccessWithGetters;
|
||||
*/
|
||||
class Object implements ObjectInterface
|
||||
{
|
||||
use ObjectTrait, NestedArrayAccessWithGetters, Export {
|
||||
NestedArrayAccessWithGetters::offsetExists as private parentOffsetExists;
|
||||
NestedArrayAccessWithGetters::offsetGet as private parentOffsetGet;
|
||||
NestedArrayAccessWithGetters::offsetSet as private parentOffsetSet;
|
||||
use ObjectTrait;
|
||||
|
||||
static protected $prefix = 'o.';
|
||||
static protected $type;
|
||||
|
||||
/**
|
||||
* Get value by using dot notation for nested arrays/objects.
|
||||
*
|
||||
* @example $value = $this->get('this.is.my.nested.variable');
|
||||
*
|
||||
* @param string $name Dot separated path to the requested value.
|
||||
* @param mixed $default Default value (or null).
|
||||
* @param string $separator Separator, defaults to '.'
|
||||
* @return mixed Value.
|
||||
*/
|
||||
public function getProperty($name, $default = null, $separator = '.')
|
||||
{
|
||||
$path = explode($separator, $name);
|
||||
$offset = array_shift($path);
|
||||
$current = $this->__get($offset);
|
||||
|
||||
do {
|
||||
// We are done: return current variable.
|
||||
if (empty($path)) {
|
||||
return $current;
|
||||
}
|
||||
|
||||
// Get property of nested Object.
|
||||
if ($current instanceof Object) {
|
||||
return $current->getProperty(implode($separator, $path), $default, $separator);
|
||||
}
|
||||
|
||||
$offset = array_shift($path);
|
||||
|
||||
if ((is_array($current) || is_a($current, 'ArrayAccess')) && isset($current[$offset])) {
|
||||
$current = $current[$offset];
|
||||
} elseif (is_object($current) && isset($current->{$offset})) {
|
||||
$current = $current->{$offset};
|
||||
} else {
|
||||
return $default;
|
||||
}
|
||||
} while ($path);
|
||||
|
||||
return $current;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set value by using dot notation for nested arrays/objects.
|
||||
*
|
||||
* @example $data->set('this.is.my.nested.variable', $value);
|
||||
*
|
||||
* @param string $name Dot separated path to the requested value.
|
||||
* @param mixed $value New value.
|
||||
* @param string $separator Separator, defaults to '.'
|
||||
* @return $this
|
||||
*/
|
||||
public function setProperty($name, $value, $separator = '.')
|
||||
{
|
||||
$path = explode($separator, $name);
|
||||
$offset = array_shift($path);
|
||||
|
||||
// Set simple variable.
|
||||
if (empty($path)) {
|
||||
$this->__set($offset, $value);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
$current = &$this->getRef($offset, true);
|
||||
|
||||
do {
|
||||
// Set property of nested Object.
|
||||
if ($current instanceof Object) {
|
||||
$current->setProperty(implode($separator, $path), $value, $separator);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
$offset = array_shift($path);
|
||||
|
||||
if (is_object($current)) {
|
||||
// Handle objects.
|
||||
if (!isset($current->{$offset})) {
|
||||
$current->{$offset} = [];
|
||||
}
|
||||
$current = &$current->{$offset};
|
||||
} else {
|
||||
// Handle arrays and scalars.
|
||||
if (!is_array($current)) {
|
||||
$current = [$offset => []];
|
||||
} elseif (!isset($current[$offset])) {
|
||||
$current[$offset] = [];
|
||||
}
|
||||
$current = &$current[$offset];
|
||||
}
|
||||
} while ($path);
|
||||
|
||||
$current = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define value by using dot notation for nested arrays/objects.
|
||||
*
|
||||
* @example $data->defProperty('this.is.my.nested.variable', $value);
|
||||
*
|
||||
* @param string $name Dot separated path to the requested value.
|
||||
* @param mixed $value New value.
|
||||
* @param string $separator Separator, defaults to '.'
|
||||
* @return $this
|
||||
*/
|
||||
public function defProperty($name, $value, $separator = '.')
|
||||
{
|
||||
$test = new \stdClass;
|
||||
if ($this->getProperty($name, $test, $separator) === $test) {
|
||||
$this->setProperty($name, $value, $separator);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -30,11 +143,9 @@ class Object implements ObjectInterface
|
||||
* @param mixed $offset An offset to check for.
|
||||
* @return bool Returns TRUE on success or FALSE on failure.
|
||||
*/
|
||||
public function offsetExists($offset)
|
||||
public function __isset($offset)
|
||||
{
|
||||
$methodName = "offsetLoad_{$offset}";
|
||||
|
||||
return $this->parentOffsetExists($offset) || method_exists($this, $methodName);
|
||||
return array_key_exists($offset, $this->items) || $this->isPropertyDefined($offset);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,18 +154,11 @@ class Object implements ObjectInterface
|
||||
* @param mixed $offset The offset to retrieve.
|
||||
* @return mixed Can return all value types.
|
||||
*/
|
||||
public function offsetGet($offset)
|
||||
public function __get($offset)
|
||||
{
|
||||
$methodName = "offsetLoad_{$offset}";
|
||||
|
||||
if (!$this->parentOffsetExists($offset) && method_exists($this, $methodName)) {
|
||||
$this->offsetSet($offset, $this->{$methodName}());
|
||||
}
|
||||
|
||||
return $this->parentOffsetGet($offset);
|
||||
return $this->getRef($offset);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Assigns a value to the specified offset with a possibility to check or alter the value by
|
||||
* $this->offsetPrepare_{$offset}().
|
||||
@@ -62,15 +166,41 @@ class Object implements ObjectInterface
|
||||
* @param mixed $offset The offset to assign the value to.
|
||||
* @param mixed $value The value to set.
|
||||
*/
|
||||
public function offsetSet($offset, $value)
|
||||
public function __set($offset, $value)
|
||||
{
|
||||
$methodName = "offsetPrepare_{$offset}";
|
||||
if ($this->isPropertyDefined($offset)) {
|
||||
$methodName = "offsetPrepare_{$offset}";
|
||||
|
||||
if (method_exists($this, $methodName)) {
|
||||
$value = $this->{$methodName}($value);
|
||||
if (method_exists($this, $methodName)) {
|
||||
$this->{$offset} = $this->{$methodName}($value);
|
||||
}
|
||||
}
|
||||
|
||||
$this->parentOffsetSet($offset, $value);
|
||||
$this->items[$offset] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic method to unset the attribute
|
||||
*
|
||||
* @param mixed $offset The name value to unset
|
||||
*/
|
||||
public function __unset($offset)
|
||||
{
|
||||
if ($this->isPropertyDefined($offset)) {
|
||||
$this->{$offset} = null;
|
||||
} else {
|
||||
unset($this->items[$offset]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert object into an array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function toArray()
|
||||
{
|
||||
return $this->items;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,6 +210,40 @@ class Object implements ObjectInterface
|
||||
*/
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return ['key' => $this->getKey(), 'object' => $this->toArray()];
|
||||
return [
|
||||
'key' => $this->getKey(),
|
||||
'type' => $this->getType(true),
|
||||
'object' => $this->toArray()
|
||||
];
|
||||
}
|
||||
|
||||
protected function &getRef($offset, $new = false)
|
||||
{
|
||||
if ($this->isPropertyDefined($offset)) {
|
||||
if ($this->{$offset} === null) {
|
||||
$methodName = "offsetLoad_{$offset}";
|
||||
|
||||
if (method_exists($this, $methodName)) {
|
||||
$this->{$offset} = $this->{$methodName}();
|
||||
}
|
||||
}
|
||||
|
||||
return $this->{$offset};
|
||||
}
|
||||
|
||||
if (!isset($this->items[$offset])) {
|
||||
if (!$new) {
|
||||
$null = null;
|
||||
return $null;
|
||||
}
|
||||
$this->items[$offset] = [];
|
||||
}
|
||||
|
||||
return $this->items[$offset];
|
||||
}
|
||||
|
||||
protected function isPropertyDefined($offset)
|
||||
{
|
||||
return array_key_exists($offset, get_object_vars($this));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ class ObjectCollection extends ArrayCollection implements ObjectCollectionInterf
|
||||
{
|
||||
use ObjectCollectionTrait;
|
||||
|
||||
static protected $prefix = 'c.';
|
||||
|
||||
/**
|
||||
* @param array $elements
|
||||
* @param string $key
|
||||
@@ -27,7 +29,11 @@ class ObjectCollection extends ArrayCollection implements ObjectCollectionInterf
|
||||
{
|
||||
parent::__construct($elements);
|
||||
|
||||
$this->key = $key ?: $this->getKey() ?: __CLASS__ . '@' . spl_object_hash($this);
|
||||
$this->key = $key !== null ? $key : (string) $this;
|
||||
|
||||
if ($this->key === null) {
|
||||
throw new \InvalidArgumentException('Object cannot be created without assigning a key to it');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -36,14 +36,14 @@ interface ObjectCollectionInterface extends CollectionInterface, ObjectInterface
|
||||
|
||||
/**
|
||||
* @param string $property Object property to be fetched.
|
||||
* @return array Values of the property.
|
||||
* @param mixed $default Default value if not set.
|
||||
* @return array Property value.
|
||||
*/
|
||||
public function getProperty($property);
|
||||
public function getProperty($property, $default = null);
|
||||
|
||||
/**
|
||||
* @param string $property Object property to be updated.
|
||||
* @param string $value New value.
|
||||
* @return $this
|
||||
*/
|
||||
public function setProperty($property, $value);
|
||||
|
||||
|
||||
@@ -46,14 +46,16 @@ trait ObjectCollectionTrait
|
||||
|
||||
/**
|
||||
* @param string $property Object property to be fetched.
|
||||
* @param mixed $default Default value if not set.
|
||||
* @return array Key/Value pairs of the properties.
|
||||
*/
|
||||
public function getProperty($property)
|
||||
public function getProperty($property, $default = null)
|
||||
{
|
||||
$list = [];
|
||||
|
||||
/** @var ObjectInterface $element */
|
||||
foreach ($this as $id => $element) {
|
||||
$list[$id] = isset($element[$property]) ? $element[$property] : null;
|
||||
$list[$id] = $element->getProperty($property, $default);
|
||||
}
|
||||
|
||||
return $list;
|
||||
@@ -62,12 +64,16 @@ trait ObjectCollectionTrait
|
||||
/**
|
||||
* @param string $property Object property to be updated.
|
||||
* @param string $value New value.
|
||||
* @return $this
|
||||
*/
|
||||
public function setProperty($property, $value)
|
||||
{
|
||||
/** @var ObjectInterface $element */
|
||||
foreach ($this as $element) {
|
||||
$element[$property] = $value;
|
||||
$element->setProperty($property, $value);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -98,8 +104,9 @@ trait ObjectCollectionTrait
|
||||
{
|
||||
$list = [];
|
||||
|
||||
/** @var ObjectInterface $element */
|
||||
foreach ($this as $element) {
|
||||
$list[$element[$property]][] = $element;
|
||||
$list[(string) $element->getProperty($property)][] = $element;
|
||||
}
|
||||
|
||||
return $list;
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Grav\Framework\Object;
|
||||
* Object Interface
|
||||
* @package Grav\Framework\Object
|
||||
*/
|
||||
interface ObjectInterface extends \ArrayAccess, \JsonSerializable
|
||||
interface ObjectInterface extends \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* @param array $elements
|
||||
@@ -20,8 +20,26 @@ interface ObjectInterface extends \ArrayAccess, \JsonSerializable
|
||||
*/
|
||||
public function __construct(array $elements = [], $key = null);
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getType();
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getKey();
|
||||
|
||||
/**
|
||||
* @param string $property Object property to be fetched.
|
||||
* @param mixed $default Default value if not set.
|
||||
* @return mixed Property value.
|
||||
*/
|
||||
public function getProperty($property, $default = null);
|
||||
|
||||
/**
|
||||
* @param string $property Object property to be updated.
|
||||
* @param string $value New value.
|
||||
*/
|
||||
public function setProperty($property, $value);
|
||||
}
|
||||
|
||||
@@ -35,13 +35,27 @@ trait ObjectTrait
|
||||
{
|
||||
|
||||
$this->items = $elements;
|
||||
$this->key = $key !== null ? $key : $this->getKey();
|
||||
$this->key = $key !== null ? $key : (string) $this;
|
||||
|
||||
if ($this->key === null) {
|
||||
throw new \InvalidArgumentException('Object cannot be created without assigning a key');
|
||||
throw new \InvalidArgumentException('Object cannot be created without assigning a key to it');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $prefix
|
||||
* @return string
|
||||
*/
|
||||
public function getType($prefix = false)
|
||||
{
|
||||
if (static::$type) {
|
||||
return ($prefix ? static::$prefix : '') . static::$type;
|
||||
}
|
||||
|
||||
$class = get_class($this);
|
||||
return ($prefix ? static::$prefix : '') . strtolower(substr($class, strrpos($class, '\\') + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
@@ -57,6 +71,6 @@ trait ObjectTrait
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return __CLASS__ . '@' . spl_object_hash($this);
|
||||
return $this->getKey() ?: $this->getType() . '@' . spl_object_hash($this);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user