Completed
Push — master ( 6c4e57...0b7137 )
by Peter
21:21
created

DataProvider::__construct()   C

Complexity

Conditions 7
Paths 33

Size

Total Lines 42
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 42
ccs 0
cts 28
cp 0
rs 6.7272
cc 7
eloc 21
nc 33
nop 2
crap 56
1
<?php
2
3
/**
4
 * This software package is licensed under AGPL or Commercial license.
5
 *
6
 * @package maslosoft/mangan
7
 * @licence AGPL or Commercial
8
 * @copyright Copyright (c) Piotr Masełkowski <[email protected]>
9
 * @copyright Copyright (c) Maslosoft
10
 * @copyright Copyright (c) Others as mentioned in code
11
 * @link http://maslosoft.com/mangan/
12
 */
13
14
namespace Maslosoft\Mangan;
15
16
use Maslosoft\Addendum\Interfaces\AnnotatedInterface;
17
use Maslosoft\Mangan\Exceptions\ManganException;
18
use Maslosoft\Mangan\Interfaces\Criteria\DecoratableInterface;
19
use Maslosoft\Mangan\Interfaces\Criteria\LimitableInterface;
20
use Maslosoft\Mangan\Interfaces\CriteriaInterface;
21
use Maslosoft\Mangan\Interfaces\DataProviderInterface;
22
use Maslosoft\Mangan\Interfaces\FinderInterface;
23
use Maslosoft\Mangan\Interfaces\PaginationInterface;
24
use Maslosoft\Mangan\Interfaces\SortInterface;
25
use Maslosoft\Mangan\Interfaces\WithCriteriaInterface;
26
use Maslosoft\Mangan\Meta\ManganMeta;
27
28
/**
29
 * Mongo document data provider
30
 *
31
 * Implements a data provider based on Document.
32
 *
33
 * DataProvider provides data in terms of Document objects which are
34
 * of class {@link modelClass}. It uses the AR {@link CActiveRecord::findAll} method
35
 * to retrieve the data from database. The {@link query} property can be used to
36
 * specify various query options, such as conditions, sorting, pagination, etc.
37
 *
38
 * @author Ianaré Sévi
39
 * @author Dariusz Górecki <[email protected]>
40
 * @author Invenzzia Group, open-source division of CleverIT company http://www.invenzzia.org
41
 * @copyright 2011 CleverIT http://www.cleverit.com.pl
42
 * @since v1.0
43
 */
