ice framework documentation ice doc v1.10.1
Class Ice

Arr

    
namespace Ice;

use ArrayIterator;

/**
 * Access class as array and the same time as object.
 *
 * @package     Ice/Arr
 * @category    Helper
 * @author      Ice Team
 * @copyright   (c) 2014-2023 Ice Team
 * @license     http://iceframework.org/license
 */
class Arr implements \ArrayAccess, \Countable, \IteratorAggregate
{
    protected data = [] { get };

    /**
     * Arr constructor.
     *
     * @param array data Initial array
     */
    public function __construct(array data = [])
    {
        let this->data = data;
    }

    /**
     * Whether or not a data exists by key.
     *
     * @param string key The data key
     * @return boolean
     */
    public function has(string key) -> boolean
    {
        return isset this->data[key];
    }

    /**
     * Retrieve a single key from an array.
     * If the key does not exist in the array, the default value will be returned.
     *
     * @param string key The data key
     * @param mixed defaultValue The value to return if data key does not exist
     * @return mixed
     */
    public function get(string key, var defaultValue = null)
    {
        var value;

        if fetch value, this->data[key] {
            return value;
        }

        return defaultValue;
    }

    /**
     * Assigns a value to the specified data.
     *
     * @param string key The data key
     * @param mixed value
     * @return object Arr
     */
    public function set(string key, var value)
    {
        let this->data[key] = value;

        return this;
    }

    /**
     * Add data to set, replaces the existing data.
     *
     * @param array data
     * @return Arr
     */
    public function merge(array! data)
    {
        var key, value;

        for key, value in data {
            this->set(key, value);
        }

        return this;
    }

    /**
     * Alias of the `merge` method.
     *
     * @deprecated
     * @see self::merge()
     */
    public function replace(array! data)
    {
        return this->merge(data);
    }

    /**
     * Fetch all data.
     *
     * @return array
     */
    public function all() -> array
    {
        return this->getData();
    }

    /**
     * Fetch some data.
     *
     * @param array keys Keys to fetch
     * @param boolean strict Fetch key only if exist
     * @return array
     */
    public function only(array! keys, boolean strict = true) -> array
    {
        var key, only = [];

        for key in keys {
            if !strict || strict && this->has(key) {
                let only[key] = this->get(key);
            }
        }
        return only;
    }

    /**
     * Gets value from data applying filters if needed.
     *
     * 

     *  //Returns value from $arr["id"] without sanitizing
     *  $id = $arr->getValue("id");
     *
     *  //Returns value from $arr["title"] with sanitizing
     *  $title = $arr->getValue("title", "escape|repeats");
     *
     *  //Returns value from $arr["id"] with a default value
     *  $id = $arr->getValue("id", null, 150);
     * 
* * @param string key Index to get * @param string|array filters Filters to apply * @param mixed defaultValue Default value if key not exist or value is empty and allowEmpty is false * @param boolean allowEmpty * @return mixed */ public function getValue(string key, var filters = null, var defaultValue = null, boolean allowEmpty = false) { var value, filter; let value = this->get(key, defaultValue); if filters { let filter = Di::$fetch()->get("filter"), value = filter->sanitize(value, filters); } if (value === "" || value === null) && allowEmpty === false { return defaultValue; } return value; } /** * Set data, clears and overwrites the current data. * * @param array data * @return void */ public function setData(array! data = []) -> void { let this->data = data; } /** * Fetch set data keys. * * @return array */ public function keys() -> array { return array_keys(this->getData()); } /** * Remove a data by key. * * @param string key The data key * @return object Arr */ public function remove(string key) { unset this->data[key]; return this; } /** * Clear all values. * * @return object Arr */ public function clear() { let this->data = []; return this; } /** * Count all elements in a data. * * @return int */ public function count() -> int { return count(this->getData()); } /** * Get a data iterator. * * return ArrayIterator */ public function getIterator() -> { return new ArrayIterator(this->getData()); } /** * Gets a value from an array using a dot separated path. * *

     *  // Get the value of $array['foo']['bar']
     *  $value = (new Arr($array))->getPath('foo.bar');
     * 
* *

     *  // Get the values of "color" in theme
     *  $colors = (new Arr($array))->getPath('theme.*.color');
     * 
* * @param mixed path Key path string (delimiter separated) or array of keys * @param mixed defaultValue Default value if the path is not set * @param string delimiter Key path delimiter * @return mixed */ public function getPath(var path, var defaultValue = null, string delimiter = ".") { var data, keys, key; let data = this->getData(); if typeof path == "array" { // The path has already been separated into keys let keys = path; } else { if array_key_exists(path, data) { // No need to do extra processing return data[path]; } // Remove starting delimiters and spaces let path = ltrim(path, "{" . delimiter . "} "), // Remove ending delimiters, spaces, and wildcards path = rtrim(path, "{" . delimiter . "} *"), // Split the keys by delimiter keys = explode(delimiter, path); } do { let key = array_shift(keys); if ctype_digit(key) { // Make the key an integer let key = (int) key; } if isset data[key] { if keys { if typeof data[key] == "array" { // Dig down into the next part of the path let data = data[key]; } else { // Unable to dig deeper break; } } else { // Found the path requested return data[key]; } } elseif key === "*" { var values, value, arr; // Handle wildcards let values = []; for arr in data { if typeof arr == "array" { let value = (new Arr(arr))->getPath(keys); if value { let values[] = value; } } } if values { // Found the values requested return values; } else { // Unable to dig deeper break; } } else { // Unable to dig deeper break; } } while keys; // Unable to find the value requested return defaultValue; } /** * Converts recursively the object to an array. * * @return array */ public function toArray() -> array { var key, value, tmp; let tmp = []; for key, value in this->getData() { if typeof value == "object" { if method_exists(value, "toArray") { let tmp[key] = value->toArray(); } else { let tmp[key] = value; } } else { let tmp[key] = value; } } return tmp; } /** * Whether or not an offset exists. * * @param string An offset to check for * @return boolean * @abstracting ArrayAccess */ public function offsetExists(mixed offset) -> boolean { return this->has(offset); } /** * Returns the value at specified offset. * * @param string The offset to retrieve * @return mixed * @abstracting ArrayAccess */ public function offsetGet(mixed offset) -> mixed { return this->get(offset); } /** * Assigns a value to the specified offset. * * @param string The offset to assign the value to * @param mixed The value to set * @return void * @abstracting ArrayAccess */ public function offsetSet(mixed offset, var value) -> void { this->set(offset, value); } /** * Unsets an offset. * * @param string The offset to unset * @return void * @abstracting ArrayAccess */ public function offsetUnset(mixed offset) -> void { this->remove(offset); } /** * Magic isset, whether or not a key exists. */ public function __isset(string key) -> boolean { return this->has(key); } /** * Magic get, returns the value at specified key. * First check if property exist. */ public function __get(key) { if isset this->{key} { return this->{key}; } return this->get(key); } /** * Magic set, assigns a value to the specified key. * First check if property exist. */ public function __set(string key, var value) -> void { if isset this->{key} { let this->{key} = value; } else { this->set(key, value); } } /** * Magic unset, unsets a key. */ public function __unset(key) -> void { this->remove(key); } }