1 <?php
2
3 /*
4 * This file is part of the Icybee package.
5 *
6 * (c) Olivier Laviale <olivier.laviale@gmail.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12 namespace Icybee\Modules\Views;
13
14 use ICanBoogie\ActiveRecord;
15 use ICanBoogie\ActiveRecord\Query;
16 use ICanBoogie\Event;
17
18 abstract class ActiveRecordProvider extends Provider
19 {
20 /**
21 * @return array[ActiveRecord]|ActiveRecord|null
22 */
23 public function __invoke()
24 {
25 $conditions = &$this->conditions;
26
27 $this->fire_alter_conditions
28 (
29 array
30 (
31 'conditions' => &$conditions,
32 'view' => $this->view,
33 'module' => $this->module
34 )
35 );
36
37 $query = $this->create_query();
38
39 $this->fire_alter_query
40 (
41 array
42 (
43 'query' => &$query,
44 'conditions' => &$conditions,
45 'view' => $this->view,
46 'module' => $this->module
47 )
48 );
49
50 $this->fire_alter_context
51 (
52 array
53 (
54 'context' => &$this->context,
55 'query' => &$query,
56 'conditions' => &$conditions,
57 'view' => $this->view,
58 'module' => $this->module
59 )
60 );
61
62 $rc = $this->extract_result($query);
63
64 new ActiveRecordProvider\AlterResultEvent
65 (
66 $this, array
67 (
68 'result' => &$rc,
69 'context' => &$this->context,
70 'query' => &$query,
71 'conditions' => &$conditions,
72 'view' => $this->view,
73 'module' => $this->module
74 )
75 );
76
77 return $rc;
78 }
79
80 /**
81 * Wraps a call to the {@link alter_conditions()} method with the
82 * {@link ActiveRecordProvider\BeforeAlterConditionsEvent} and
83 * {@link ActiveRecordProvider\AlterConditionsEvent} events.
84 *
85 * @param array $payload Event payload.
86 *
87 * @return array The altered conditions.
88 */
89 protected function fire_alter_conditions(array $payload)
90 {
91 new ActiveRecordProvider\BeforeAlterConditionsEvent($this, $payload);
92 $payload['conditions'] = $this->alter_conditions($payload['conditions']);
93 new ActiveRecordProvider\AlterConditionsEvent($this, $payload);
94
95 return $payload['conditions'];
96 }
97
98 /**
99 * Alters the activerecord query using the provided conditions.
100 *
101 * @param Query $query
102 * @param array $conditions
103 *
104 * @return Query
105 */
106 protected function alter_query(Query $query, array $conditions)
107 {
108 return $query;
109 }
110
111 /**
112 * Wraps a call to the {@link alter_query()} method with the
113 * {@link ActiveRecordProvider\BeforeAlterQueryEvent} and
114 * {@link ActiveRecordProvider\AlterQueryEvent} events.
115 *
116 * @param array $payload Event payload.
117 *
118 * @return array The altered query.
119 */
120 protected function fire_alter_query(array $payload)
121 {
122 new ActiveRecordProvider\BeforeAlterQueryEvent($this, $payload);
123 $payload['query'] = $this->alter_query($payload['query'], $payload['conditions']);
124 new ActiveRecordProvider\AlterQueryEvent($this, $payload);
125
126 return $payload['query'];
127 }
128
129 /**
130 * Wraps a call to the {@link alter_context()} method with the
131 * {@link ActiveRecordProvider\BeforeAlterContextEvent} and
132 * {@link ActiveRecordProvider\AlterContextEvent} events.
133 *
134 * @param array $payload Event payload.
135 *
136 * @return array The altered context.
137 */
138 protected function fire_alter_context(array $payload)
139 {
140 new ActiveRecordProvider\BeforeAlterContextEvent($this, $payload);
141 $payload['context'] = $this->alter_context($payload['context'], $payload['query'], $payload['conditions']);
142 new ActiveRecordProvider\AlterContextEvent($this, $payload);
143
144 return $payload['context'];
145 }
146
147 /**
148 * Create the activerecord query object.
149 *
150 * @return Query
151 */
152 protected function create_query()
153 {
154 return new Query($this->module->model);
155 }
156
157 protected function count_result(Query $query)
158 {
159 $range = $this->view->range;
160
161 $page = $range['page'];
162 $limit = $range['limit'];
163
164 $count = $query->count;
165
166 return $count;
167 }
168
169 protected function limit_result(Query $query, $limit, $page)
170 {
171 return $query->limit($page * $limit, $limit);
172 }
173
174 /**
175 * Extracts a result from the query.
176 *
177 * The returned result depends on the return type:
178 *
179 * - If the return type is {@link RETURNS_ONE} the first record is returned.
180 *
181 * - If the return type is {@link RETURNS_MANY} a number of records is returned according
182 * to the range limit and range page, the `count` value of the range is updated with the
183 * number of records matching the query. The {@link count_result()} method is used for this.
184 *
185 * - Otherwise, all the records matching the query are returned.
186 *
187 * @return ActiveRecord|array[ActiveRecord]|null If the provider must return one record,
188 * the method returns an ActiveRecord, or null if no record matching the conditions could be
189 * found, otherwise the method returns an array of ActiveRecord.
190 */
191 protected function extract_result(Query $query)
192 {
193 if ($this->returns == self::RETURNS_ONE)
194 {
195 return $query->one;
196 }
197 else if ($this->returns == self::RETURNS_MANY)
198 {
199 $range = &$this->view->range;
200 $range['count'] = $this->count_result($query);
201
202 $query = $this->limit_result($query, $range['limit'], $range['page']);
203 }
204
205 return $query->all;
206 }
207 }
208
209 namespace Icybee\Modules\Views\ActiveRecordProvider;
210
211 abstract class AlterEvent extends \ICanBoogie\Event
212 {
213 /**
214 * Reference to the conditions to alter.
215 *
216 * @var array
217 */
218 public $conditions;
219
220 /**
221 * The view invoked the provider.
222 *
223 * @var \Icybee\Modules\Views\View
224 */
225 public $view;
226
227 /**
228 * The module of the view.
229 *
230 * @var \ICanBoogie\Module
231 */
232 public $module;
233
234 /**
235 * Reference to the ActiveRecord query.
236 *
237 * @var \ICanBoogie\ActiveRecord\Query
238 */
239 public $query;
240
241 /**
242 * Reference to the rendering context.
243 *
244 * @var \BlueTihi\Context
245 */
246 public $context;
247
248 /**
249 * Reference to the result of the provider.
250 *
251 * @var mixed
252 */
253 public $result;
254 }
255
256 /**
257 * The event class for the `Icybee\Modules\Views\ActiveRecordProvider::alter_conditions:before` event.
258 */
259 class BeforeAlterConditionsEvent extends AlterEvent
260 {
261 /**
262 * The event is constructed with the type `alter_conditions:before`.
263 *
264 * @param Icybee\Modules\Views\ActiveRecordProvider $target
265 * @param array $payload
266 */
267 public function __construct(\Icybee\Modules\Views\ActiveRecordProvider $target, array $payload)
268 {
269 parent::__construct($target, 'alter_conditions:before', $payload);
270 }
271 }
272
273 /**
274 * The event class for the `Icybee\Modules\Views\ActiveRecordProvider::alter_conditions` event.
275 */
276 class AlterConditionsEvent extends AlterEvent
277 {
278 /**
279 * The event is constructed with the type `alter_conditions`.
280 *
281 * @param Icybee\Modules\Views\ActiveRecordProvider $target
282 * @param array $payload
283 */
284 public function __construct(\Icybee\Modules\Views\ActiveRecordProvider $target, array $payload)
285 {
286 parent::__construct($target, 'alter_conditions', $payload);
287 }
288 }
289
290 /**
291 * The event class for the `Icybee\Modules\Views\ActiveRecordProvider::alter_query:before` event.
292 */
293 class BeforeAlterQueryEvent extends AlterEvent
294 {
295 /**
296 * The event is constructed with the type `alter_query:before`.
297 *
298 * @param Icybee\Modules\Views\ActiveRecordProvider $target
299 * @param array $payload
300 */
301 public function __construct(\Icybee\Modules\Views\ActiveRecordProvider $target, array $payload)
302 {
303 parent::__construct($target, 'alter_query:before', $payload);
304 }
305 }
306
307 /**
308 * The event class for the `Icybee\Modules\Views\ActiveRecordProvider::alter_query` event.
309 */
310 class AlterQueryEvent extends AlterEvent
311 {
312 /**
313 * The event is constructed with the type `alter_query`.
314 *
315 * @param Icybee\Modules\Views\ActiveRecordProvider $target
316 * @param array $payload
317 */
318 public function __construct(\Icybee\Modules\Views\ActiveRecordProvider $target, array $payload)
319 {
320 parent::__construct($target, 'alter_query', $payload);
321 }
322 }
323
324 /**
325 * The event class for the `Icybee\Modules\Views\ActiveRecordProvider::alter_context:before` event.
326 */
327 class BeforeAlterContextEvent extends AlterEvent
328 {
329 /**
330 * The event is constructed with the type `alter_context:before`.
331 *
332 * @param Icybee\Modules\Views\ActiveRecordProvider $target
333 * @param array $payload
334 */
335 public function __construct(\Icybee\Modules\Views\ActiveRecordProvider $target, array $payload)
336 {
337 parent::__construct($target, 'alter_context:before', $payload);
338 }
339 }
340
341 /**
342 * The event class for the `Icybee\Modules\Views\ActiveRecordProvider::alter_context` event.
343 */
344 class AlterContextEvent extends AlterEvent
345 {
346 /**
347 * The event is constructed with the type `alter_context`.
348 *
349 * @param Icybee\Modules\Views\ActiveRecordProvider $target
350 * @param array $payload
351 */
352 public function __construct(\Icybee\Modules\Views\ActiveRecordProvider $target, array $payload)
353 {
354 parent::__construct($target, 'alter_context', $payload);
355 }
356 }
357
358 /**
359 * The event class for the `Icybee\Modules\Views\ActiveRecordProvider::alter_result` event.
360 */
361 class AlterResultEvent extends AlterEvent
362 {
363 /**
364 * The event is constructed with the type `alter_result`.
365 *
366 * @param \Icybee\Modules\Views\ActiveRecordProvider $target
367 * @param array $payload
368 */
369 public function __construct(\Icybee\Modules\Views\ActiveRecordProvider $target, array $payload)
370 {
371 parent::__construct($target, 'alter_result', $payload);
372 }
373 }