44
class DataProvider implements DataProviderInterface
45
{
46
47
	/**
48
	 * Instance of model
49
	 * @var Document
50
	 * @since v1.0
51
	 */
52
	public $model;
53
54
	/**
55
	 * Finder instance
56
	 * @var FinderInterface
57
	 */
58
	private $finder = null;
59
60
	/**
61
	 * @var CriteriaInterface
62
	 */
63
	private $criteria;
64
65
	/**
66
	 * @var SortInterface
67
	 */
68
	private $sort;
69
	private $data = null;
70
	private $totalItemCount = null;
71
72
	/**
73
	 * Pagination instance
74
	 * @var PaginationInterface
75
	 */
76
	private $pagination = null;
77
78
	/**
79
	 * Constructor.
80
	 * @param mixed $modelClass the model class (e.g. 'Post') or the model finder instance
81
	 * (e.g. <code>Post::model()</code>, <code>Post::model()->published()</code>).
82
	 * @param array $config configuration (name=>value) to be applied as the initial property values of this class.
83
	 * @since v1.0
84
	 */
85
	public function __construct($modelClass, $config = [])
86
	{
87
		if (is_string($modelClass))
88
		{
89
			$this->model = new $modelClass;
90
		}
91
		elseif (is_object($modelClass))
92
		{
93
			$this->model = $modelClass;
94
		}
95
		else
96
		{
97
			throw new ManganException('Invalid model type for ' . __CLASS__);
98
		}
99
100
		$this->finder = Finder::create($this->model);
101
		if ($this->model instanceof WithCriteriaInterface)
102
		{
103
			$this->criteria = $this->model->getDbCriteria();
104
		}
105
		else
106
		{
107
			$this->criteria = new Criteria();
108
		}
109
		if (isset($config['criteria']))
110
		{
111
			$this->criteria->mergeWith($config['criteria']);
112
			unset($config['criteria']);
113
		}
114
115
		if (!$this->criteria->getSelect())
116
		{
117
			$fields = array_keys(ManganMeta::create($this->model)->fields());
118
			$fields = array_fill_keys($fields, true);
119
			$this->criteria->setSelect($fields);
120
		}
121
122
		foreach ($config as $key => $value)
123
		{
124
			$this->$key = $value;
125
		}
126
	}
127
128
	/**
129
	 * Get model used by this dataprovider
130
	 * @return AnnotatedInterface
131
	 */
132
	public function getModel()
133
	{
134
		return $this->model;
135
	}
136
137
	/**
138
	 * Returns the criteria.
139
	 * @return Criteria the query criteria
140
	 * @since v1.0
141
	 */
142
	public function getCriteria()
143
	{
144
		// Initialise empty criteria, so it's always available via this method call.
145
		if (empty($this->criteria))
146
		{
147
			$this->criteria = new Criteria;
148
		}
149
		return $this->criteria;
150
	}
151
152
	/**
153
	 * Sets the query criteria.
154
	 * @param CriteriaInterface|array $criteria the query criteria. Array representing the MongoDB query criteria.
155
	 * @since v1.0
156
	 */
157
	public function setCriteria($criteria)
158
	{
159
		if (is_array($criteria))
160
		{
161
			$this->criteria = new Criteria($criteria);
162
		}
163
		elseif ($criteria instanceof CriteriaInterface)
164
		{
165
			$this->criteria = $criteria;
166
		}
167
		if ($this->criteria instanceof DecoratableInterface)
168
		{
169
			$this->criteria->decorateWith($this->getModel());
170
		}
171
	}
172
173
	/**
174
	 * Returns the sort object.
175
	 * @return Sort the sorting object. If this is false, it means the sorting is disabled.
176
	 */
177
	public function getSort()
178
	{
179
		if ($this->sort === null)
180
		{
181
			$this->sort = new Sort;
182
			$this->sort->setModel($this->model);
183
		}
184
		return $this->sort;
185
	}
186
187
	/**
188
	 * Set sort
189
	 * @param SortInterface $sort
190
	 * @return DataProvider
191
	 */
192
	public function setSort(SortInterface $sort)
193
	{
194
		$this->sort = $sort;
195
		$this->sort->setModel($this->model);
196
		return $this;
197
	}
198
199
	/**
200
	 * Returns the pagination object.
201
	 * @param string $className the pagination object class name, use this param to override default pagination class.
202
	 * @return Pagination|false the pagination object. If this is false, it means the pagination is disabled.
203
	 */
204
	public function getPagination($className = Pagination::class)
205
	{
206
		if ($this->pagination === false)
207
		{
208
			return false;
209
		}
210
		if ($this->pagination === null)
211
		{
212
			$this->pagination = new $className;
213
		}
214
		return $this->pagination;
215
	}
216
217
	/**
218
	 * Returns the number of data items in the current page.
219
	 * This is equivalent to <code>count($provider->getData())</code>.
220
	 * When {@link pagination} is set false, this returns the same value as {@link totalItemCount}.
221
	 * @param boolean $refresh whether the number of data items should be re-calculated.
222
	 * @return integer the number of data items in the current page.
223
	 */
224
	public function getItemCount($refresh = false)
225
	{
226
		return count($this->getData($refresh));
227
	}
228
229
	/**
230
	 * Returns the total number of data items.
231
	 * When {@link pagination} is set false, this returns the same value as {@link itemCount}.
232
	 * @return integer total number of possible data items.
233
	 */
234
	public function getTotalItemCount()
235
	{
236
		if ($this->totalItemCount === null)
237
		{
238
			$this->totalItemCount = $this->finder->count($this->criteria);
239
		}
240
		return $this->totalItemCount;
241
	}
242
243
	/**
244
	 * Fetches the data from the persistent data storage.
245
	 * @return Document[]|Cursor list of data items
246
	 * @since v1.0
247
	 */
248
	protected function fetchData()
249
	{
250
		$pagination = $this->getPagination();
251
		if ($pagination !== false && $this->criteria instanceof LimitableInterface)
252
		{
253
			$pagination->setCount($this->getTotalItemCount());
254
			$pagination->apply($this->criteria);
255
		}
256
257
		$sort = $this->getSort();
258
		if ($sort->isSorted())
259
		{
260
			$this->criteria->setSort($sort);
261
		}
262
263
		return $this->finder->findAll($this->criteria);
264
	}
265
266
	/**
267
	 * Returns the data items currently available, ensures that result is at leas empty array
268
	 * @param boolean $refresh whether the data should be re-fetched from persistent storage.
269
	 * @return array the list of data items currently available in this data provider.
270
	 */
271
	public function getData($refresh = false)
272
	{
273
		if ($this->data === null || $refresh)
274
		{
275
			$this->data = $this->fetchData();
276
		}
277
		if ($this->data === null)
278
		{
279
			return [];
280
		}
281
		return $this->data;
282
	}
283
284
}
285