Major update on Object classes (backwards incompatible)

This commit is contained in:
Matias Griese 2017-09-13 09:50:34 +03:00
parent 62389975a2
commit 23592b8a76
20 changed files with 1292 additions and 404 deletions

View File

@ -0,0 +1,64 @@
<?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\Access;
/**
* ArrayAccess Object Trait
* @package Grav\Framework\Object
*/
trait ArrayAccessTrait
{
/**
* 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)
{
return $this->hasProperty($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)
{
$this->unsetProperty($offset);
}
abstract public function hasProperty($property);
abstract public function getProperty($property, $default = null);
abstract public function setProperty($property, $value);
abstract public function unsetProperty($property);
}

View File

@ -0,0 +1,64 @@
<?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\Access;
/**
* Nested ArrayAccess Object Trait
* @package Grav\Framework\Object
*/
trait NestedArrayAccessTrait
{
/**
* 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)
{
return $this->hasNestedProperty($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->getNestedProperty($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->setNestedProperty($offset, $value);
}
/**
* Unsets an offset.
*
* @param mixed $offset The offset to unset.
*/
public function offsetUnset($offset)
{
$this->unsetNestedProperty($offset);
}
abstract public function hasNestedProperty($property, $separator = null);
abstract public function getNestedProperty($property, $default = null, $separator = null);
abstract public function setNestedProperty($property, $value, $separator = null);
abstract public function unsetNestedProperty($property, $separator = null);
}

View File

@ -0,0 +1,124 @@
<?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\Access;
use Grav\Framework\Object\Interfaces\NestedObjectInterface;
/**
* Nested Properties Collection Trait
* @package Grav\Framework\Object\Properties
*/
trait NestedPropertyCollectionTrait
{
/**
* @param string $property Object property to be matched.
* @param string $separator Separator, defaults to '.'
* @return array Key/Value pairs of the properties.
*/
public function hasNestedProperty($property, $separator = null)
{
$list = [];
/** @var NestedObjectInterface $element */
foreach ($this->getIterator() as $id => $element) {
$list[$id] = $element->hasNestedProperty($property, $separator);
}
return $list;
}
/**
* @param string $property Object property to be fetched.
* @param mixed $default Default value if not set.
* @param string $separator Separator, defaults to '.'
* @return array Key/Value pairs of the properties.
*/
public function getNestedProperty($property, $default = null, $separator = null)
{
$list = [];
/** @var NestedObjectInterface $element */
foreach ($this->getIterator() as $id => $element) {
$list[$id] = $element->getNestedProperty($property, $default, $separator);
}
return $list;
}
/**
* @param string $property Object property to be updated.
* @param string $value New value.
* @param string $separator Separator, defaults to '.'
* @return $this
*/
public function setNestedProperty($property, $value, $separator = null)
{
/** @var NestedObjectInterface $element */
foreach ($this->getIterator() as $element) {
$element->setNestedProperty($property, $value, $separator);
}
return $this;
}
/**
* @param string $property Object property to be updated.
* @param string $separator Separator, defaults to '.'
* @return $this
*/
public function unsetNestedProperty($property, $separator = null)
{
/** @var NestedObjectInterface $element */
foreach ($this->getIterator() as $element) {
$element->unsetNestedProperty($property, $separator);
}
return $this;
}
/**
* @param string $property Object property to be updated.
* @param string $default Default value.
* @param string $separator Separator, defaults to '.'
* @return $this
*/
public function defNestedProperty($property, $default, $separator = null)
{
/** @var NestedObjectInterface $element */
foreach ($this->getIterator() as $element) {
$element->defNestedProperty($property, $default, $separator);
}
return $this;
}
/**
* Group items in the collection by a field.
*
* @param string $property Object property to be used to make groups.
* @param string $separator Separator, defaults to '.'
* @return array
*/
public function group($property, $separator = null)
{
$list = [];
/** @var NestedObjectInterface $element */
foreach ($this->getIterator() as $element) {
$list[(string) $element->getNestedProperty($property, null, $separator)][] = $element;
}
return $list;
}
/**
* @return \Traversable
*/
abstract public function getIterator();
}

View File

@ -0,0 +1,179 @@
<?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\Access;
use Grav\Framework\Object\Interfaces\ObjectInterface;
/**
* Nested Property Object Trait
* @package Grav\Framework\Object\Traits
*/
trait NestedPropertyTrait
{
/**
* @param string $property Object property name.
* @param string $separator Separator, defaults to '.'
* @return bool True if property has been defined (can be null).
*/
public function hasNestedProperty($property, $separator = null)
{
$test = new \stdClass;
return $this->getNestedProperty($property, $test, $separator) !== $test;
}
/**
* @param string $property Object property to be fetched.
* @param mixed $default Default value if property has not been set.
* @param string $separator Separator, defaults to '.'
* @return mixed Property value.
*/
public function getNestedProperty($property, $default = null, $separator = null)
{
$path = explode($separator ?: '.', $property);
$offset = array_shift($path);
if (!$this->hasProperty($offset)) {
return $default;
}
$current = $this->getProperty($offset);
while ($path) {
// Get property of nested Object.
if ($current instanceof ObjectInterface) {
if (method_exists($current, 'getNestedProperty')) {
return $current->getNestedProperty(implode($separator, $path), $default, $separator);
}
return $current->getProperty(implode($separator, $path), $default);
}
$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;
}
};
return $current;
}
/**
* @param string $property Object property to be updated.
* @param string $value New value.
* @param string $separator Separator, defaults to '.'
* @return $this
* @throws \RuntimeException
*/
public function setNestedProperty($property, $value, $separator = null)
{
$path = explode($separator ?: '.', $property);
$offset = array_shift($path);
if (!$path) {
$this->setProperty($offset, $value);
return $this;
}
$current = &$this->doGetProperty($offset, null, true);
while ($path) {
$offset = array_shift($path);
// Handle arrays and scalars.
if ($current === null) {
$current = [$offset => []];
} elseif (is_array($current)) {
if (!isset($current[$offset])) {
$current[$offset] = [];
}
} else {
throw new \RuntimeException('Cannot set nested property on non-array value');
}
$current = &$current[$offset];
};
$current = $value;
return $this;
}
/**
* @param string $property Object property to be updated.
* @param string $separator Separator, defaults to '.'
* @return $this
* @throws \RuntimeException
*/
public function unsetNestedProperty($property, $separator = null)
{
$path = explode($separator ?: '.', $property);
$offset = array_shift($path);
if (!$path) {
$this->unsetProperty($offset);
return $this;
}
$last = array_pop($path);
$current = &$this->doGetProperty($offset, null, true);
while ($path) {
$offset = array_shift($path);
// Handle arrays and scalars.
if ($current === null) {
return $this;
}
if (is_array($current)) {
if (!isset($current[$offset])) {
return $this;
}
} else {
throw new \RuntimeException('Cannot set nested property on non-array value');
}
$current = &$current[$offset];
};
unset($current[$last]);
return $this;
}
/**
* @param string $property Object property to be updated.
* @param string $default Default value.
* @param string $separator Separator, defaults to '.'
* @return $this
* @throws \RuntimeException
*/
public function defNestedProperty($property, $default, $separator = null)
{
if (!$this->hasNestedProperty($property, $separator)) {
$this->setNestedProperty($property, $default, $separator);
}
return $this;
}
abstract public function hasProperty($property);
abstract public function getProperty($property, $default = null);
abstract public function setProperty($property, $value);
abstract public function unsetProperty($property);
abstract protected function &doGetProperty($property, $default = null, $doCreate = false);
}

