1: <?php
2: /**
3: * CArrayDataProvider class file.
4: *
5: * @author Qiang Xue <qiang.xue@gmail.com>
6: * @link http://www.yiiframework.com/
7: * @copyright 2008-2013 Yii Software LLC
8: * @license http://www.yiiframework.com/license/
9: */
10:
11: /**
12: * CArrayDataProvider implements a data provider based on a raw data array.
13: *
14: * The {@link rawData} property contains all data that may be sorted and/or paginated.
15: * CArrayDataProvider will supply the data after sorting and/or pagination.
16: * You may configure the {@link sort} and {@link pagination} properties to
17: * customize sorting and pagination behaviors.
18: *
19: * Elements in the raw data array may be either objects (e.g. model objects)
20: * or associative arrays (e.g. query results of DAO).
21: * Make sure to set the {@link keyField} property to the name of the field that uniquely
22: * identifies a data record or false if you do not have such a field.
23: *
24: * CArrayDataProvider may be used in the following way:
25: * <pre>
26: * $rawData=Yii::app()->db->createCommand('SELECT * FROM tbl_user')->queryAll();
27: * // or using: $rawData=User::model()->findAll();
28: * $dataProvider=new CArrayDataProvider($rawData, array(
29: * 'id'=>'user',
30: * 'sort'=>array(
31: * 'attributes'=>array(
32: * 'id', 'username', 'email',
33: * ),
34: * ),
35: * 'pagination'=>array(
36: * 'pageSize'=>10,
37: * ),
38: * ));
39: * // $dataProvider->getData() will return a list of arrays.
40: * </pre>
41: *
42: * Note: if you want to use the sorting feature, you must configure {@link sort} property
43: * so that the provider knows which columns can be sorted.
44: *
45: * @author Qiang Xue <qiang.xue@gmail.com>
46: * @package system.web
47: * @since 1.1.4
48: */
49: class CArrayDataProvider extends CDataProvider
50: {
51: /**
52: * @var string the name of the key field. This is a field that uniquely identifies a
53: * data record. In database this would be the primary key.
54: * Defaults to 'id'. If it's set to false, keys of {@link rawData} array are used.
55: */
56: public $keyField='id';
57: /**
58: * @var array the data that is not paginated or sorted. When pagination is enabled,
59: * this property usually contains more elements than {@link data}.
60: * The array elements must use zero-based integer keys.
61: */
62: public $rawData=array();
63: /**
64: * @var boolean controls how sorting works. True value means that case will be
65: * taken into account. False value will lead to the case insensitive sort. Default
66: * value is true.
67: * @since 1.1.13
68: */
69: public $caseSensitiveSort=true;
70:
71: /**
72: * Constructor.
73: * @param array $rawData the data that is not paginated or sorted. The array elements must use zero-based integer keys.
74: * @param array $config configuration (name=>value) to be applied as the initial property values of this class.
75: */
76: public function __construct($rawData,$config=array())
77: {
78: $this->rawData=$rawData;
79: foreach($config as $key=>$value)
80: $this->$key=$value;
81: }
82:
83: /**
84: * Fetches the data from the persistent data storage.
85: * @return array list of data items
86: */
87: protected function fetchData()
88: {
89: if(($sort=$this->getSort())!==false && ($order=$sort->getOrderBy())!='')
90: $this->sortData($this->getSortDirections($order));
91:
92: if(($pagination=$this->getPagination())!==false)
93: {
94: $pagination->setItemCount($this->getTotalItemCount());
95: return array_slice($this->rawData, $pagination->getOffset(), $pagination->getLimit());
96: }
97: else
98: return $this->rawData;
99: }
100:
101: /**
102: * Fetches the data item keys from the persistent data storage.
103: * @return array list of data item keys.
104: */
105: protected function fetchKeys()
106: {
107: if($this->keyField===false)
108: return array_keys($this->rawData);
109: $keys=array();
110: foreach($this->getData() as $i=>$data)
111: $keys[$i]=is_object($data) ? $data->{$this->keyField} : $data[$this->keyField];
112: return $keys;
113: }
114:
115: /**
116: * Calculates the total number of data items.
117: * This method simply returns the number of elements in {@link rawData}.
118: * @return integer the total number of data items.
119: */
120: protected function calculateTotalItemCount()
121: {
122: return count($this->rawData);
123: }
124:
125: /**
126: * Sorts the raw data according to the specified sorting instructions.
127: * After calling this method, {@link rawData} will be modified.
128: * @param array $directions the sorting directions (field name => whether it is descending sort)
129: */
130: protected function sortData($directions)
131: {
132: if(empty($directions))
133: return;
134: $args=array();
135: $dummy=array();
136: foreach($directions as $name=>$descending)
137: {
138: $column=array();
139: $fields_array=preg_split('/\.+/',$name,-1,PREG_SPLIT_NO_EMPTY);
140: foreach($this->rawData as $index=>$data)
141: $column[$index]=$this->getSortingFieldValue($data, $fields_array);
142: $args[]=&$column;
143: $dummy[]=&$column;
144: unset($column);
145: $direction=$descending ? SORT_DESC : SORT_ASC;
146: $args[]=&$direction;
147: $dummy[]=&$direction;
148: unset($direction);
149: }
150: $args[]=&$this->rawData;
151: call_user_func_array('array_multisort', $args);
152: }
153:
154: /**
155: * Get field for sorting, using dot like delimiter in query.
156: * @param mixed $data array or object
157: * @param array $fields sorting fields in $data
158: * @return mixed $data sorting field value
159: */
160: protected function getSortingFieldValue($data, $fields)
161: {
162: if(is_object($data))
163: {
164: foreach($fields as $field)
165: $data=isset($data->$field) ? $data->$field : null;
166: }
167: else
168: {
169: foreach($fields as $field)
170: $data=isset($data[$field]) ? $data[$field] : null;
171: }
172: return $this->caseSensitiveSort ? $data : mb_strtolower($data,Yii::app()->charset);
173: }
174:
175: /**
176: * Converts the "ORDER BY" clause into an array representing the sorting directions.
177: * @param string $order the "ORDER BY" clause.
178: * @return array the sorting directions (field name => whether it is descending sort)
179: */
180: protected function getSortDirections($order)
181: {
182: $segs=explode(',',$order);
183: $directions=array();
184: foreach($segs as $seg)
185: {
186: if(preg_match('/(.*?)(\s+(desc|asc))?$/i',trim($seg),$matches))
187: $directions[$matches[1]]=isset($matches[3]) && !strcasecmp($matches[3],'desc');
188: else
189: $directions[trim($seg)]=false;
190: }
191: return $directions;
192: }
193: }
194: