Collection.php

Namespace

Guzzle\Common

File

drupal/core/vendor/guzzle/common/Guzzle/Common/Collection.php
View source
<?php

namespace Guzzle\Common;

use Guzzle\Common\Exception\InvalidArgumentException;

/**
 * Key value pair collection object
 */
class Collection implements \ArrayAccess, \IteratorAggregate, \Countable, ToArrayInterface {

  /**
   * @var array Data associated with the object.
   */
  protected $data;

  /**
   * Constructor
   *
   * @param array $data Associative array of data to set
   */
  public function __construct(array $data = null) {
    $this->data = $data ?: array();
  }

  /**
   * Create a new collection from an array, validate the keys, and add default values where missing
   *
   * @param array $config   Configuration values to apply.
   * @param array $defaults Default parameters
   * @param array $required Required parameter names
   *
   * @return self
   * @throws InvalidArgumentException if a parameter is missing
   */
  public static function fromConfig(array $config = null, array $defaults = null, array $required = null) {
    $collection = new self($defaults);
    foreach ((array) $config as $key => $value) {
      $collection
        ->set($key, $value);
    }
    foreach ((array) $required as $key) {
      if ($collection
        ->hasKey($key) === false) {
        throw new InvalidArgumentException("Config must contain a '{$key}' key");
      }
    }
    return $collection;
  }

  /**
   * Add a value to a key.  If a key of the same name has already been added, the key value will be converted into an
   * array and the new value will be pushed to the end of the array.
   *
   * @param string $key   Key to add
   * @param mixed  $value Value to add to the key
   *
   * @return Collection Returns a reference to the object.
   */
  public function add($key, $value) {
    if (!array_key_exists($key, $this->data)) {
      $this->data[$key] = $value;
    }
    elseif (is_array($this->data[$key])) {
      $this->data[$key][] = $value;
    }
    else {
      $this->data[$key] = array(
        $this->data[$key],
        $value,
      );
    }
    return $this;
  }

  /**
   * Removes all key value pairs
   *
   * @return Collection
   */
  public function clear() {
    $this->data = array();
    return $this;
  }

  /**
   * Return the number of keys
   *
   * @return integer
   */
  public function count() {
    return count($this->data);
  }

  /**
   * Iterates over each key value pair in the collection passing them to the Closure. If the  Closure function returns
   * true, the current value from input is returned into the result Collection.  The Closure must accept three
   * parameters: (string) $key, (string) $value and return Boolean TRUE or FALSE for each value.
   *
   * @param \Closure $closure Closure evaluation function
   * @param bool     $static  Set to TRUE to use the same class as the return rather than returning a Collection
   *
   * @return Collection
   */
  public function filter(\Closure $closure, $static = true) {
    $collection = $static ? new static() : new self();
    foreach ($this->data as $key => $value) {
      if ($closure($key, $value)) {
        $collection
          ->add($key, $value);
      }
    }
    return $collection;
  }

  /**
   * Get an iterator object
   *
   * @return array
   */
  public function getIterator() {
    return new \ArrayIterator($this->data);
  }

  /**
   * Get a specific key value.
   *
   * @param string $key Key to retrieve.
   *
   * @return mixed|null Value of the key or NULL
   */
  public function get($key) {
    return isset($this->data[$key]) ? $this->data[$key] : null;
  }

  /**
   * Get all or a subset of matching key value pairs
   *
   * @param array $keys Pass an array of keys to retrieve only a subset of key value pairs
   *
   * @return array Returns an array of all matching key value pairs
   */
  public function getAll(array $keys = null) {
    return $keys ? array_intersect_key($this->data, array_flip($keys)) : $this->data;
  }

  /**
   * {@inheritdoc}
   */
  public function toArray() {
    return $this->data;
  }

  /**
   * Get all keys in the collection
   *
   * @return array
   */
  public function getKeys() {
    return array_keys($this->data);
  }

  /**
   * Returns whether or not the specified key is present.
   *
   * @param string $key The key for which to check the existence.
   *
   * @return bool
   */
  public function hasKey($key) {
    return array_key_exists($key, $this->data);
  }

  /**
   * Case insensitive search the keys in the collection
   *
   * @param string $key Key to search for
   *
   * @return bool|string Returns false if not found, otherwise returns the key
   */
  public function keySearch($key) {
    foreach (array_keys($this->data) as $k) {
      if (!strcasecmp($k, $key)) {
        return $k;
      }
    }
    return false;
  }

  /**
   * Checks if any keys contains a certain value
   *
   * @param string $value Value to search for
   *
   * @return mixed Returns the key if the value was found FALSE if the value was not found.
   */
  public function hasValue($value) {
    return array_search($value, $this->data);
  }

