diff --git a/CHANGELOG b/CHANGELOG index df21f2fdc..85a52a22c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -34,7 +34,7 @@ Version 1.1.4 to be released - Chg: Replaced jQuery live() with delegate() in CHtml-generated js code (Qiang) - New: Upgraded JQuery UI to 1.8.2 (Sam Dark) - New: Upgraded code highlighter: added sh and VBScript, fixed comments in CSS and hex numbers in JavaScript (Sam Dark) -- New: Added CSqlDataProvider (Qiang) +- New: Added CSqlDataProvider and CArrayDataProvider (Qiang) Version 1.1.3 July 4, 2010 -------------------------- diff --git a/framework/YiiBase.php b/framework/YiiBase.php index 2bf1dc0ba..eda0f4106 100644 --- a/framework/YiiBase.php +++ b/framework/YiiBase.php @@ -636,6 +636,7 @@ class YiiBase 'CUrlValidator' => '/validators/CUrlValidator.php', 'CValidator' => '/validators/CValidator.php', 'CActiveDataProvider' => '/web/CActiveDataProvider.php', + 'CArrayDataProvider' => '/web/CArrayDataProvider.php', 'CAssetManager' => '/web/CAssetManager.php', 'CBaseController' => '/web/CBaseController.php', 'CCacheHttpSession' => '/web/CCacheHttpSession.php', diff --git a/framework/web/CArrayDataProvider.php b/framework/web/CArrayDataProvider.php new file mode 100644 index 000000000..c8d8ab84b --- /dev/null +++ b/framework/web/CArrayDataProvider.php @@ -0,0 +1,144 @@ + + * $rawData=Yii::app()->db->createCommand('SELECT * FROM tbl_user')->queryAll(); + * // or using: $rawData=User::model()->findAll(); + * $dataProvider=new CArrayDataProvider('user', $rawData, array( + * 'sort'=>array( + * 'attributes'=>array( + * 'id', 'username', 'email', + * ), + * ), + * 'pagination'=>array( + * 'pageSize'=>10, + * ), + * )); + * // $dataProvider->getData() will return a list of arrays. + * + * + * Note: if you want to use the sorting feature, you must configure {@link sort} property + * so that the provider knows which columns can be sorted. + * + * @author Qiang Xue + * @version $Id$ + * @package system.web + * @since 1.1.4 + */ +class CArrayDataProvider extends CDataProvider +{ + /** + * @var string the name of key field. Defaults to 'id'. + */ + public $keyField='id'; + /** + * @var array the data that is not paginated or sorted. When pagination is enabled, + * this property usually contains more elements than {@link data}. + */ + public $rawData=array(); + + /** + * Constructor. + * @param string the ID of the provider. This is mainly used to prefix the page and sort GET variables. + * @param array the data that is not paginated or sorted. + * @param array configuration (name=>value) to be applied as the initial property values of this class. + */ + public function __construct($id,$rawData,$config=array()) + { + $this->setId($id); + $this->rawData=$rawData; + foreach($config as $key=>$value) + $this->$key=$value; + } + + /** + * Fetches the data from the persistent data storage. + * @return array list of data items + */ + protected function fetchData() + { + if(($sort=$this->getSort())!==false && ($order=$sort->getOrderBy())!='') + $this->sortData($this->getSortDirections($order)); + + if(($pagination=$this->getPagination())!==false) + { + $pagination->setItemCount($this->getTotalItemCount()); + return array_slice($this->rawData, $pagination->getOffset(), $pagination->getLimit()); + } + else + return $this->rawData; + } + + /** + * Fetches the data item keys from the persistent data storage. + * @return array list of data item keys. + */ + protected function fetchKeys() + { + $keys=array(); + foreach($this->getData() as $i=>$data) + $keys[$i]=is_object($data) ? $data->{$this->keyField} : $data[$this->keyField]; + return $keys; + } + + /** + * Calculates the total number of data items. + * This method simply returns the number of elements in {@link rawData}. + * @return integer the total number of data items. + */ + protected function calculateTotalItemCount() + { + return count($this->rawData); + } + + /** + * Sorts the raw data according to the specified sorting instructions. + * After calling this method, {@link rawData} will be modified. + * @param array the sorting directions (field name => whether it is descending sort) + */ + protected function sortData($directions) + { + if(empty($directions)) + return; + $args=array(); + foreach($directions as $name=>$descending) + { + $column=array(); + foreach($this->rawData as $index=>$data) + $column[$index]=is_object($data) ? $data->$name : $data[$name]; + $args[]=$column; + $args[]=$descending ? SORT_DESC : SORT_ASC; + } + $args[]=&$this->rawData; + call_user_func_array('array_multisort', $args); + } + + /** + * Converts the "ORDER BY" clause into an array representing the sorting directions. + * @param string the "ORDER BY" clause. + * @return array the sorting directions (field name => whether it is descending sort) + */ + protected function getSortDirections($order) + { + $segs=explode(',',$order); + $directions=array(); + foreach($segs as $seg) + { + if(preg_match('/(.*?)(\s+(desc|asc))?$/i',trim($seg),$matches)) + $directions[$matches[1]]=isset($matches[3]) && !strcasecmp($matches[3],'desc'); + else + $directions[trim($seg)]=false; + } + return $directions; + } +} diff --git a/framework/web/CSqlDataProvider.php b/framework/web/CSqlDataProvider.php new file mode 100644 index 000000000..054c59a4f --- /dev/null +++ b/framework/web/CSqlDataProvider.php @@ -0,0 +1,134 @@ + + * $count=Yii::app()->db->createCommand('SELECT COUNT(*) FROM tbl_user')->queryScalar(); + * $sql='SELECT * FROM tbl_user'; + * $dataProvider=new CSqlDataProvider('user', $sql, array( + * 'totalItemCount'=>$count, + * 'sort'=>array( + * 'attributes'=>array( + * 'id', 'username', 'email', + * ), + * ), + * 'pagination'=>array( + * 'pageSize'=>10, + * ), + * )); + * // $dataProvider->getData() will return a list of arrays. + * + * + * Note: if you want to use the pagination feature, you must configure the {@link totalItemCount} property + * to be the total number of rows (without pagination). And if you want to use the sorting feature, + * you must configure {@link sort} property so that the provider knows which columns can be sorted. + * + * @author Qiang Xue + * @version $Id$ + * @package system.web + * @since 1.1.4 + */ +class CSqlDataProvider extends CDataProvider +{ + /** + * @var CDbConnection the database connection to be used in the queries. + * Defaults to null, meaning using Yii::app()->db. + */ + public $db; + /** + * @var string the SQL statement to be used for fetching data rows. + */ + public $sql; + /** + * @var array parameters (name=>value) to be bound to the SQL statement. + */ + public $params=array(); + /** + * @var string the name of key field. Defaults to 'id'. + */ + public $keyField='id'; + + /** + * Constructor. + * @param string the ID of the provider. This is mainly used to prefix the page and sort GET variables. + * @param string the SQL statement to be used for fetching data rows. + * @param array configuration (name=>value) to be applied as the initial property values of this class. + */ + public function __construct($id,$sql,$config=array()) + { + $this->setId($id); + $this->sql=$sql; + foreach($config as $key=>$value) + $this->$key=$value; + } + + /** + * Fetches the data from the persistent data storage. + * @return array list of data items + */ + protected function fetchData() + { + $sql=$this->sql; + $db=$this->db===null ? Yii::app()->db : $this->db; + $db->active=true; + + if(($sort=$this->getSort())!==false) + { + $order=$sort->getOrderBy(); + if(!empty($order)) + { + if(preg_match('/\s+order\s+by\s+/i',$sql)) + $sql.=', '.$order; + else + $sql.=' ORDER BY '.$order; + } + } + + if(($pagination=$this->getPagination())!==false) + { + $pagination->setItemCount($this->getTotalItemCount()); + $limit=$pagination->getLimit(); + $offset=$pagination->getOffset(); + $sql=$db->getCommandBuilder()->applyLimit($sql,$limit,$offset); + } + + $command=$db->createCommand($sql); + foreach($this->params as $name=>$value) + $command->bindValue($name,$value); + + return $command->queryAll(); + } + + /** + * Fetches the data item keys from the persistent data storage. + * @return array list of data item keys. + */ + protected function fetchKeys() + { + $keys=array(); + foreach($this->getData() as $i=>$data) + $keys[$i]=$data[$this->keyField]; + return $keys; + } + + /** + * Calculates the total number of data items. + * This method is invoked when {@link getTotalItemCount()} is invoked + * and {@link totalItemCount} is not set previously. + * The default implementation simply returns 0. + * You may override this method to return accurate total number of data items. + * @return integer the total number of data items. + */ + protected function calculateTotalItemCount() + { + return 0; + } +} diff --git a/framework/yiilite.php b/framework/yiilite.php index 64abdb2f7..5d26d93ac 100644 --- a/framework/yiilite.php +++ b/framework/yiilite.php @@ -394,6 +394,7 @@ class YiiBase 'CUrlValidator' => '/validators/CUrlValidator.php', 'CValidator' => '/validators/CValidator.php', 'CActiveDataProvider' => '/web/CActiveDataProvider.php', + 'CArrayDataProvider' => '/web/CArrayDataProvider.php', 'CAssetManager' => '/web/CAssetManager.php', 'CBaseController' => '/web/CBaseController.php', 'CCacheHttpSession' => '/web/CCacheHttpSession.php',