summaryrefslogtreecommitdiff
path: root/framework/collections
diff options
context:
space:
mode:
Diffstat (limited to 'framework/collections')
-rw-r--r--framework/collections/CAttributeCollection.php185
-rw-r--r--framework/collections/CConfiguration.php101
-rw-r--r--framework/collections/CList.php346
-rw-r--r--framework/collections/CListIterator.php94
-rw-r--r--framework/collections/CMap.php343
-rw-r--r--framework/collections/CMapIterator.php94
-rw-r--r--framework/collections/CQueue.php172
-rw-r--r--framework/collections/CQueueIterator.php94
-rw-r--r--framework/collections/CStack.php173
-rw-r--r--framework/collections/CStackIterator.php94
-rw-r--r--framework/collections/CTypedList.php52
-rw-r--r--framework/collections/CTypedMap.php52
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 &copy; 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 &copy; 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 &copy; 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 &copy; 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 &copy; 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 &copy; 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 &copy; 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 &copy; 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 &copy; 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 &copy; 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 &copy; 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 &copy; 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)));
+ }
+}