Skip to content

Commit

Permalink
Add ArrayObject and make Object not to implement ArrayAccess in…
Browse files Browse the repository at this point in the history
…terface. Remove Toolbox dependency.
  • Loading branch information
mahagr committed Sep 8, 2017
1 parent 758ccad commit 8c32103
Show file tree
Hide file tree
Showing 7 changed files with 316 additions and 38 deletions.
69 changes: 69 additions & 0 deletions system/src/Grav/Framework/Object/ArrayObject.php
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
216 changes: 190 additions & 26 deletions system/src/Grav/Framework/Object/Object.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,133 @@

namespace Grav\Framework\Object;

use RocketTheme\Toolbox\ArrayTraits\Export;
use RocketTheme\Toolbox\ArrayTraits\NestedArrayAccessWithGetters;

/**
* Object class.
*
* @package Grav\Framework\Object
*/
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;
}

/**
Expand All @@ -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);
}

/**
Expand All @@ -43,34 +154,53 @@ public function offsetExists($offset)
* @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}().
*
* @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;
}

/**
Expand All @@ -80,6 +210,40 @@ public function offsetSet($offset, $value)
*/
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));
}
}
8 changes: 7 additions & 1 deletion system/src/Grav/Framework/Object/ObjectCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ class ObjectCollection extends ArrayCollection implements ObjectCollectionInterf
{
use ObjectCollectionTrait;

static protected $prefix = 'c.';

/**
* @param array $elements
* @param string $key
Expand All @@ -27,7 +29,11 @@ public function __construct(array $elements = [], $key = null)
{
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');
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@ public function getObjectKeys();

/**
* @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);

Expand Down
Loading

0 comments on commit 8c32103

Please sign in to comment.