ZwiiCMS/core/class/jsondb/Dot.class.php

317 lines
7.8 KiB
PHP

<?php
namespace Prowebcraft;
use ArrayAccess;
/**
* Dot Notation
*
* This class provides dot notation access to arrays, so it's easy to handle
* multidimensional data in a clean way.
*/
class Dot implements ArrayAccess
{
/** @var array Data */
protected $data = [];
/**
* Constructor
*
* @param array|null $data Data
*/
public function __construct(array $data = null)
{
if (is_array($data)) {
$this->data = $data;
}
}
/**
* Get value of path, default value if path doesn't exist or all data
*
* @param array $array Source Array
* @param mixed|null $key Path
* @param mixed|null $default Default value
* @return mixed Value of path
*/
public static function getValue($array, $key, $default = null)
{
if (is_string($key)) {
// Iterate path
$keys = explode('.', $key);
foreach ($keys as $key) {
if (!isset($array[$key])) {
return $default;
}
$array = &$array[$key];
}
// Get value
return $array;
} elseif (is_null($key)) {
// Get all data
return $array;
}
return null;
}
/**
* Set value or array of values to path
*
* @param array $array Target array with data
* @param mixed $key Path or array of paths and values
* @param mixed|null $value Value to set if path is not an array
*/
public static function setValue(&$array, $key, $value)
{
if (is_string($key)) {
// Iterate path
$keys = explode('.', $key);
foreach ($keys as $key) {
if (!isset($array[$key]) || !is_array($array[$key])) {
$array[$key] = [];
}
$array = &$array[$key];
}
// Set value to path
$array = $value;
} elseif (is_array($key)) {
// Iterate array of paths and values
foreach ($key as $k => $v) {
self::setValue($array, $k, $v);
}
}
}
/**
* Add value or array of values to path
*
* @param array $array Target array with data
* @param mixed $key Path or array of paths and values
* @param mixed|null $value Value to set if path is not an array
* @param boolean $pop Helper to pop out last key if value is an array
*/
public static function addValue(&$array, $key, $value = null, $pop = false)
{
if (is_string($key)) {
// Iterate path
$keys = explode('.', $key);
if ($pop === true) {
array_pop($keys);
}
foreach ($keys as $key) {
if (!isset($array[$key]) || !is_array($array[$key])) {
$array[$key] = [];
}
$array = &$array[$key];
}
// Add value to path
$array[] = $value;
} elseif (is_array($key)) {
// Iterate array of paths and values
foreach ($key as $k => $v) {
self::addValue($array, $k, $v);
}
}
}
/**
* Delete path or array of paths
*
* @param array $array Target array with data
* @param mixed $key Path or array of paths to delete
*/
public static function deleteValue(&$array, $key)
{
if (is_string($key)) {
// Iterate path
$keys = explode('.', $key);
$last = array_pop($keys);
foreach ($keys as $key) {
if (!isset($array[$key])) {
return;
}
$array = &$array[$key];
}
if (isset($array[$last])) {
// Detele path
unset($array[$last]);
}
} elseif (is_array($key)) {
// Iterate array of paths
foreach ($key as $k) {
self::delete($k);
}
}
}
/**
* Get value of path, default value if path doesn't exist or all data
*
* @param mixed|null $key Path
* @param mixed|null $default Default value
* @return mixed Value of path
*/
public function get($key = null, $default = null)
{
return self::getValue($this->data, $key, $default);
}
/**
* Set value or array of values to path
*
* @param mixed $key Path or array of paths and values
* @param mixed|null $value Value to set if path is not an array
*/
public function set($key, $value = null)
{
return self::setValue($this->data, $key, $value);
}
/**
* Add value or array of values to path
*
* @param mixed $key Path or array of paths and values
* @param mixed|null $value Value to set if path is not an array
* @param boolean $pop Helper to pop out last key if value is an array
*/
public function add($key, $value = null, $pop = false)
{
return self::addValue($this->data, $key, $value, $pop);
}
/**
* Check if path exists
*
* @param string $key Path
* @return boolean
*/
public function has($key)
{
$keys = explode('.', (string)$key);
$data = &$this->data;
foreach ($keys as $key) {
if (!isset($data[$key])) {
return false;
}
$data = &$data[$key];
}
return true;
}
/**
* Delete path or array of paths
*
* @param mixed $key Path or array of paths to delete
*/
public function delete($key)
{
return self::deleteValue($this->data, $key);
}
/**
* Delete all data, data from path or array of paths and
* optionally format path if it doesn't exist
*
* @param mixed|null $key Path or array of paths to clean
* @param boolean $format Format option
*/
public function clear($key = null, $format = false)
{
if (is_string($key)) {
// Iterate path
$keys = explode('.', $key);
$data = &$this->data;
foreach ($keys as $key) {
if (!isset($data[$key]) || !is_array($data[$key])) {
if ($format === true) {
$data[$key] = [];
} else {
return;
}
}
$data = &$data[$key];
}
// Clear path
$data = [];
} elseif (is_array($key)) {
// Iterate array
foreach ($key as $k) {
$this->clear($k, $format);
}
} elseif (is_null($key)) {
// Clear all data
$this->data = [];
}
}
/**
* Set data
*
* @param array $data
*/
public function setData(array $data)
{
$this->data = $data;
}
/**
* Set data as a reference
*
* @param array $data
*/
public function setDataAsRef(array &$data)
{
$this->data = &$data;
}
/**
* ArrayAccess abstract methods
*/
public function offsetSet($offset, $value)
{
$this->set($offset, $value);
}
public function offsetExists($offset)
{
return $this->has($offset);
}
public function offsetGet($offset)
{
return $this->get($offset);
}
public function offsetUnset($offset)
{
$this->delete($offset);
}
/**
* Magic methods
*/
public function __set($key, $value = null)
{
$this->set($key, $value);
}
public function __get($key)
{
return $this->get($key);
}
public function __isset($key)
{
return $this->has($key);
}
public function __unset($key)
{
$this->delete($key);
}
}