View File

@ -0,0 +1,64 @@
<?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\Access;
/**
* Overloaded Property Object Trait
* @package Grav\Framework\Object\Access
*/
trait OverloadedPropertyTrait
{
/**
* Checks 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 __isset($offset)
{
return $this->hasProperty($offset);
}
/**
* Returns the value at specified offset.
*
* @param mixed $offset The offset to retrieve.
* @return mixed Can return all value types.
*/
public function __get($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 __set($offset, $value)
{
$this->setProperty($offset, $value);
}
/**
* Magic method to unset the attribute
*
* @param mixed $offset The name value to unset
*/
public function __unset($offset)
{
$this->unsetProperty($offset);
}
abstract public function hasProperty($property);
abstract public function getProperty($property, $default = null);
abstract public function setProperty($property, $value);
abstract public function unsetProperty($property);
}

View File

@ -8,62 +8,19 @@
namespace Grav\Framework\Object;
use Grav\Framework\Object\Access\NestedPropertyTrait;
use Grav\Framework\Object\Access\OverloadedPropertyTrait;
use Grav\Framework\Object\Base\ObjectTrait;
use Grav\Framework\Object\Interfaces\NestedObjectInterface;
use Grav\Framework\Object\Property\ArrayPropertyTrait;
use RocketTheme\Toolbox\ArrayTraits\NestedArrayAccess;
/**
* ArrayObject class.
* Array Object class.
*
* @package Grav\Framework\Object
*/
class ArrayObject extends Object implements \ArrayAccess
class ArrayObject implements NestedObjectInterface, \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);
}
}
use ObjectTrait, ArrayPropertyTrait, NestedPropertyTrait, OverloadedPropertyTrait, NestedArrayAccess;
}

