diff options
Diffstat (limited to 'framework/collections')
| -rw-r--r-- | framework/collections/CAttributeCollection.php | 185 | ||||
| -rw-r--r-- | framework/collections/CConfiguration.php | 101 | ||||
| -rw-r--r-- | framework/collections/CList.php | 346 | ||||
| -rw-r--r-- | framework/collections/CListIterator.php | 94 | ||||
| -rw-r--r-- | framework/collections/CMap.php | 343 | ||||
| -rw-r--r-- | framework/collections/CMapIterator.php | 94 | ||||
| -rw-r--r-- | framework/collections/CQueue.php | 172 | ||||
| -rw-r--r-- | framework/collections/CQueueIterator.php | 94 | ||||
| -rw-r--r-- | framework/collections/CStack.php | 173 | ||||
| -rw-r--r-- | framework/collections/CStackIterator.php | 94 | ||||
| -rw-r--r-- | framework/collections/CTypedList.php | 52 | ||||
| -rw-r--r-- | framework/collections/CTypedMap.php | 52 |
12 files changed, 1800 insertions, 0 deletions
diff --git a/framework/collections/CAttributeCollection.php b/framework/collections/CAttributeCollection.php new file mode 100644 index 0000000..b0f1eb9 --- /dev/null +++ b/framework/collections/CAttributeCollection.php @@ -0,0 +1,185 @@ +<?php +/** + * This file contains classes implementing attribute collection feature. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + + +/** + * CAttributeCollection implements a collection for storing attribute names and values. + * + * Besides all functionalities provided by {@link CMap}, CAttributeCollection + * allows you to get and set attribute values like getting and setting + * properties. For example, the following usages are all valid for a + * CAttributeCollection object: + * <pre> + * $collection->text='text'; // same as: $collection->add('text','text'); + * echo $collection->text; // same as: echo $collection->itemAt('text'); + * </pre> + * + * The case sensitivity of attribute names can be toggled by setting the + * {@link caseSensitive} property of the collection. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id: CAttributeCollection.php 3515 2011-12-28 12:29:24Z mdomba $ + * @package system.collections + * @since 1.0 + */ +class CAttributeCollection extends CMap +{ + /** + * @var boolean whether the keys are case-sensitive. Defaults to false. + */ + public $caseSensitive=false; + + /** + * Returns a property value or an event handler list by property or event name. + * This method overrides the parent implementation by returning + * a key value if the key exists in the collection. + * @param string $name the property name or the event name + * @return mixed the property value or the event handler list + * @throws CException if the property/event is not defined. + */ + public function __get($name) + { + if($this->contains($name)) + return $this->itemAt($name); + else + return parent::__get($name); + } + + /** + * Sets value of a component property. + * This method overrides the parent implementation by adding a new key value + * to the collection. + * @param string $name the property name or event name + * @param mixed $value the property value or event handler + * @throws CException If the property is not defined or read-only. + */ + public function __set($name,$value) + { + $this->add($name,$value); + } + + /** + * Checks if a property value is null. + * This method overrides the parent implementation by checking + * if the key exists in the collection and contains a non-null value. + * @param string $name the property name or the event name + * @return boolean whether the property value is null + */ + public function __isset($name) + { + if($this->contains($name)) + return $this->itemAt($name)!==null; + else + return parent::__isset($name); + } + + /** + * Sets a component property to be null. + * This method overrides the parent implementation by clearing + * the specified key value. + * @param string $name the property name or the event name + */ + public function __unset($name) + { + $this->remove($name); + } + + /** + * Returns the item with the specified key. + * This overrides the parent implementation by converting the key to lower case first if {@link caseSensitive} is false. + * @param mixed $key the key + * @return mixed the element at the offset, null if no element is found at the offset + */ + public function itemAt($key) + { + if($this->caseSensitive) + return parent::itemAt($key); + else + return parent::itemAt(strtolower($key)); + } + + /** + * Adds an item into the map. + * This overrides the parent implementation by converting the key to lower case first if {@link caseSensitive} is false. + * @param mixed $key key + * @param mixed $value value + */ + public function add($key,$value) + { + if($this->caseSensitive) + parent::add($key,$value); + else + parent::add(strtolower($key),$value); + } + + /** + * Removes an item from the map by its key. + * This overrides the parent implementation by converting the key to lower case first if {@link caseSensitive} is false. + * @param mixed $key the key of the item to be removed + * @return mixed the removed value, null if no such key exists. + */ + public function remove($key) + { + if($this->caseSensitive) + return parent::remove($key); + else + return parent::remove(strtolower($key)); + } + + /** + * Returns whether the specified is in the map. + * This overrides the parent implementation by converting the key to lower case first if {@link caseSensitive} is false. + * @param mixed $key the key + * @return boolean whether the map contains an item with the specified key + */ + public function contains($key) + { + if($this->caseSensitive) + return parent::contains($key); + else + return parent::contains(strtolower($key)); + } + + /** + * Determines whether a property is defined. + * This method overrides parent implementation by returning true + * if the collection contains the named key. + * @param string $name the property name + * @return boolean whether the property is defined + */ + public function hasProperty($name) + { + return $this->contains($name) || parent::hasProperty($name); + } + + /** + * Determines whether a property can be read. + * This method overrides parent implementation by returning true + * if the collection contains the named key. + * @param string $name the property name + * @return boolean whether the property can be read + */ + public function canGetProperty($name) + { + return $this->contains($name) || parent::canGetProperty($name); + } + + /** + * Determines whether a property can be set. + * This method overrides parent implementation by always returning true + * because you can always add a new value to the collection. + * @param string $name the property name + * @return boolean true + */ + public function canSetProperty($name) + { + return true; + } +} diff --git a/framework/collections/CConfiguration.php b/framework/collections/CConfiguration.php new file mode 100644 index 0000000..eaa427b --- /dev/null +++ b/framework/collections/CConfiguration.php @@ -0,0 +1,101 @@ +<?php +/** + * This file contains classes implementing configuration feature. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + + +/** + * CConfiguration represents an array-based configuration. + * + * It can be used to initialize an object's properties. + * + * The configuration data may be obtained from a PHP script. For example, + * <pre> + * return array( + * 'name'=>'My Application', + * 'defaultController'=>'index', + * ); + * </pre> + * Use the following code to load the above configuration data: + * <pre> + * $config=new CConfiguration('path/to/config.php'); + * </pre> + * + * To apply the configuration to an object, call {@link applyTo()}. + * Each (key,value) pair in the configuration data is applied + * to the object like: $object->$key=$value. + * + * Since CConfiguration extends from {@link CMap}, it can be + * used like an associative array. See {@link CMap} for more details. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id: CConfiguration.php 3458 2011-11-21 02:13:03Z alexander.makarow $ + * @package system.collections + * @since 1.0 + */ +class CConfiguration extends CMap +{ + /** + * Constructor. + * @param mixed $data if string, it represents a config file (a PHP script returning the configuration as an array); + * If array, it is config data. + */ + public function __construct($data=null) + { + if(is_string($data)) + parent::__construct(require($data)); + else + parent::__construct($data); + } + + /** + * Loads configuration data from a file and merges it with the existing configuration. + * + * A config file must be a PHP script returning a configuration array (like the following) + * <pre> + * return array + * ( + * 'name'=>'My Application', + * 'defaultController'=>'index', + * ); + * </pre> + * + * @param string $configFile configuration file path (if using relative path, be aware of what is the current path) + * @see mergeWith + */ + public function loadFromFile($configFile) + { + $data=require($configFile); + if($this->getCount()>0) + $this->mergeWith($data); + else + $this->copyFrom($data); + } + + /** + * Saves the configuration into a string. + * The string is a valid PHP expression representing the configuration data as an array. + * @return string the string representation of the configuration + */ + public function saveAsString() + { + return str_replace("\r",'',var_export($this->toArray(),true)); + } + + /** + * Applies the configuration to an object. + * Each (key,value) pair in the configuration data is applied + * to the object like: $object->$key=$value. + * @param object $object object to be applied with this configuration + */ + public function applyTo($object) + { + foreach($this->toArray() as $key=>$value) + $object->$key=$value; + } +} diff --git a/framework/collections/CList.php b/framework/collections/CList.php new file mode 100644 index 0000000..9f41dc4 --- /dev/null +++ b/framework/collections/CList.php @@ -0,0 +1,346 @@ +<?php +/** + * This file contains classes implementing list feature. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +/** + * CList implements an integer-indexed collection class. + * + * You can access, append, insert, remove an item by using + * {@link itemAt}, {@link add}, {@link insertAt}, {@link remove}, and {@link removeAt}. + * To get the number of the items in the list, use {@link getCount}. + * CList can also be used like a regular array as follows, + * <pre> + * $list[]=$item; // append at the end + * $list[$index]=$item; // $index must be between 0 and $list->Count + * unset($list[$index]); // remove the item at $index + * if(isset($list[$index])) // if the list has an item at $index + * foreach($list as $index=>$item) // traverse each item in the list + * $n=count($list); // returns the number of items in the list + * </pre> + * + * To extend CList by doing additional operations with each addition or removal + * operation (e.g. performing type check), override {@link insertAt()}, and {@link removeAt()}. + * + * @property boolean $readOnly Whether this list is read-only or not. Defaults to false. + * @property Iterator $iterator An iterator for traversing the items in the list. + * @property integer $count The number of items in the list. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id: CList.php 3430 2011-11-02 23:10:03Z alexander.makarow@gmail.com $ + * @package system.collections + * @since 1.0 + */ +class CList extends CComponent implements IteratorAggregate,ArrayAccess,Countable +{ + /** + * @var array internal data storage + */ + private $_d=array(); + /** + * @var integer number of items + */ + private $_c=0; + /** + * @var boolean whether this list is read-only + */ + private $_r=false; + + /** + * Constructor. + * Initializes the list with an array or an iterable object. + * @param array $data the initial data. Default is null, meaning no initialization. + * @param boolean $readOnly whether the list is read-only + * @throws CException If data is not null and neither an array nor an iterator. + */ + public function __construct($data=null,$readOnly=false) + { + if($data!==null) + $this->copyFrom($data); + $this->setReadOnly($readOnly); + } + + /** + * @return boolean whether this list is read-only or not. Defaults to false. + */ + public function getReadOnly() + { + return $this->_r; + } + + /** + * @param boolean $value whether this list is read-only or not + */ + protected function setReadOnly($value) + { + $this->_r=$value; + } + + /** + * Returns an iterator for traversing the items in the list. + * This method is required by the interface IteratorAggregate. + * @return Iterator an iterator for traversing the items in the list. + */ + public function getIterator() + { + return new CListIterator($this->_d); + } + + /** + * Returns the number of items in the list. + * This method is required by Countable interface. + * @return integer number of items in the list. + */ + public function count() + { + return $this->getCount(); + } + + /** + * Returns the number of items in the list. + * @return integer the number of items in the list + */ + public function getCount() + { + return $this->_c; + } + + /** + * Returns the item at the specified offset. + * This method is exactly the same as {@link offsetGet}. + * @param integer $index the index of the item + * @return mixed the item at the index + * @throws CException if the index is out of the range + */ + public function itemAt($index) + { + if(isset($this->_d[$index])) + return $this->_d[$index]; + else if($index>=0 && $index<$this->_c) // in case the value is null + return $this->_d[$index]; + else + throw new CException(Yii::t('yii','List index "{index}" is out of bound.', + array('{index}'=>$index))); + } + + /** + * Appends an item at the end of the list. + * @param mixed $item new item + * @return integer the zero-based index at which the item is added + */ + public function add($item) + { + $this->insertAt($this->_c,$item); + return $this->_c-1; + } + + /** + * Inserts an item at the specified position. + * Original item at the position and the next items + * will be moved one step towards the end. + * @param integer $index the specified position. + * @param mixed $item new item + * @throws CException If the index specified exceeds the bound or the list is read-only + */ + public function insertAt($index,$item) + { + if(!$this->_r) + { + if($index===$this->_c) + $this->_d[$this->_c++]=$item; + else if($index>=0 && $index<$this->_c) + { + array_splice($this->_d,$index,0,array($item)); + $this->_c++; + } + else + throw new CException(Yii::t('yii','List index "{index}" is out of bound.', + array('{index}'=>$index))); + } + else + throw new CException(Yii::t('yii','The list is read only.')); + } + + /** + * Removes an item from the list. + * The list will first search for the item. + * The first item found will be removed from the list. + * @param mixed $item the item to be removed. + * @return integer the index at which the item is being removed + * @throws CException If the item does not exist + */ + public function remove($item) + { + if(($index=$this->indexOf($item))>=0) + { + $this->removeAt($index); + return $index; + } + else + return false; + } + + /** + * Removes an item at the specified position. + * @param integer $index the index of the item to be removed. + * @return mixed the removed item. + * @throws CException If the index specified exceeds the bound or the list is read-only + */ + public function removeAt($index) + { + if(!$this->_r) + { + if($index>=0 && $index<$this->_c) + { + $this->_c--; + if($index===$this->_c) + return array_pop($this->_d); + else + { + $item=$this->_d[$index]; + array_splice($this->_d,$index,1); + return $item; + } + } + else + throw new CException(Yii::t('yii','List index "{index}" is out of bound.', + array('{index}'=>$index))); + } + else + throw new CException(Yii::t('yii','The list is read only.')); + } + + /** + * Removes all items in the list. + */ + public function clear() + { + for($i=$this->_c-1;$i>=0;--$i) + $this->removeAt($i); + } + + /** + * @param mixed $item the item + * @return boolean whether the list contains the item + */ + public function contains($item) + { + return $this->indexOf($item)>=0; + } + + /** + * @param mixed $item the item + * @return integer the index of the item in the list (0 based), -1 if not found. + */ + public function indexOf($item) + { + if(($index=array_search($item,$this->_d,true))!==false) + return $index; + else + return -1; + } + + /** + * @return array the list of items in array + */ + public function toArray() + { + return $this->_d; + } + + /** + * Copies iterable data into the list. + * Note, existing data in the list will be cleared first. + * @param mixed $data the data to be copied from, must be an array or object implementing Traversable + * @throws CException If data is neither an array nor a Traversable. + */ + public function copyFrom($data) + { + if(is_array($data) || ($data instanceof Traversable)) + { + if($this->_c>0) + $this->clear(); + if($data instanceof CList) + $data=$data->_d; + foreach($data as $item) + $this->add($item); + } + else if($data!==null) + throw new CException(Yii::t('yii','List data must be an array or an object implementing Traversable.')); + } + + /** + * Merges iterable data into the map. + * New data will be appended to the end of the existing data. + * @param mixed $data the data to be merged with, must be an array or object implementing Traversable + * @throws CException If data is neither an array nor an iterator. + */ + public function mergeWith($data) + { + if(is_array($data) || ($data instanceof Traversable)) + { + if($data instanceof CList) + $data=$data->_d; + foreach($data as $item) + $this->add($item); + } + else if($data!==null) + throw new CException(Yii::t('yii','List data must be an array or an object implementing Traversable.')); + } + + /** + * Returns whether there is an item at the specified offset. + * This method is required by the interface ArrayAccess. + * @param integer $offset the offset to check on + * @return boolean + */ + public function offsetExists($offset) + { + return ($offset>=0 && $offset<$this->_c); + } + + /** + * Returns the item at the specified offset. + * This method is required by the interface ArrayAccess. + * @param integer $offset the offset to retrieve item. + * @return mixed the item at the offset + * @throws CException if the offset is invalid + */ + public function offsetGet($offset) + { + return $this->itemAt($offset); + } + + /** + * Sets the item at the specified offset. + * This method is required by the interface ArrayAccess. + * @param integer $offset the offset to set item + * @param mixed $item the item value + */ + public function offsetSet($offset,$item) + { + if($offset===null || $offset===$this->_c) + $this->insertAt($this->_c,$item); + else + { + $this->removeAt($offset); + $this->insertAt($offset,$item); + } + } + + /** + * Unsets the item at the specified offset. + * This method is required by the interface ArrayAccess. + * @param integer $offset the offset to unset item + */ + public function offsetUnset($offset) + { + $this->removeAt($offset); + } +} + diff --git a/framework/collections/CListIterator.php b/framework/collections/CListIterator.php new file mode 100644 index 0000000..ca7f788 --- /dev/null +++ b/framework/collections/CListIterator.php @@ -0,0 +1,94 @@ +<?php +/** + * CListIterator class file. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +/** + * CListIterator implements an interator for {@link CList}. + * + * It allows CList to return a new iterator for traversing the items in the list. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id: CListIterator.php 2799 2011-01-01 19:31:13Z qiang.xue $ + * @package system.collections + * @since 1.0 + */ +class CListIterator implements Iterator +{ + /** + * @var array the data to be iterated through + */ + private $_d; + /** + * @var integer index of the current item + */ + private $_i; + /** + * @var integer count of the data items + */ + private $_c; + + /** + * Constructor. + * @param array $data the data to be iterated through + */ + public function __construct(&$data) + { + $this->_d=&$data; + $this->_i=0; + $this->_c=count($this->_d); + } + + /** + * Rewinds internal array pointer. + * This method is required by the interface Iterator. + */ + public function rewind() + { + $this->_i=0; + } + + /** + * Returns the key of the current array item. + * This method is required by the interface Iterator. + * @return integer the key of the current array item + */ + public function key() + { + return $this->_i; + } + + /** + * Returns the current array item. + * This method is required by the interface Iterator. + * @return mixed the current array item + */ + public function current() + { + return $this->_d[$this->_i]; + } + + /** + * Moves the internal pointer to the next array item. + * This method is required by the interface Iterator. + */ + public function next() + { + $this->_i++; + } + + /** + * Returns whether there is an item at current position. + * This method is required by the interface Iterator. + * @return boolean + */ + public function valid() + { + return $this->_i<$this->_c; + } +} diff --git a/framework/collections/CMap.php b/framework/collections/CMap.php new file mode 100644 index 0000000..ef0c55d --- /dev/null +++ b/framework/collections/CMap.php @@ -0,0 +1,343 @@ +<?php +/** + * This file contains classes implementing Map feature. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +/** + * CMap implements a collection that takes key-value pairs. + * + * You can access, add or remove an item with a key by using + * {@link itemAt}, {@link add}, and {@link remove}. + * To get the number of the items in the map, use {@link getCount}. + * CMap can also be used like a regular array as follows, + * <pre> + * $map[$key]=$value; // add a key-value pair + * unset($map[$key]); // remove the value with the specified key + * if(isset($map[$key])) // if the map contains the key + * foreach($map as $key=>$value) // traverse the items in the map + * $n=count($map); // returns the number of items in the map + * </pre> + * + * @property boolean $readOnly Whether this map is read-only or not. Defaults to false. + * @property CMapIterator $iterator An iterator for traversing the items in the list. + * @property integer $count The number of items in the map. + * @property array $keys The key list. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id: CMap.php 3518 2011-12-28 23:31:29Z alexander.makarow $ + * @package system.collections + * @since 1.0 + */ +class CMap extends CComponent implements IteratorAggregate,ArrayAccess,Countable +{ + /** + * @var array internal data storage + */ + private $_d=array(); + /** + * @var boolean whether this list is read-only + */ + private $_r=false; + + /** + * Constructor. + * Initializes the list with an array or an iterable object. + * @param array $data the intial data. Default is null, meaning no initialization. + * @param boolean $readOnly whether the list is read-only + * @throws CException If data is not null and neither an array nor an iterator. + */ + public function __construct($data=null,$readOnly=false) + { + if($data!==null) + $this->copyFrom($data); + $this->setReadOnly($readOnly); + } + + /** + * @return boolean whether this map is read-only or not. Defaults to false. + */ + public function getReadOnly() + { + return $this->_r; + } + + /** + * @param boolean $value whether this list is read-only or not + */ + protected function setReadOnly($value) + { + $this->_r=$value; + } + + /** + * Returns an iterator for traversing the items in the list. + * This method is required by the interface IteratorAggregate. + * @return CMapIterator an iterator for traversing the items in the list. + */ + public function getIterator() + { + return new CMapIterator($this->_d); + } + + /** + * Returns the number of items in the map. + * This method is required by Countable interface. + * @return integer number of items in the map. + */ + public function count() + { + return $this->getCount(); + } + + /** + * Returns the number of items in the map. + * @return integer the number of items in the map + */ + public function getCount() + { + return count($this->_d); + } + + /** + * @return array the key list + */ + public function getKeys() + { + return array_keys($this->_d); + } + + /** + * Returns the item with the specified key. + * This method is exactly the same as {@link offsetGet}. + * @param mixed $key the key + * @return mixed the element at the offset, null if no element is found at the offset + */ + public function itemAt($key) + { + if(isset($this->_d[$key])) + return $this->_d[$key]; + else + return null; + } + + /** + * Adds an item into the map. + * Note, if the specified key already exists, the old value will be overwritten. + * @param mixed $key key + * @param mixed $value value + * @throws CException if the map is read-only + */ + public function add($key,$value) + { + if(!$this->_r) + { + if($key===null) + $this->_d[]=$value; + else + $this->_d[$key]=$value; + } + else + throw new CException(Yii::t('yii','The map is read only.')); + } + + /** + * Removes an item from the map by its key. + * @param mixed $key the key of the item to be removed + * @return mixed the removed value, null if no such key exists. + * @throws CException if the map is read-only + */ + public function remove($key) + { + if(!$this->_r) + { + if(isset($this->_d[$key])) + { + $value=$this->_d[$key]; + unset($this->_d[$key]); + return $value; + } + else + { + // it is possible the value is null, which is not detected by isset + unset($this->_d[$key]); + return null; + } + } + else + throw new CException(Yii::t('yii','The map is read only.')); + } + + /** + * Removes all items in the map. + */ + public function clear() + { + foreach(array_keys($this->_d) as $key) + $this->remove($key); + } + + /** + * @param mixed $key the key + * @return boolean whether the map contains an item with the specified key + */ + public function contains($key) + { + return isset($this->_d[$key]) || array_key_exists($key,$this->_d); + } + + /** + * @return array the list of items in array + */ + public function toArray() + { + return $this->_d; + } + + /** + * Copies iterable data into the map. + * Note, existing data in the map will be cleared first. + * @param mixed $data the data to be copied from, must be an array or object implementing Traversable + * @throws CException If data is neither an array nor an iterator. + */ + public function copyFrom($data) + { + if(is_array($data) || $data instanceof Traversable) + { + if($this->getCount()>0) + $this->clear(); + if($data instanceof CMap) + $data=$data->_d; + foreach($data as $key=>$value) + $this->add($key,$value); + } + else if($data!==null) + throw new CException(Yii::t('yii','Map data must be an array or an object implementing Traversable.')); + } + + /** + * Merges iterable data into the map. + * + * Existing elements in the map will be overwritten if their keys are the same as those in the source. + * If the merge is recursive, the following algorithm is performed: + * <ul> + * <li>the map data is saved as $a, and the source data is saved as $b;</li> + * <li>if $a and $b both have an array indxed at the same string key, the arrays will be merged using this algorithm;</li> + * <li>any integer-indexed elements in $b will be appended to $a and reindexed accordingly;</li> + * <li>any string-indexed elements in $b will overwrite elements in $a with the same index;</li> + * </ul> + * + * @param mixed $data the data to be merged with, must be an array or object implementing Traversable + * @param boolean $recursive whether the merging should be recursive. + * + * @throws CException If data is neither an array nor an iterator. + */ + public function mergeWith($data,$recursive=true) + { + if(is_array($data) || $data instanceof Traversable) + { + if($data instanceof CMap) + $data=$data->_d; + if($recursive) + { + if($data instanceof Traversable) + { + $d=array(); + foreach($data as $key=>$value) + $d[$key]=$value; + $this->_d=self::mergeArray($this->_d,$d); + } + else + $this->_d=self::mergeArray($this->_d,$data); + } + else + { + foreach($data as $key=>$value) + $this->add($key,$value); + } + } + else if($data!==null) + throw new CException(Yii::t('yii','Map data must be an array or an object implementing Traversable.')); + } + + /** + * Merges two or more arrays into one recursively. + * If each array has an element with the same string key value, the latter + * will overwrite the former (different from array_merge_recursive). + * Recursive merging will be conducted if both arrays have an element of array + * type and are having the same key. + * For integer-keyed elements, the elements from the latter array will + * be appended to the former array. + * @param array $a array to be merged to + * @param array $b array to be merged from. You can specifiy additional + * arrays via third argument, fourth argument etc. + * @return array the merged array (the original arrays are not changed.) + * @see mergeWith + */ + public static function mergeArray($a,$b) + { + $args=func_get_args(); + $res=array_shift($args); + while(!empty($args)) + { + $next=array_shift($args); + foreach($next as $k => $v) + { + if(is_integer($k)) + isset($res[$k]) ? $res[]=$v : $res[$k]=$v; + else if(is_array($v) && isset($res[$k]) && is_array($res[$k])) + $res[$k]=self::mergeArray($res[$k],$v); + else + $res[$k]=$v; + } + } + return $res; + } + + /** + * Returns whether there is an element at the specified offset. + * This method is required by the interface ArrayAccess. + * @param mixed $offset the offset to check on + * @return boolean + */ + public function offsetExists($offset) + { + return $this->contains($offset); + } + + /** + * Returns the element at the specified offset. + * This method is required by the interface ArrayAccess. + * @param integer $offset the offset to retrieve element. + * @return mixed the element at the offset, null if no element is found at the offset + */ + public function offsetGet($offset) + { + return $this->itemAt($offset); + } + + /** + * Sets the element at the specified offset. + * This method is required by the interface ArrayAccess. + * @param integer $offset the offset to set element + * @param mixed $item the element value + */ + public function offsetSet($offset,$item) + { + $this->add($offset,$item); + } + + /** + * Unsets the element at the specified offset. + * This method is required by the interface ArrayAccess. + * @param mixed $offset the offset to unset element + */ + public function offsetUnset($offset) + { + $this->remove($offset); + } +} diff --git a/framework/collections/CMapIterator.php b/framework/collections/CMapIterator.php new file mode 100644 index 0000000..e91ac39 --- /dev/null +++ b/framework/collections/CMapIterator.php @@ -0,0 +1,94 @@ +<?php +/** + * CMapIterator class file. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +/** + * CMapIterator implements an interator for {@link CMap}. + * + * It allows CMap to return a new iterator for traversing the items in the map. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id: CMapIterator.php 3186 2011-04-15 22:34:55Z alexander.makarow $ + * @package system.collections + * @since 1.0 + */ +class CMapIterator implements Iterator +{ + /** + * @var array the data to be iterated through + */ + private $_d; + /** + * @var array list of keys in the map + */ + private $_keys; + /** + * @var mixed current key + */ + private $_key; + + /** + * Constructor. + * @param array $data the data to be iterated through + */ + public function __construct(&$data) + { + $this->_d=&$data; + $this->_keys=array_keys($data); + $this->_key=reset($this->_keys); + } + + /** + * Rewinds internal array pointer. + * This method is required by the interface Iterator. + */ + public function rewind() + { + $this->_key=reset($this->_keys); + } + + /** + * Returns the key of the current array element. + * This method is required by the interface Iterator. + * @return mixed the key of the current array element + */ + public function key() + { + return $this->_key; + } + + /** + * Returns the current array element. + * This method is required by the interface Iterator. + * @return mixed the current array element + */ + public function current() + { + return $this->_d[$this->_key]; + } + + /** + * Moves the internal pointer to the next array element. + * This method is required by the interface Iterator. + */ + public function next() + { + $this->_key=next($this->_keys); + } + + /** + * Returns whether there is an element at current position. + * This method is required by the interface Iterator. + * @return boolean + */ + public function valid() + { + return $this->_key!==false; + } +} diff --git a/framework/collections/CQueue.php b/framework/collections/CQueue.php new file mode 100644 index 0000000..9f1aa99 --- /dev/null +++ b/framework/collections/CQueue.php @@ -0,0 +1,172 @@ +<?php +/** + * This file contains classes implementing the queue feature. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +/** + * CQueue implements a queue. + * + * The typical queue operations are implemented, which include + * {@link enqueue()}, {@link dequeue()} and {@link peek()}. In addition, + * {@link contains()} can be used to check if an item is contained + * in the queue. To obtain the number of the items in the queue, + * check the {@link getCount Count} property. + * + * Items in the queue may be traversed using foreach as follows, + * <pre> + * foreach($queue as $item) ... + * </pre> + * + * @property Iterator $iterator An iterator for traversing the items in the queue. + * @property integer $count The number of items in the queue. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id: CQueue.php 3427 2011-10-25 00:03:52Z alexander.makarow $ + * @package system.collections + * @since 1.0 + */ +class CQueue extends CComponent implements IteratorAggregate,Countable +{ + /** + * internal data storage + * @var array + */ + private $_d=array(); + /** + * number of items + * @var integer + */ + private $_c=0; + + /** + * Constructor. + * Initializes the queue with an array or an iterable object. + * @param array $data the intial data. Default is null, meaning no initialization. + * @throws CException If data is not null and neither an array nor an iterator. + */ + public function __construct($data=null) + { + if($data!==null) + $this->copyFrom($data); + } + + /** + * @return array the list of items in queue + */ + public function toArray() + { + return $this->_d; + } + + /** + * Copies iterable data into the queue. + * Note, existing data in the list will be cleared first. + * @param mixed $data the data to be copied from, must be an array or object implementing Traversable + * @throws CException If data is neither an array nor a Traversable. + */ + public function copyFrom($data) + { + if(is_array($data) || ($data instanceof Traversable)) + { + $this->clear(); + foreach($data as $item) + { + $this->_d[]=$item; + ++$this->_c; + } + } + else if($data!==null) + throw new CException(Yii::t('yii','Queue data must be an array or an object implementing Traversable.')); + } + + /** + * Removes all items in the queue. + */ + public function clear() + { + $this->_c=0; + $this->_d=array(); + } + + /** + * @param mixed $item the item + * @return boolean whether the queue contains the item + */ + public function contains($item) + { + return array_search($item,$this->_d,true)!==false; + } + + /** + * Returns the item at the top of the queue. + * @return mixed item at the top of the queue + * @throws CException if the queue is empty + */ + public function peek() + { + if($this->_c===0) + throw new CException(Yii::t('yii','The queue is empty.')); + else + return $this->_d[0]; + } + + /** + * Removes and returns the object at the beginning of the queue. + * @return mixed the item at the beginning of the queue + * @throws CException if the queue is empty + */ + public function dequeue() + { + if($this->_c===0) + throw new CException(Yii::t('yii','The queue is empty.')); + else + { + --$this->_c; + return array_shift($this->_d); + } + } + + /** + * Adds an object to the end of the queue. + * @param mixed $item the item to be appended into the queue + */ + public function enqueue($item) + { + ++$this->_c; + array_push($this->_d,$item); + } + + /** + * Returns an iterator for traversing the items in the queue. + * This method is required by the interface IteratorAggregate. + * @return Iterator an iterator for traversing the items in the queue. + */ + public function getIterator() + { + return new CQueueIterator($this->_d); + } + + /** + * Returns the number of items in the queue. + * @return integer the number of items in the queue + */ + public function getCount() + { + return $this->_c; + } + + /** + * Returns the number of items in the queue. + * This method is required by Countable interface. + * @return integer number of items in the queue. + */ + public function count() + { + return $this->getCount(); + } +} diff --git a/framework/collections/CQueueIterator.php b/framework/collections/CQueueIterator.php new file mode 100644 index 0000000..bdcbdc0 --- /dev/null +++ b/framework/collections/CQueueIterator.php @@ -0,0 +1,94 @@ +<?php +/** + * CQueueIterator class file. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +/** + * CQueueIterator implements an interator for {@link CQueue}. + * + * It allows CQueue to return a new iterator for traversing the items in the queue. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id: CQueueIterator.php 2799 2011-01-01 19:31:13Z qiang.xue $ + * @package system.collections + * @since 1.0 + */ +class CQueueIterator implements Iterator +{ + /** + * @var array the data to be iterated through + */ + private $_d; + /** + * @var integer index of the current item + */ + private $_i; + /** + * @var integer count of the data items + */ + private $_c; + + /** + * Constructor. + * @param array $data the data to be iterated through + */ + public function __construct(&$data) + { + $this->_d=&$data; + $this->_i=0; + $this->_c=count($this->_d); + } + + /** + * Rewinds internal array pointer. + * This method is required by the interface Iterator. + */ + public function rewind() + { + $this->_i=0; + } + + /** + * Returns the key of the current array item. + * This method is required by the interface Iterator. + * @return integer the key of the current array item + */ + public function key() + { + return $this->_i; + } + + /** + * Returns the current array item. + * This method is required by the interface Iterator. + * @return mixed the current array item + */ + public function current() + { + return $this->_d[$this->_i]; + } + + /** + * Moves the internal pointer to the next array item. + * This method is required by the interface Iterator. + */ + public function next() + { + $this->_i++; + } + + /** + * Returns whether there is an item at current position. + * This method is required by the interface Iterator. + * @return boolean + */ + public function valid() + { + return $this->_i<$this->_c; + } +} diff --git a/framework/collections/CStack.php b/framework/collections/CStack.php new file mode 100644 index 0000000..4e51265 --- /dev/null +++ b/framework/collections/CStack.php @@ -0,0 +1,173 @@ +<?php +/** + * This file contains classes implementing the stack feature. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +/** + * CStack implements a stack. + * + * The typical stack operations are implemented, which include + * {@link push()}, {@link pop()} and {@link peek()}. In addition, + * {@link contains()} can be used to check if an item is contained + * in the stack. To obtain the number of the items in the stack, + * check the {@link getCount Count} property. + * + * Items in the stack may be traversed using foreach as follows, + * <pre> + * foreach($stack as $item) ... + * </pre> + * + * @property Iterator $iterator An iterator for traversing the items in the stack. + * @property integer $count The number of items in the stack. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id: CStack.php 3427 2011-10-25 00:03:52Z alexander.makarow $ + * @package system.collections + * @since 1.0 + */ +class CStack extends CComponent implements IteratorAggregate,Countable +{ + /** + * internal data storage + * @var array + */ + private $_d=array(); + /** + * number of items + * @var integer + */ + private $_c=0; + + /** + * Constructor. + * Initializes the stack with an array or an iterable object. + * @param array $data the initial data. Default is null, meaning no initialization. + * @throws CException If data is not null and neither an array nor an iterator. + */ + public function __construct($data=null) + { + if($data!==null) + $this->copyFrom($data); + } + + /** + * @return array the list of items in stack + */ + public function toArray() + { + return $this->_d; + } + + /** + * Copies iterable data into the stack. + * Note, existing data in the list will be cleared first. + * @param mixed $data the data to be copied from, must be an array or object implementing Traversable + * @throws CException If data is neither an array nor a Traversable. + */ + public function copyFrom($data) + { + if(is_array($data) || ($data instanceof Traversable)) + { + $this->clear(); + foreach($data as $item) + { + $this->_d[]=$item; + ++$this->_c; + } + } + else if($data!==null) + throw new CException(Yii::t('yii','Stack data must be an array or an object implementing Traversable.')); + } + + /** + * Removes all items in the stack. + */ + public function clear() + { + $this->_c=0; + $this->_d=array(); + } + + /** + * @param mixed $item the item + * @return boolean whether the stack contains the item + */ + public function contains($item) + { + return array_search($item,$this->_d,true)!==false; + } + + /** + * Returns the item at the top of the stack. + * Unlike {@link pop()}, this method does not remove the item from the stack. + * @return mixed item at the top of the stack + * @throws CException if the stack is empty + */ + public function peek() + { + if($this->_c) + return $this->_d[$this->_c-1]; + else + throw new CException(Yii::t('yii','The stack is empty.')); + } + + /** + * Pops up the item at the top of the stack. + * @return mixed the item at the top of the stack + * @throws CException if the stack is empty + */ + public function pop() + { + if($this->_c) + { + --$this->_c; + return array_pop($this->_d); + } + else + throw new CException(Yii::t('yii','The stack is empty.')); + } + + /** + * Pushes an item into the stack. + * @param mixed $item the item to be pushed into the stack + */ + public function push($item) + { + ++$this->_c; + array_push($this->_d,$item); + } + + /** + * Returns an iterator for traversing the items in the stack. + * This method is required by the interface IteratorAggregate. + * @return Iterator an iterator for traversing the items in the stack. + */ + public function getIterator() + { + return new CStackIterator($this->_d); + } + + /** + * Returns the number of items in the stack. + * @return integer the number of items in the stack + */ + public function getCount() + { + return $this->_c; + } + + /** + * Returns the number of items in the stack. + * This method is required by Countable interface. + * @return integer number of items in the stack. + */ + public function count() + { + return $this->getCount(); + } +} diff --git a/framework/collections/CStackIterator.php b/framework/collections/CStackIterator.php new file mode 100644 index 0000000..cefa933 --- /dev/null +++ b/framework/collections/CStackIterator.php @@ -0,0 +1,94 @@ +<?php +/** + * CStackIterator class file. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +/** + * CStackIterator implements an interator for {@link CStack}. + * + * It allows CStack to return a new iterator for traversing the items in the stack. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id: CStackIterator.php 2799 2011-01-01 19:31:13Z qiang.xue $ + * @package system.collections + * @since 1.0 + */ +class CStackIterator implements Iterator +{ + /** + * @var array the data to be iterated through + */ + private $_d; + /** + * @var integer index of the current item + */ + private $_i; + /** + * @var integer count of the data items + */ + private $_c; + + /** + * Constructor. + * @param array $data the data to be iterated through + */ + public function __construct(&$data) + { + $this->_d=&$data; + $this->_i=0; + $this->_c=count($this->_d); + } + + /** + * Rewinds internal array pointer. + * This method is required by the interface Iterator. + */ + public function rewind() + { + $this->_i=0; + } + + /** + * Returns the key of the current array item. + * This method is required by the interface Iterator. + * @return integer the key of the current array item + */ + public function key() + { + return $this->_i; + } + + /** + * Returns the current array item. + * This method is required by the interface Iterator. + * @return mixed the current array item + */ + public function current() + { + return $this->_d[$this->_i]; + } + + /** + * Moves the internal pointer to the next array item. + * This method is required by the interface Iterator. + */ + public function next() + { + $this->_i++; + } + + /** + * Returns whether there is an item at current position. + * This method is required by the interface Iterator. + * @return boolean + */ + public function valid() + { + return $this->_i<$this->_c; + } +} diff --git a/framework/collections/CTypedList.php b/framework/collections/CTypedList.php new file mode 100644 index 0000000..a8adaf7 --- /dev/null +++ b/framework/collections/CTypedList.php @@ -0,0 +1,52 @@ +<?php +/** + * This file contains CTypedList class. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +/** + * CTypedList represents a list whose items are of the certain type. + * + * CTypedList extends {@link CList} by making sure that the elements to be + * added to the list is of certain class type. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id: CTypedList.php 3001 2011-02-24 16:42:44Z alexander.makarow $ + * @package system.collections + * @since 1.0 + */ +class CTypedList extends CList +{ + private $_type; + + /** + * Constructor. + * @param string $type class type + */ + public function __construct($type) + { + $this->_type=$type; + } + + /** + * Inserts an item at the specified position. + * This method overrides the parent implementation by + * checking the item to be inserted is of certain type. + * @param integer $index the specified position. + * @param mixed $item new item + * @throws CException If the index specified exceeds the bound, + * the list is read-only or the element is not of the expected type. + */ + public function insertAt($index,$item) + { + if($item instanceof $this->_type) + parent::insertAt($index,$item); + else + throw new CException(Yii::t('yii','CTypedList<{type}> can only hold objects of {type} class.', + array('{type}'=>$this->_type))); + } +} diff --git a/framework/collections/CTypedMap.php b/framework/collections/CTypedMap.php new file mode 100644 index 0000000..12d043d --- /dev/null +++ b/framework/collections/CTypedMap.php @@ -0,0 +1,52 @@ +<?php +/** + * This file contains CTypedMap class. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.yiiframework.com/ + * @copyright Copyright © 2008-2011 Yii Software LLC + * @license http://www.yiiframework.com/license/ + */ + +/** + * CTypedMap represents a map whose items are of the certain type. + * + * CTypedMap extends {@link CMap} by making sure that the elements to be + * added to the list is of certain class type. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id: CTypedMap.php 3001 2011-02-24 16:42:44Z alexander.makarow $ + * @package system.collections + * @since 1.0 + */ +class CTypedMap extends CMap +{ + private $_type; + + /** + * Constructor. + * @param string $type class type + */ + public function __construct($type) + { + $this->_type=$type; + } + + /** + * Adds an item into the map. + * This method overrides the parent implementation by + * checking the item to be inserted is of certain type. + * @param integer $index the specified position. + * @param mixed $item new item + * @throws CException If the index specified exceeds the bound, + * the map is read-only or the element is not of the expected type. + */ + public function add($index,$item) + { + if($item instanceof $this->_type) + parent::add($index,$item); + else + throw new CException(Yii::t('yii','CTypedMap<{type}> can only hold objects of {type} class.', + array('{type}'=>$this->_type))); + } +} |
