first commit

This commit is contained in:
2018-08-01 16:00:05 +02:00
commit 944fd76206
3205 changed files with 356767 additions and 0 deletions
@@ -0,0 +1,64 @@
<?php
/**
* @package Grav\Framework\Object
*
* @copyright Copyright (C) 2015 - 2018 Trilby Media, 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);
}
@@ -0,0 +1,64 @@
<?php
/**
* @package Grav\Framework\Object
*
* @copyright Copyright (C) 2015 - 2018 Trilby Media, 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);
}
@@ -0,0 +1,124 @@
<?php
/**
* @package Grav\Framework\Object
*
* @copyright Copyright (C) 2015 - 2018 Trilby Media, 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();
}
@@ -0,0 +1,182 @@
<?php
/**
* @package Grav\Framework\Object
*
* @copyright Copyright (C) 2015 - 2018 Trilby Media, 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)
{
$separator = $separator ?: '.';
$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)
{
$separator = $separator ?: '.';
$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)
{
$separator = $separator ?: '.';
$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);
}
@@ -0,0 +1,64 @@
<?php
/**
* @package Grav\Framework\Object
*
* @copyright Copyright (C) 2015 - 2018 Trilby Media, 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);
}
@@ -0,0 +1,26 @@
<?php
/**
* @package Grav\Framework\Object
*
* @copyright Copyright (C) 2015 - 2018 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
namespace Grav\Framework\Object;
use Grav\Framework\Object\Access\NestedArrayAccessTrait;
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;
/**
* Array Object class.
*
* @package Grav\Framework\Object
*/
class ArrayObject implements NestedObjectInterface, \ArrayAccess
{
use ObjectTrait, ArrayPropertyTrait, NestedPropertyTrait, OverloadedPropertyTrait, NestedArrayAccessTrait;
}
@@ -0,0 +1,190 @@
<?php
/**
* @package Grav\Framework\Object
*
* @copyright Copyright (C) 2015 - 2018 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
namespace Grav\Framework\Object\Base;
use Grav\Framework\Object\Interfaces\ObjectInterface;
/**
* ObjectCollection Trait
* @package Grav\Framework\Object
*/
trait ObjectCollectionTrait
{
use ObjectTrait {
setKey as public;
}
/**
* Create a copy from this collection by cloning all objects in the collection.
*
* @return static
*/
public function copy()
{
$list = [];
foreach ($this->getIterator() as $key => $value) {
$list[$key] = is_object($value) ? clone $value : $value;
}
// TODO: remove when PHP 5.6 is minimum (with doctrine/collections v1.4).
if (!method_exists($this, 'createFrom')) {
return new static($list);
}
return $this->createFrom($list);
}
/**
* @return array
*/
public function getObjectKeys()
{
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 doGetProperty($property, $default = null)
{
$list = [];
/** @var ObjectInterface $element */
foreach ($this->getIterator() as $id => $element) {
$list[$id] = $element->getProperty($property, $default);
}
return $list;
}
/**
* @param string $property Object property to be updated.
* @param string $value New value.
* @return $this
*/
public function doSetProperty($property, $value)
{
/** @var ObjectInterface $element */
foreach ($this->getIterator() as $element) {
$element->setProperty($property, $value);
}
return $this;
}
/**
* @param string $property Object property to be updated.
* @return $this
*/
public function doUnsetProperty($property)
{
/** @var ObjectInterface $element */
foreach ($this->getIterator() as $element) {
$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;
}
/**
* @param string $method Method name.
* @param array $arguments List of arguments passed to the function.
* @return array Return values.
*/
public function call($method, array $arguments = [])
{
$list = [];
foreach ($this->getIterator() as $id => $element) {
$list[$id] = method_exists($element, $method)
? call_user_func_array([$element, $method], $arguments) : null;
}
return $list;
}
/**
* Group items in the collection by a field and return them as associated array.
*
* @param string $property
* @return array
*/
public function group($property)
{
$list = [];
/** @var ObjectInterface $element */
foreach ($this->getIterator() as $element) {
$list[(string) $element->getProperty($property)][] = $element;
}
return $list;
}
/**
* Group items in the collection by a field and return them as associated array of collections.
*
* @param string $property
* @return static[]
*/
public function collectionGroup($property)
{
$collections = [];
foreach ($this->group($property) as $id => $elements) {
// TODO: remove when PHP 5.6 is minimum (with doctrine/collections v1.4).
if (!method_exists($this, 'createFrom')) {
$collection = new static($elements);
} else {
$collection = $this->createFrom($elements);
}
$collections[$id] = $collection;
}
return $collections;
}
/**
* @return \Traversable
*/
abstract public function getIterator();
}
@@ -0,0 +1,174 @@
<?php
/**
* @package Grav\Framework\Object
*
* @copyright Copyright (C) 2015 - 2018 Trilby Media, 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);
if (method_exists($this, 'initObjectProperties')) {
$this->initObjectProperties();
}
$this->doUnserialize($data);
}
/**
* @param array $serialized
*/
protected function doUnserialize(array $serialized)
{
if (!isset($serialized['key'], $serialized['type'], $serialized['elements']) || $serialized['type'] !== $this->getType()) {
throw new \InvalidArgumentException("Cannot unserialize '{$this->getType()}': Bad data");
}
$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);
}
@@ -0,0 +1,57 @@
<?php
/**
* @package Grav\Framework\Object
*
* @copyright Copyright (C) 2015 - 2018 Trilby Media, 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);
}
@@ -0,0 +1,66 @@
<?php
/**
* @package Grav\Framework\Object
*
* @copyright Copyright (C) 2015 - 2018 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
namespace Grav\Framework\Object\Interfaces;
use Grav\Framework\Collection\CollectionInterface;
/**
* ObjectCollection Interface
* @package Grav\Framework\Collection
*/
interface ObjectCollectionInterface extends CollectionInterface, ObjectInterface
{
/**
* Create a copy from this collection by cloning all objects in the collection.
*
* @return static
*/
public function copy();
/**
* @param string $key
* @return $this
*/
public function setKey($key);
/**
* @return array
*/
public function getObjectKeys();
/**
* @param string $property Object property to be fetched.
* @param mixed $default Default value if not set.
* @return array Property value.
*/
public function getProperty($property, $default = null);
/**
* @param string $name Method name.
* @param array $arguments List of arguments passed to the function.
* @return array Return values.
*/
public function call($name, array $arguments);
/**
* Group items in the collection by a field and return them as associated array.
*
* @param string $property
* @return array
*/
public function group($property);
/**
* Group items in the collection by a field and return them as associated array of collections.
*
* @param string $property
* @return static[]
*/
public function collectionGroup($property);
}
@@ -0,0 +1,59 @@
<?php
/**
* @package Grav\Framework\Object
*
* @copyright Copyright (C) 2015 - 2018 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
namespace Grav\Framework\Object\Interfaces;
/**
* Object Interface
* @package Grav\Framework\Object
*/
interface ObjectInterface extends \Serializable, \JsonSerializable
{
/**
* @return string
*/
public function getType();
/**
* @return string
*/
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 property has not been set.
* @return mixed Property value.
*/
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);
/**
* @param string $property Object property to be defined.
* @param mixed $default Default value.
* @return $this
*/
public function defProperty($property, $default);
/**
* @param string $property Object property to be unset.
* @return $this
*/
public function unsetProperty($property);
}
@@ -0,0 +1,26 @@
<?php
/**
* @package Grav\Framework\Object
*
* @copyright Copyright (C) 2015 - 2018 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
namespace Grav\Framework\Object;
use Grav\Framework\Object\Access\NestedArrayAccessTrait;
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;
/**
* Lazy Object class.
*
* @package Grav\Framework\Object
*/
class LazyObject implements NestedObjectInterface, \ArrayAccess
{
use ObjectTrait, LazyPropertyTrait, NestedPropertyTrait, OverloadedPropertyTrait, NestedArrayAccessTrait;
}
@@ -0,0 +1,48 @@
<?php
/**
* @package Grav\Framework\Object
*
* @copyright Copyright (C) 2015 - 2018 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
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, NestedObjectInterface
{
use ObjectCollectionTrait, NestedPropertyCollectionTrait {
NestedPropertyCollectionTrait::group insteadof ObjectCollectionTrait;
}
/**
* @param array $elements
* @param string $key
* @throws \InvalidArgumentException
*/
public function __construct(array $elements = [], $key = null)
{
parent::__construct($this->setElements($elements));
$this->setKey($key);
}
protected function getElements()
{
return $this->toArray();
}
protected function setElements(array $elements)
{
return $elements;
}
}
@@ -0,0 +1,109 @@
<?php
/**
* @package Grav\Framework\Object
*
* @copyright Copyright (C) 2015 - 2018 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
namespace Grav\Framework\Object\Property;
/**
* Array Property Trait
*
* Stores all object properties into an array.
*
* @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 (!array_key_exists($property, $this->_elements)) {
if ($doCreate) {
$this->_elements[$property] = null;
} else {
return $default;
}
}
return $this->_elements[$property];
}
/**
* @param string $property Object property to be updated.
* @param mixed $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]);
}
/**
* @param string $property
* @param mixed|null $default
* @return mixed|null
*/
protected function getElement($property, $default = null)
{
return array_key_exists($property, $this->_elements) ? $this->_elements[$property] : $default;
}
/**
* @return array
*/
protected function getElements()
{
return $this->_elements;
}
/**
* @param array $elements
*/
protected function setElements(array $elements)
{
$this->_elements = $elements;
}
abstract protected function setKey($key);
}
@@ -0,0 +1,117 @@
<?php
/**
* @package Grav\Framework\Object
*
* @copyright Copyright (C) 2015 - 2018 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
namespace Grav\Framework\Object\Property;
/**
* Lazy Mixed Property Trait
*
* Stores defined object properties as class member variables and the rest into an array. Object properties are lazy
* loaded from the array.
*
* You may define following methods for the member variables:
* - `$this->offsetLoad($offset, $value)` called first time object property gets accessed
* - `$this->offsetPrepare($offset, $value)` called on every object property set
* - `$this->offsetSerialize($offset, $value)` called when the raw or serialized object property value is needed
*
* @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::getElement as getArrayElement;
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::getElement as getObjectElement;
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 mixed $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;
}
/**
* @param string $property
* @param mixed|null $default
* @return mixed|null
*/
protected function getElement($property, $default = null)
{
if ($this->isPropertyLoaded($property)) {
return $this->getObjectElement($property, $default);
}
return $this->getArrayElement($property, $default);
}
/**
* @return array
*/
protected function getElements()
{
return $this->getObjectElements() + $this->getArrayElements();
}
}
@@ -0,0 +1,122 @@
<?php
/**
* @package Grav\Framework\Object
*
* @copyright Copyright (C) 2015 - 2018 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
namespace Grav\Framework\Object\Property;
/**
* Mixed Property Trait
*
* Stores defined object properties as class member variables and the rest into an array.
*
* You may define following methods for member variables:
* - `$this->offsetLoad($offset, $value)` called first time object property gets accessed
* - `$this->offsetPrepare($offset, $value)` called on every object property set
* - `$this->offsetSerialize($offset, $value)` called when the raw or serialized object property value is needed
*
* @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::getElement as getArrayElement;
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::getElement as getObjectElement;
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 mixed $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;
}
/**
* @param string $property
* @param mixed|null $default
* @return mixed|null
*/
protected function getElement($property, $default = null)
{
if ($this->hasObjectProperty($property)) {
return $this->getObjectElement($property, $default);
}
return $this->getArrayElement($property, $default);
}
/**
* @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));
}
}
@@ -0,0 +1,203 @@
<?php
/**
* @package Grav\Framework\Object
*
* @copyright Copyright (C) 2015 - 2018 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
namespace Grav\Framework\Object\Property;
/**
* Object Property Trait
*
* Stores all properties as class member variables or object properties. All properties need to be defined as protected
* properties. Undefined properties will throw an error.
*
* Additionally you may define following methods:
* - `$this->offsetLoad($offset, $value)` called first time object property gets accessed
* - `$this->offsetPrepare($offset, $value)` called on every object property set
* - `$this->offsetSerialize($offset, $value)` called when the raw or serialized object property value is needed
*
* @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 loaded.
*/
protected function isPropertyLoaded($property)
{
return !empty($this->_definedProperties[$property]);
}
/**
* @param string $offset
* @param mixed $value
* @return mixed
*/
protected function offsetLoad($offset, $value)
{
$methodName = "offsetLoad_{$offset}";
return method_exists($this, $methodName)? $this->{$methodName}($value) : $value;
}
/**
* @param string $offset
* @param mixed $value
* @return mixed
*/
protected function offsetPrepare($offset, $value)
{
$methodName = "offsetPrepare_{$offset}";
return method_exists($this, $methodName) ? $this->{$methodName}($value) : $value;
}
/**
* @param string $offset
* @param mixed $value
* @return mixed
*/
protected function offsetSerialize($offset, $value)
{
$methodName = "offsetSerialize_{$offset}";
return method_exists($this, $methodName) ? $this->{$methodName}($value) : $value;
}
/**
* @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->offsetLoad($property, $doCreate());
} else {
return $default;
}
}
return $this->{$property};
}
/**
* @param string $property Object property to be updated.
* @param mixed $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->offsetPrepare($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 initObjectProperties()
{
$this->_definedProperties = [];
foreach (get_object_vars($this) as $property => $value) {
if ($property[0] !== '_') {
$this->_definedProperties[$property] = ($value !== null);
}
}
}
/**
* @param string $property
* @param mixed|null $default
* @return mixed|null
*/
protected function getElement($property, $default = null)
{
if (empty($this->_definedProperties[$property])) {
return $default;
}
return $this->offsetSerialize($property, $this->{$property});
}
/**
* @return array
*/
protected function getElements()
{
$properties = array_intersect_key(get_object_vars($this), array_filter($this->_definedProperties));
$elements = [];
foreach ($properties as $offset => $value) {
$elements[$offset] = $this->offsetSerialize($offset, $value);
}
return $elements;
}
/**
* @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);
}
@@ -0,0 +1,26 @@
<?php
/**
* @package Grav\Framework\Object
*
* @copyright Copyright (C) 2015 - 2018 Trilby Media, LLC. All rights reserved.
* @license MIT License; see LICENSE file for details.
*/
namespace Grav\Framework\Object;
use Grav\Framework\Object\Access\NestedArrayAccessTrait;
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;
/**
* Property Object class.
*
* @package Grav\Framework\Object
*/
class PropertyObject implements NestedObjectInterface, \ArrayAccess
{
use ObjectTrait, ObjectPropertyTrait, NestedPropertyTrait, OverloadedPropertyTrait, NestedArrayAccessTrait;
}