View File

@ -6,7 +6,9 @@
* @license MIT License; see LICENSE file for details.
*/
namespace Grav\Framework\Object;
namespace Grav\Framework\Object\Base;
use Grav\Framework\Object\Interfaces\ObjectInterface;
/**
* ObjectCollection Trait
@ -14,7 +16,9 @@ namespace Grav\Framework\Object;
*/
trait ObjectCollectionTrait
{
use ObjectTrait;
use ObjectTrait {
setKey as public;
}
/**
* Create a copy from this collection by cloning all objects in the collection.
@ -44,12 +48,28 @@ trait ObjectCollectionTrait
return $this->call('getKey');
}
/**
* @param string $property Object property to be matched.
* @return array Key/Value pairs of the properties.
*/
public function doHasProperty($property)
{
$list = [];
/** @var ObjectInterface $element */
foreach ($this->getIterator() as $id => $element) {
$list[$id] = $element->hasProperty($property);
}
return $list;
}
/**
* @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, $default = null)
public function doGetProperty($property, $default = null)
{
$list = [];
@ -66,7 +86,7 @@ trait ObjectCollectionTrait
* @param string $value New value.
* @return $this
*/
public function setProperty($property, $value)
public function doSetProperty($property, $value)
{
/** @var ObjectInterface $element */
foreach ($this->getIterator() as $element) {
@ -78,14 +98,28 @@ trait ObjectCollectionTrait
/**
* @param string $property Object property to be updated.
* @param string $value New value.
* @return $this
*/
public function defProperty($property, $value)
public function doUnsetProperty($property)
{
/** @var ObjectInterface $element */
foreach ($this->getIterator() as $element) {
$element->defProperty($property, $value);
$element->unsetProperty($property);
}
return $this;
}
/**
* @param string $property Object property to be updated.
* @param string $default Default value.
* @return $this
*/
public function doDefProperty($property, $default)
{
/** @var ObjectInterface $element */
foreach ($this->getIterator() as $element) {
$element->defProperty($property, $default);
}
return $this;

View File

@ -0,0 +1,167 @@
<?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\Base;
/**
* Object trait.
*
* @package Grav\Framework\Object
*/
trait ObjectTrait
{
static protected $prefix;
static protected $type;
/**
* @var string
*/
private $_key;
/**
* @param bool $prefix
* @return string
*/
public function getType($prefix = true)
{
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
*/
public function getKey()
{
return $this->_key ?: $this->getType() . '@' . spl_object_hash($this);
}
/**
* @param string $property Object property name.
* @return bool True if property has been defined (can be null).
*/
public function hasProperty($property)
{
return $this->doHasProperty($property);
}
/**
* @param string $property Object property to be fetched.
* @param mixed $default Default value if property has not been set.
* @return mixed Property value.
*/
public function getProperty($property, $default = null)
{
return $this->doGetProperty($property, $default);
}
/**
* @param string $property Object property to be updated.
* @param string $value New value.
* @return $this
*/
public function setProperty($property, $value)
{
$this->doSetProperty($property, $value);
return $this;
}
/**
* @param string $property Object property to be unset.
* @return $this
*/
public function unsetProperty($property)
{
$this->doUnsetProperty($property);
return $this;
}
/**
* @param string $property Object property to be defined.
* @param mixed $default Default value.
* @return $this
*/
public function defProperty($property, $default)
{
if (!$this->hasProperty($property)) {
$this->setProperty($property, $default);
}
return $this;
}
/**
* Implements Serializable interface.
*
* @return string
*/
public function serialize()
{
return serialize($this->jsonSerialize());
}
/**
* @param string $serialized
*/
public function unserialize($serialized)
{
$data = unserialize($serialized);
$this->doUnserialize($data);
}
/**
* @param array $serialized
*/
protected function doUnserialize(array $serialized)
{
$this->setKey($serialized['key']);
$this->setElements($serialized['elements']);
}
/**
* Implements JsonSerializable interface.
*
* @return array
*/
public function jsonSerialize()
{
return ['key' => $this->getKey(), 'type' => $this->getType(), 'elements' => $this->getElements()];
}
/**
* Returns a string representation of this object.
*
* @return string
*/
public function __toString()
{
return $this->getKey();
}
/**
* @param string $key
*/
protected function setKey($key)
{
$this->_key = (string) $key;
}
abstract protected function doHasProperty($property);
abstract protected function &doGetProperty($property, $default = null, $doCreate = false);
abstract protected function doSetProperty($property, $value);
abstract protected function doUnsetProperty($property);
abstract protected function getElements();
abstract protected function setElements(array $elements);
}

View File

@ -0,0 +1,57 @@
<?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\Interfaces;
/**
* Object Interface
* @package Grav\Framework\Object
*/
interface NestedObjectInterface extends ObjectInterface
{
/**
* @param string $property Object property name.
* @param string $separator Separator, defaults to '.'
* @return bool True if property has been defined (can be null).
*/
public function hasNestedProperty($property, $separator = null);
/**
* @param string $property Object property to be fetched.
* @param mixed $default Default value if property has not been set.
* @param string $separator Separator, defaults to '.'
* @return mixed Property value.
*/
public function getNestedProperty($property, $default = null, $separator = null);
/**
* @param string $property Object property to be updated.
* @param string $value New value.
* @param string $separator Separator, defaults to '.'
* @return $this
* @throws \RuntimeException
*/
public function setNestedProperty($property, $value, $separator = null);
/**
* @param string $property Object property to be defined.
* @param string $default Default value.
* @param string $separator Separator, defaults to '.'
* @return $this
* @throws \RuntimeException
*/
public function defNestedProperty($property, $default, $separator = null);
/**
* @param string $property Object property to be unset.
* @param string $separator Separator, defaults to '.'
* @return $this
* @throws \RuntimeException
*/
public function unsetNestedProperty($property, $separator = null);
}

View File

@ -6,7 +6,7 @@
* @license MIT License; see LICENSE file for details.
*/
namespace Grav\Framework\Object;
namespace Grav\Framework\Object\Interfaces;
use Grav\Framework\Collection\CollectionInterface;

View File

@ -6,13 +6,13 @@
* @license MIT License; see LICENSE file for details.
*/
namespace Grav\Framework\Object;
namespace Grav\Framework\Object\Interfaces;
/**
* Object Interface
* @package Grav\Framework\Object
*/
interface ObjectInterface extends \JsonSerializable
interface ObjectInterface extends \Serializable, \JsonSerializable
{
/**
* @param array $elements
@ -30,9 +30,15 @@ interface ObjectInterface extends \JsonSerializable
*/
public function getKey();
/**
* @param string $property Object property name.
* @return bool True if property has been defined (can be null).
*/
public function hasProperty($property);
/**
* @param string $property Object property to be fetched.
* @param mixed $default Default value if not set.
* @param mixed $default Default value if property has not been set.
* @return mixed Property value.
*/
public function getProperty($property, $default = null);
@ -46,8 +52,14 @@ interface ObjectInterface extends \JsonSerializable
/**
* @param string $property Object property to be defined.
* @param mixed $value Default value.
* @param mixed $default Default value.
* @return $this
*/
public function defProperty($property, $value);
public function defProperty($property, $default);
/**
* @param string $property Object property to be unset.
* @return $this
*/
public function unsetProperty($property);
}

View File

@ -0,0 +1,26 @@
<?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;
use Grav\Framework\Object\Access\NestedPropertyTrait;
use Grav\Framework\Object\Access\OverloadedPropertyTrait;
use Grav\Framework\Object\Base\ObjectTrait;
use Grav\Framework\Object\Interfaces\NestedObjectInterface;
use Grav\Framework\Object\Property\LazyPropertyTrait;
use RocketTheme\Toolbox\ArrayTraits\NestedArrayAccess;
/**
* Lazy Object class.
*
* @package Grav\Framework\Object
*/
class LazyObject implements NestedObjectInterface, \ArrayAccess
{
use ObjectTrait, LazyPropertyTrait, NestedPropertyTrait, OverloadedPropertyTrait, NestedArrayAccess;
}

View File

@ -1,235 +0,0 @@
<?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 Object implements ObjectInterface
{
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 $property 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($property, $default = null, $separator = '.')
{
$path = explode($separator, $property);
$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 $property Dot separated path to the requested value.
* @param mixed $value New value.
* @param string $separator Separator, defaults to '.'
* @return $this
*/
public function setProperty($property, $value, $separator = '.')
{
$path = explode($separator, $property);
$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 $property Dot separated path to the requested value.
* @param mixed $value New value.
* @param string $separator Separator, defaults to '.'
* @return $this
*/
public function defProperty($property, $value, $separator = '.')
{
$test = new \stdClass;
if ($this->getProperty($property, $test, $separator) === $test) {
$this->setProperty($property, $value, $separator);
}
return $this;
}
/**
* Checks whether or not an offset exists with a possibility to load the field by $this->offsetLoad_{$offset}().
*
* @param mixed $offset An offset to check for.
* @return bool Returns TRUE on success or FALSE on failure.
*/
public function __isset($offset)
{
return array_key_exists($offset, $this->items) || $this->isPropertyDefined($offset);
}
/**
* Returns the value at specified offset with a possibility to load the field by $this->offsetLoad_{$offset}().
*
* @param mixed $offset The offset to retrieve.
* @return mixed Can return all value types.
*/
public function __get($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}().
*
* @param mixed $offset The offset to assign the value to.
* @param mixed $value The value to set.
*/
public function __set($offset, $value)
{
if ($this->isPropertyDefined($offset)) {
$methodName = "offsetPrepare_{$offset}";
if (method_exists($this, $methodName)) {
$this->{$offset} = $this->{$methodName}($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;
}
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));
}
}

View File

@ -9,16 +9,20 @@
namespace Grav\Framework\Object;
use Grav\Framework\Collection\ArrayCollection;
use Grav\Framework\Object\Access\NestedPropertyCollectionTrait;
use Grav\Framework\Object\Base\ObjectCollectionTrait;
use Grav\Framework\Object\Interfaces\NestedObjectInterface;
use Grav\Framework\Object\Interfaces\ObjectCollectionInterface;
/**
* Object Collection
* @package Grav\Framework\Object
*/
class ObjectCollection extends ArrayCollection implements ObjectCollectionInterface
class ObjectCollection extends ArrayCollection implements ObjectCollectionInterface, NestedObjectInterface
{
use ObjectCollectionTrait;
static protected $prefix = 'c.';
use ObjectCollectionTrait, NestedPropertyCollectionTrait {
NestedPropertyCollectionTrait::group insteadof ObjectCollectionTrait;
}
/**
* @param array $elements
@ -27,23 +31,18 @@ class ObjectCollection extends ArrayCollection implements ObjectCollectionInterf
*/
public function __construct(array $elements = [], $key = null)
{
parent::__construct($elements);
parent::__construct($this->setElements($elements));
$this->key = $key !== null ? $key : (string) $this;
if ($this->key === null) {
throw new \InvalidArgumentException('Object cannot be created without assigning a key to it');
}
$this->setKey($key);
}
/**
* @param string $key
* @return $this
*/
public function setKey($key)
protected function getElements()
{
$this->key = $key;
return $this->toArray();
}
return $this;
protected function setElements(array $elements)
{
return $elements;
}
}

View File

@ -1,86 +0,0 @@
<?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 trait.
*
* @package Grav\Framework\Object
*/
trait ObjectTrait
{
/**
* Properties of the object.
* @var array
*/
protected $items;
/**
* @var string
*/
private $key;
/**
* @param array $elements
* @param string $key
* @throws \InvalidArgumentException
*/
public function __construct(array $elements = [], $key = null)
{
$this->items = $elements;
$this->key = $key !== null ? $key : (string) $this;
if ($this->key === null) {
throw new \InvalidArgumentException('Object cannot be created without assigning a key to it');
}
}
/**
* @param bool $prefix
* @return string
*/
public function getType($prefix = true)
{
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
*/
public function getKey()
{
return $this->key;
}
/**
* Implements JsonSerializable interface.
*
* @return array
*/
public function jsonSerialize()
{
return ['key' => (string) $this, 'type' => $this->getType(), 'elements' => $this->toArray()];
}
/**
* Returns a string representation of this object.
*
* @return string
*/
public function __toString()
{
return $this->getKey() ?: $this->getType() . '@' . spl_object_hash($this);
}
}

View File

@ -0,0 +1,96 @@
<?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\Property;
/**
* Array Property Trait
* @package Grav\Framework\Object\Property
*/
trait ArrayPropertyTrait
{
/**
* Properties of the object.
* @var array
*/
private $_elements;
/**
* @param array $elements
* @param string $key
* @throws \InvalidArgumentException
*/
public function __construct(array $elements = [], $key = null)
{
$this->setElements($elements);
$this->setKey($key);
}
/**
* @param string $property Object property name.
* @return bool True if property has been defined (can be null).
*/
protected function doHasProperty($property)
{
return array_key_exists($property, $this->_elements);
}
/**
* @param string $property Object property to be fetched.
* @param mixed $default Default value if property has not been set.
* @param bool $doCreate Set true to create variable.
* @return mixed Property value.
*/
protected function &doGetProperty($property, $default = null, $doCreate = false)
{
if (!$this->doHasProperty($property)) {
if ($doCreate) {
$this->_elements[$property] = null;
} else {
return $default;
}
}
return $this->_elements[$property];
}
/**
* @param string $property Object property to be updated.
* @param string $value New value.
*/
protected function doSetProperty($property, $value)
{
$this->_elements[$property] = $value;
}
/**
* @param string $property Object property to be unset.
*/
protected function doUnsetProperty($property)
{
unset($this->_elements[$property]);
}
/**
* @return array
*/
protected function getElements()
{
return $this->_elements;
}
/**
* @param array $elements
*/
protected function setElements(array $elements)
{
$this->_elements = $elements;
}
abstract protected function setKey($key);
}

View File

@ -0,0 +1,92 @@
<?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\Property;
/**
* Lazy Mixed Property Trait
* @package Grav\Framework\Object\Property
*/
trait LazyPropertyTrait
{
use ArrayPropertyTrait, ObjectPropertyTrait {
ObjectPropertyTrait::__construct insteadof ArrayPropertyTrait;
ArrayPropertyTrait::doHasProperty as hasArrayProperty;
ArrayPropertyTrait::doGetProperty as getArrayProperty;
ArrayPropertyTrait::doSetProperty as setArrayProperty;
ArrayPropertyTrait::doUnsetProperty as unsetArrayProperty;
ArrayPropertyTrait::getElements as getArrayElements;
ArrayPropertyTrait::setElements insteadof ObjectPropertyTrait;
ObjectPropertyTrait::doHasProperty as hasObjectProperty;
ObjectPropertyTrait::doGetProperty as getObjectProperty;
ObjectPropertyTrait::doSetProperty as setObjectProperty;
ObjectPropertyTrait::doUnsetProperty as unsetObjectProperty;
ObjectPropertyTrait::getElements as getObjectElements;
}
/**
* @param string $property Object property name.
* @return bool True if property has been defined (can be null).
*/
protected function doHasProperty($property)
{
return $this->hasArrayProperty($property) || $this->hasObjectProperty($property);
}
/**
* @param string $property Object property to be fetched.
* @param mixed $default Default value if property has not been set.
* @return mixed Property value.
*/
protected function &doGetProperty($property, $default = null, $doCreate = false)
{
if ($this->hasObjectProperty($property)) {
return $this->getObjectProperty($property, $default, function ($default = null) use ($property) {
return $this->getArrayProperty($property, $default);
});
}
return $this->getArrayProperty($property, $default, $doCreate);
}
/**
* @param string $property Object property to be updated.
* @param string $value New value.
* @return $this
*/
protected function doSetProperty($property, $value)
{
if ($this->hasObjectProperty($property)) {
$this->setObjectProperty($property, $value);
} else {
$this->setArrayProperty($property, $value);
}
return $this;
}
/**
* @param string $property Object property to be unset.
* @return $this
*/
protected function doUnsetProperty($property)
{
$this->hasObjectProperty($property) ?
$this->unsetObjectProperty($property) : $this->unsetArrayProperty($property);
return $this;
}
/**
* @return array
*/
protected function getElements()
{
return $this->getObjectElements() + $this->getArrayElements();
}
}

View File

@ -0,0 +1,97 @@
<?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\Property;
/**
* Mixed Property Trait
* @package Grav\Framework\Object\Property
*/
trait MixedPropertyTrait
{
use ArrayPropertyTrait, ObjectPropertyTrait {
ObjectPropertyTrait::__construct insteadof ArrayPropertyTrait;
ArrayPropertyTrait::doHasProperty as hasArrayProperty;
ArrayPropertyTrait::doGetProperty as getArrayProperty;
ArrayPropertyTrait::doSetProperty as setArrayProperty;
ArrayPropertyTrait::doUnsetProperty as unsetArrayProperty;
ArrayPropertyTrait::getElements as getArrayElements;
ArrayPropertyTrait::setElements as setArrayElements;
ObjectPropertyTrait::doHasProperty as hasObjectProperty;
ObjectPropertyTrait::doGetProperty as getObjectProperty;
ObjectPropertyTrait::doSetProperty as setObjectProperty;
ObjectPropertyTrait::doUnsetProperty as unsetObjectProperty;
ObjectPropertyTrait::getElements as getObjectElements;
ObjectPropertyTrait::setElements as setObjectElements;
}
/**
* @param string $property Object property name.
* @return bool True if property has been defined (can be null).
*/
protected function doHasProperty($property)
{
return $this->hasArrayProperty($property) || $this->hasObjectProperty($property);
}
/**
* @param string $property Object property to be fetched.
* @param mixed $default Default value if property has not been set.
* @return mixed Property value.
*/
protected function &doGetProperty($property, $default = null, $doCreate = false)
{
if ($this->hasObjectProperty($property)) {
return $this->getObjectProperty($property);
}
return $this->getArrayProperty($property, $default, $doCreate);
}
/**
* @param string $property Object property to be updated.
* @param string $value New value.
* @return $this
*/
protected function doSetProperty($property, $value)
{
$this->hasObjectProperty($property)
? $this->setObjectProperty($property, $value) : $this->setArrayProperty($property, $value);
return $this;
}
/**
* @param string $property Object property to be unset.
* @return $this
*/
protected function doUnsetProperty($property)
{
$this->hasObjectProperty($property) ?
$this->unsetObjectProperty($property) : $this->unsetArrayProperty($property);
return $this;
}
/**
* @return array
*/
protected function getElements()
{
return $this->getObjectElements() + $this->getArrayElements();
}
/**
* @param array $elements
*/
protected function setElements(array $elements)
{
$this->setObjectElements(array_intersect_key($elements, $this->_definedProperties));
$this->setArrayElements(array_diff_key($elements, $this->_definedProperties));
}
}

View File

@ -0,0 +1,151 @@
<?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\Property;
/**
* Object Property Trait
* @package Grav\Framework\Object\Property
*/
trait ObjectPropertyTrait
{
/**
* @var array
*/
private $_definedProperties;
/**
* @param array $elements
* @param string $key
* @throws \InvalidArgumentException
*/
public function __construct(array $elements = [], $key = null)
{
$this->initObjectProperties();
$this->setElements($elements);
$this->setKey($key);
}
/**
* @param string $property Object property name.
* @return bool True if property has been defined (can be null).
*/
protected function doHasProperty($property)
{
return array_key_exists($property, $this->_definedProperties);
}
/**
* @param string $property Object property to be fetched.
* @param mixed $default Default value if property has not been set.
* @param bool $doCreate Set true to create variable.
* @return mixed Property value.
*/
protected function &doGetProperty($property, $default = null, $doCreate = false)
{
if (!array_key_exists($property, $this->_definedProperties)) {
throw new \InvalidArgumentException("Property '{$property}' does not exist in the object!");
}
if (empty($this->_definedProperties[$property])) {
if ($doCreate === true) {
$this->_definedProperties[$property] = true;
$this->{$property} = null;
} elseif (is_callable($doCreate)) {
$this->_definedProperties[$property] = true;
$this->{$property} = $this->onPropertyLoad($property, $doCreate());
} else {
return $default;
}
}
return $this->{$property};
}
/**
* @param string $property Object property to be updated.
* @param string $value New value.
* @throws \InvalidArgumentException
*/
protected function doSetProperty($property, $value)
{
if (!array_key_exists($property, $this->_definedProperties)) {
throw new \InvalidArgumentException("Property '{$property}' does not exist in the object!");
}
$this->_definedProperties[$property] = true;
$this->{$property} = $this->onPropertySet($property, $value);
}
/**
* @param string $property Object property to be unset.
*/
protected function doUnsetProperty($property)
{
if (!array_key_exists($property, $this->_definedProperties)) {
return;
}
$this->_definedProperties[$property] = false;
unset($this->{$property});
}
protected function onPropertyLoad($offset, $value)
{
$methodName = "offsetLoad_{$offset}";
if (method_exists($this, $methodName)) {
return $this->{$methodName}($value);
}
return $value;
}
protected function onPropertySet($offset, $value)
{
$methodName = "offsetPrepare_{$offset}";
if (method_exists($this, $methodName)) {
return $this->{$methodName}($value);
}
return $value;
}
protected function initObjectProperties()
{
$this->_definedProperties = [];
foreach (get_object_vars($this) as $property => $value) {
if ($property[0] !== '_') {
$this->_definedProperties[$property] = ($value !== null);
}
}
}
/**
* @return array
*/
protected function getElements()
{
return array_intersect_key(get_object_vars($this), array_filter($this->_definedProperties));
}
/**
* @param array $elements
*/
protected function setElements(array $elements)
{
foreach ($elements as $property => $value) {
$this->setProperty($property, $value);
}
}
abstract public function setProperty($property, $value);
abstract protected function setKey($key);
}

View File

@ -0,0 +1,26 @@
<?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;
use Grav\Framework\Object\Access\NestedPropertyTrait;
use Grav\Framework\Object\Access\OverloadedPropertyTrait;
use Grav\Framework\Object\Base\ObjectTrait;
use Grav\Framework\Object\Interfaces\NestedObjectInterface;
use Grav\Framework\Object\Property\ObjectPropertyTrait;
use RocketTheme\Toolbox\ArrayTraits\NestedArrayAccess;
/**
* Property Object class.
*
* @package Grav\Framework\Object
*/
class PropertyObject implements NestedObjectInterface, \ArrayAccess
{
use ObjectTrait, ObjectPropertyTrait, NestedPropertyTrait, OverloadedPropertyTrait, NestedArrayAccess;
}