  /**
   * Returns a Collection containing all the elements of the collection after applying the callback function to each
   * one. The Closure should accept three parameters: (string) $key, (string) $value, (array) $context and return a
   * modified value
   *
   * @param \Closure $closure Closure to apply
   * @param array    $context Context to pass to the closure
   * @param bool     $static  Set to TRUE to use the same class as the return rather than returning a Collection
   *
   * @return Collection
   */
  public function map(\Closure $closure, array $context = array(), $static = true) {
    $collection = $static ? new static() : new self();
    foreach ($this as $key => $value) {
      $collection
        ->add($key, $closure($key, $value, $context));
    }
    return $collection;
  }

  /**
   * Add and merge in a Collection or array of key value pair data.
   *
   * @param Collection|array $data Associative array of key value pair data
   *
   * @return Collection Returns a reference to the object.
   */
  public function merge($data) {
    if ($data instanceof self) {
      $data = $data
        ->getAll();
    }
    elseif (!is_array($data)) {
      return $this;
    }
    if (empty($this->data)) {
      $this->data = $data;
    }
    else {
      foreach ($data as $key => $value) {
        $this
          ->add($key, $value);
      }
    }
    return $this;
  }

  /**
   * ArrayAccess implementation of offsetExists()
   *
   * @param string $offset Array key
   *
   * @return bool
   */
  public function offsetExists($offset) {
    return $this
      ->hasKey($offset) !== false;
  }

  /**
   * ArrayAccess implementation of offsetGet()
   *
   * @param string $offset Array key
   *
   * @return null|mixed
   */
  public function offsetGet($offset) {
    return $this
      ->get($offset);
  }

  /**
   * ArrayAccess implementation of offsetGet()
   *
   * @param string $offset Array key
   * @param mixed  $value  Value to set
   */
  public function offsetSet($offset, $value) {
    $this
      ->set($offset, $value);
  }

  /**
   * ArrayAccess implementation of offsetUnset()
   *
   * @param string $offset Array key
   */
  public function offsetUnset($offset) {
    $this
      ->remove($offset);
  }

  /**
   * Remove a specific key value pair
   *
   * @param string $key A key to remove
   *
   * @return Collection
   */
  public function remove($key) {
    unset($this->data[$key]);
    return $this;
  }

  /**
   * Replace the data of the object with the value of an array
   *
   * @param array $data Associative array of data
   *
   * @return Collection Returns a reference to the object
   */
  public function replace(array $data) {
    $this->data = $data;
    return $this;
  }

  /**
   * Set a key value pair
   *
   * @param string $key   Key to set
   * @param mixed  $value Value to set
   *
   * @return Collection Returns a reference to the object
   */
  public function set($key, $value) {
    $this->data[$key] = $value;
    return $this;
  }

  /**
   * Inject configuration settings into an input string
   *
   * @param string $input  Input to inject
   *
   * @return string
   */
  public function inject($input) {
    $replace = array();
    foreach ($this->data as $key => $val) {
      $replace['{' . $key . '}'] = $val;
    }
    return strtr($input, $replace);
  }

  /**
   * Gets a value from the collection using an array path (e.g. foo/baz/bar would retrieve bar from two nested arrays)
   * Allows for wildcard searches which recursively combine matches up to the level at which the wildcard occurs. This
   * can be useful for accepting any key of a sub-array and combining matching keys from each diverging path.
   *
   * @param string $path      Path to traverse and retrieve a value from
   * @param string $separator Character used to add depth to the search
   * @param mixed  $data      Optional data to descend into (used when wildcards are encountered)
   *
   * @return mixed|null
   */
  public function getPath($path, $separator = '/', $data = null) {

    // Assume the data of the collection if no data was passed into the method
    if ($data === null) {
      $data =& $this->data;
    }

    // Break the path into an array if needed
    if (!is_array($path)) {
      $path = explode($separator, $path);
    }

    // Using an iterative approach rather than recursion for speed
    while (null !== ($part = array_shift($path))) {
      if (!is_array($data)) {
        return null;
      }

      // The value does not exist in the array or the path has more but the value is not an array
      if (!isset($data[$part])) {

        // Not using a wildcard and the key was not found, so return null
        if ($part != '*') {
          return null;
        }

        // If using a wildcard search, then diverge and combine paths
        $result = array();
        foreach ($data as $value) {
          if (!$path) {
            $result = array_merge_recursive($result, (array) $value);
          }
          else {
            $test = $this
              ->getPath($path, $separator, $value);
            if ($test !== null) {
              $result = array_merge_recursive($result, (array) $test);
            }
          }
        }
        return $result;
      }

      // Descend deeper into the data
      $data =& $data[$part];
    }
    return $data;
  }

  /**
   * Over write key value pairs in this collection with all of the data from an array or collection.
   *
   * @param array|\Traversable $data Values to override over this config
   *
   * @return self
   */
  public function overwriteWith($data) {
    foreach ($data as $k => $v) {
      $this
        ->set($k, $v);
    }
    return $this;
  }

}

Classes

Namesort descending Description
Collection Key value pair collection object