Completed
Push — master ( e8b3d2...889b57 )
by Thomas
14:29
created

GroupDomainTrait::addActions()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 29
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 29
rs 8.5806
cc 4
eloc 17
nc 4
nop 2
1
<?php
2
namespace keeko\core\domain\base;
3
4
use keeko\core\event\GroupEvent;
5
use keeko\core\model\ActionQuery;
6
use keeko\core\model\GroupActionQuery;
7
use keeko\core\model\GroupQuery;
8
use keeko\core\model\Group;
9
use keeko\core\model\UserGroupQuery;
10
use keeko\core\model\UserQuery;
11
use keeko\framework\domain\payload\Created;
12
use keeko\framework\domain\payload\Deleted;
13
use keeko\framework\domain\payload\Found;
14
use keeko\framework\domain\payload\NotDeleted;
15
use keeko\framework\domain\payload\NotFound;
16
use keeko\framework\domain\payload\NotUpdated;
17
use keeko\framework\domain\payload\NotValid;
18
use keeko\framework\domain\payload\PayloadInterface;
19
use keeko\framework\domain\payload\Updated;
20
use keeko\framework\exceptions\ErrorsException;
21
use keeko\framework\service\ServiceContainer;
22
use keeko\framework\utils\NameUtils;
23
use keeko\framework\utils\Parameters;
24
use phootwork\collection\Map;
25
26
/**
27
 */
28
trait GroupDomainTrait {
29
30
	/**
31
	 */
32
	protected $pool;
33
34
	/**
35
	 * Adds Actions to Group
36
	 * 
37
	 * @param mixed $id
38
	 * @param mixed $data
39
	 * @return PayloadInterface
40
	 */
41
	public function addActions($id, $data) {
42
		// find
43
		$model = $this->get($id);
44
45
		if ($model === null) {
46
			return new NotFound(['message' => 'Group not found.']);
47
		}
48
49
		// pass add to internal logic
50
		try {
51
			$this->doAddActions($model, $data);
52
		} catch (ErrorsException $e) {
0 ignored issues
show
Bug introduced by
The class keeko\framework\exceptions\ErrorsException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
53
			return new NotValid(['errors' => $e->getErrors()]);
54
		}
55
56
		// save and dispatch events
57
		$event = new GroupEvent($model);
58
		$this->dispatch(GroupEvent::PRE_ACTIONS_ADD, $event);
59
		$this->dispatch(GroupEvent::PRE_SAVE, $event);
60
		$rows = $model->save();
61
		$this->dispatch(GroupEvent::POST_ACTIONS_ADD, $event);
62
		$this->dispatch(GroupEvent::POST_SAVE, $event);
63
64
		if ($rows > 0) {
65
			return Updated(['model' => $model]);
66
		}
67
68
		return NotUpdated(['model' => $model]);
69
	}
70
71
	/**
72
	 * Adds Users to Group
73
	 * 
74
	 * @param mixed $id
75
	 * @param mixed $data
76
	 * @return PayloadInterface
77
	 */
78
	public function addUsers($id, $data) {
79
		// find
80
		$model = $this->get($id);
81
82
		if ($model === null) {
83
			return new NotFound(['message' => 'Group not found.']);
84
		}
85
86
		// pass add to internal logic
87
		try {
88
			$this->doAddUsers($model, $data);
89
		} catch (ErrorsException $e) {
0 ignored issues
show
Bug introduced by
The class keeko\framework\exceptions\ErrorsException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
90
			return new NotValid(['errors' => $e->getErrors()]);
91
		}
92
93
		// save and dispatch events
94
		$event = new GroupEvent($model);
95
		$this->dispatch(GroupEvent::PRE_USERS_ADD, $event);
96
		$this->dispatch(GroupEvent::PRE_SAVE, $event);
97
		$rows = $model->save();
98
		$this->dispatch(GroupEvent::POST_USERS_ADD, $event);
99
		$this->dispatch(GroupEvent::POST_SAVE, $event);
100
101
		if ($rows > 0) {
102
			return Updated(['model' => $model]);
103
		}
104
105
		return NotUpdated(['model' => $model]);
106
	}
107
108
	/**
109
	 * Creates a new Group with the provided data
110
	 * 
111
	 * @param mixed $data
112
	 * @return PayloadInterface
113
	 */
114
	public function create($data) {
115
		// hydrate
116
		$serializer = Group::getSerializer();
117
		$model = $serializer->hydrate(new Group(), $data);
118
		$this->hydrateRelationships($model, $data);
0 ignored issues
show
Bug introduced by
It seems like hydrateRelationships() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
119
120
		// validate
121
		$validator = $this->getValidator();
0 ignored issues
show
Bug introduced by
It seems like getValidator() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
122
		if ($validator !== null && !$validator->validate($model)) {
123
			return new NotValid([
124
				'errors' => $validator->getValidationFailures()
125
			]);
126
		}
127
128
		// dispatch
129
		$event = new GroupEvent($model);
130
		$this->dispatch(GroupEvent::PRE_CREATE, $event);
131
		$this->dispatch(GroupEvent::PRE_SAVE, $event);
132
		$model->save();
133
		$this->dispatch(GroupEvent::POST_CREATE, $event);
134
		$this->dispatch(GroupEvent::POST_SAVE, $event);
135
		return new Created(['model' => $model]);
136
	}
137
138
	/**
139
	 * Deletes a Group with the given id
140
	 * 
141
	 * @param mixed $id
142
	 * @return PayloadInterface
143
	 */
144
	public function delete($id) {
145
		// find
146
		$model = $this->get($id);
147
148
		if ($model === null) {
149
			return new NotFound(['message' => 'Group not found.']);
150
		}
151
152
		// delete
153
		$event = new GroupEvent($model);
154
		$this->dispatch(GroupEvent::PRE_DELETE, $event);
155
		$model->delete();
156
157
		if ($model->isDeleted()) {
158
			$this->dispatch(GroupEvent::POST_DELETE, $event);
159
			return new Deleted(['model' => $model]);
160
		}
161
162
		return new NotDeleted(['message' => 'Could not delete Group']);
163
	}
164
165
	/**
166
	 * Returns a paginated result
167
	 * 
168
	 * @param Parameters $params
169
	 * @return PayloadInterface
170
	 */
171
	public function paginate(Parameters $params) {
172
		$sysPrefs = $this->getServiceContainer()->getPreferenceLoader()->getSystemPreferences();
173
		$defaultSize = $sysPrefs->getPaginationSize();
174
		$page = $params->getPage('number');
175
		$size = $params->getPage('size', $defaultSize);
176
177
		$query = GroupQuery::create();
178
179
		// sorting
180
		$sort = $params->getSort(Group::getSerializer()->getSortFields());
181
		foreach ($sort as $field => $order) {
182
			$method = 'orderBy' . NameUtils::toStudlyCase($field);
183
			$query->$method($order);
184
		}
185
186
		// filtering
187
		$filter = $params->getFilter();
188
		if (!empty($filter)) {
189
			$this->applyFilter($query, $filter);
190
		}
191
192
		// paginate
193
		$model = $query->paginate($page, $size);
194
195
		// run response
196
		return new Found(['model' => $model]);
197
	}
198
199
	/**
200
	 * Returns one Group with the given id
201
	 * 
202
	 * @param mixed $id
203
	 * @return PayloadInterface
204
	 */
205
	public function read($id) {
206
		// read
207
		$model = $this->get($id);
208
209
		// check existence
210
		if ($model === null) {
211
			return new NotFound(['message' => 'Group not found.']);
212
		}
213
214
		return new Found(['model' => $model]);
215
	}
216
217
	/**
218
	 * Removes Actions from Group
219
	 * 
220
	 * @param mixed $id
221
	 * @param mixed $data
222
	 * @return PayloadInterface
223
	 */
224
	public function removeActions($id, $data) {
225
		// find
226
		$model = $this->get($id);
227
228
		if ($model === null) {
229
			return new NotFound(['message' => 'Group not found.']);
230
		}
231
232
		// pass remove to internal logic
233
		try {
234
			$this->doRemoveActions($model, $data);
235
		} catch (ErrorsException $e) {
0 ignored issues
show
Bug introduced by
The class keeko\framework\exceptions\ErrorsException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
236
			return new NotValid(['errors' => $e->getErrors()]);
237
		}
238
239
		// save and dispatch events
240
		$event = new GroupEvent($model);
241
		$this->dispatch(GroupEvent::PRE_ACTIONS_REMOVE, $event);
242
		$this->dispatch(GroupEvent::PRE_SAVE, $event);
243
		$rows = $model->save();
244
		$this->dispatch(GroupEvent::POST_ACTIONS_REMOVE, $event);
245
		$this->dispatch(GroupEvent::POST_SAVE, $event);
246
247
		if ($rows > 0) {
248
			return Updated(['model' => $model]);
249
		}
250
251
		return NotUpdated(['model' => $model]);
252
	}
253
254
	/**
255
	 * Removes Users from Group
256
	 * 
257
	 * @param mixed $id
258
	 * @param mixed $data
259
	 * @return PayloadInterface
260
	 */
261
	public function removeUsers($id, $data) {
262
		// find
263
		$model = $this->get($id);
264
265
		if ($model === null) {
266
			return new NotFound(['message' => 'Group not found.']);
267
		}
268
269
		// pass remove to internal logic
270
		try {
271
			$this->doRemoveUsers($model, $data);
272
		} catch (ErrorsException $e) {
0 ignored issues
show
Bug introduced by
The class keeko\framework\exceptions\ErrorsException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
273
			return new NotValid(['errors' => $e->getErrors()]);
274
		}
275
276
		// save and dispatch events
277
		$event = new GroupEvent($model);
278
		$this->dispatch(GroupEvent::PRE_USERS_REMOVE, $event);
279
		$this->dispatch(GroupEvent::PRE_SAVE, $event);
280
		$rows = $model->save();
281
		$this->dispatch(GroupEvent::POST_USERS_REMOVE, $event);
282
		$this->dispatch(GroupEvent::POST_SAVE, $event);
283
284
		if ($rows > 0) {
285
			return Updated(['model' => $model]);
286
		}
287
288
		return NotUpdated(['model' => $model]);
289
	}
290
291
	/**
292
	 * Updates a Group with the given idand the provided data
293
	 * 
294
	 * @param mixed $id
295
	 * @param mixed $data
296
	 * @return PayloadInterface
297
	 */
298
	public function update($id, $data) {
299
		// find
300
		$model = $this->get($id);
301
302
		if ($model === null) {
303
			return new NotFound(['message' => 'Group not found.']);
304
		}
305
306
		// hydrate
307
		$serializer = Group::getSerializer();
308
		$model = $serializer->hydrate($model, $data);
309
		$this->hydrateRelationships($model, $data);
0 ignored issues
show
Bug introduced by
It seems like hydrateRelationships() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
310
311
		// validate
312
		$validator = $this->getValidator();
0 ignored issues
show
Bug introduced by
It seems like getValidator() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
313
		if ($validator !== null && !$validator->validate($model)) {
314
			return new NotValid([
315
				'errors' => $validator->getValidationFailures()
316
			]);
317
		}
318
319
		// dispatch
320
		$event = new GroupEvent($model);
321
		$this->dispatch(GroupEvent::PRE_UPDATE, $event);
322
		$this->dispatch(GroupEvent::PRE_SAVE, $event);
323
		$rows = $model->save();
324
		$this->dispatch(GroupEvent::POST_UPDATE, $event);
325
		$this->dispatch(GroupEvent::POST_SAVE, $event);
326
327
		$payload = ['model' => $model];
328
329
		if ($rows === 0) {
330
			return new NotUpdated($payload);
331
		}
332
333
		return new Updated($payload);
334
	}
335
336
	/**
337
	 * Updates Actions on Group
338
	 * 
339
	 * @param mixed $id
340
	 * @param mixed $data
341
	 * @return PayloadInterface
342
	 */
343
	public function updateActions($id, $data) {
344
		// find
345
		$model = $this->get($id);
346
347
		if ($model === null) {
348
			return new NotFound(['message' => 'Group not found.']);
349
		}
350
351
		// pass update to internal logic
352
		try {
353
			$this->doUpdateActions($model, $data);
354
		} catch (ErrorsException $e) {
0 ignored issues
show
Bug introduced by
The class keeko\framework\exceptions\ErrorsException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
355
			return new NotValid(['errors' => $e->getErrors()]);
356
		}
357
358
		// save and dispatch events
359
		$event = new GroupEvent($model);
360
		$this->dispatch(GroupEvent::PRE_ACTIONS_UPDATE, $event);
361
		$this->dispatch(GroupEvent::PRE_SAVE, $event);
362
		$rows = $model->save();
363
		$this->dispatch(GroupEvent::POST_ACTIONS_UPDATE, $event);
364
		$this->dispatch(GroupEvent::POST_SAVE, $event);
365
366
		if ($rows > 0) {
367
			return Updated(['model' => $model]);
368
		}
369
370
		return NotUpdated(['model' => $model]);
371
	}
372
373
	/**
374
	 * Updates Users on Group
375
	 * 
376
	 * @param mixed $id
377
	 * @param mixed $data
378
	 * @return PayloadInterface
379
	 */
380
	public function updateUsers($id, $data) {
381
		// find
382
		$model = $this->get($id);
383
384
		if ($model === null) {
385
			return new NotFound(['message' => 'Group not found.']);
386
		}
387
388
		// pass update to internal logic
389
		try {
390
			$this->doUpdateUsers($model, $data);
391
		} catch (ErrorsException $e) {
0 ignored issues
show
Bug introduced by
The class keeko\framework\exceptions\ErrorsException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
392
			return new NotValid(['errors' => $e->getErrors()]);
393
		}
394
395
		// save and dispatch events
396
		$event = new GroupEvent($model);
397
		$this->dispatch(GroupEvent::PRE_USERS_UPDATE, $event);
398
		$this->dispatch(GroupEvent::PRE_SAVE, $event);
399
		$rows = $model->save();
400
		$this->dispatch(GroupEvent::POST_USERS_UPDATE, $event);
401
		$this->dispatch(GroupEvent::POST_SAVE, $event);
402
403
		if ($rows > 0) {
404
			return Updated(['model' => $model]);
405
		}
406
407
		return NotUpdated(['model' => $model]);
408
	}
409
410
	/**
411
	 * @param mixed $query
412
	 * @param mixed $filter
413
	 * @return void
414
	 */
415
	protected function applyFilter($query, $filter) {
416
		foreach ($filter as $column => $value) {
417
			$pos = strpos($column, '.');
418
			if ($pos !== false) {
419
				$rel = NameUtils::toStudlyCase(substr($column, 0, $pos));
420
				$col = substr($column, $pos + 1);
421
				$method = 'use' . $rel . 'Query';
422
				if (method_exists($query, $method)) {
423
					$sub = $query->$method();
424
					$this->applyFilter($sub, [$col => $value]);
425
					$sub->endUse();
426
				}
427
			} else {
428
				$method = 'filterBy' . NameUtils::toStudlyCase($column);
429
				if (method_exists($query, $method)) {
430
					$query->$method($value);
431
				}
432
			}
433
		}
434
	}
435
436
	/**
437
	 * @param string $type
438
	 * @param GroupEvent $event
439
	 */
440
	protected function dispatch($type, GroupEvent $event) {
441
		$model = $event->getGroup();
442
		$methods = [
443
			GroupEvent::PRE_CREATE => 'preCreate',
444
			GroupEvent::POST_CREATE => 'postCreate',
445
			GroupEvent::PRE_UPDATE => 'preUpdate',
446
			GroupEvent::POST_UPDATE => 'postUpdate',
447
			GroupEvent::PRE_DELETE => 'preDelete',
448
			GroupEvent::POST_DELETE => 'postDelete',
449
			GroupEvent::PRE_SAVE => 'preSave',
450
			GroupEvent::POST_SAVE => 'postSave'
451
		];
452
453
		if (isset($methods[$type])) {
454
			$method = $methods[$type];
455
			if (method_exists($this, $method)) {
456
				$this->$method($model);
457
			}
458
		}
459
460
		$dispatcher = $this->getServiceContainer()->getDispatcher();
461
		$dispatcher->dispatch($type, $event);
462
	}
463
464
	/**
465
	 * Interal mechanism to add Actions to Group
466
	 * 
467
	 * @param Group $model
468
	 * @param mixed $data
469
	 */
470
	protected function doAddActions(Group $model, $data) {
471
		$errors = [];
472
		foreach ($data as $entry) {
473
			if (!isset($entry['id'])) {
474
				$errors[] = 'Missing id for Action';
475
			} else {
476
				$related = ActionQuery::create()->findOneById($entry['id']);
477
				$model->addAction($related);
478
			}
479
		}
480
481
		if (count($errors) > 0) {
482
			return new ErrorsException($errors);
483
		}
484
	}
485
486
	/**
487
	 * Interal mechanism to add Users to Group
488
	 * 
489
	 * @param Group $model
490
	 * @param mixed $data
491
	 */
492
	protected function doAddUsers(Group $model, $data) {
493
		$errors = [];
494
		foreach ($data as $entry) {
495
			if (!isset($entry['id'])) {
496
				$errors[] = 'Missing id for User';
497
			} else {
498
				$related = UserQuery::create()->findOneById($entry['id']);
499
				$model->addUser($related);
500
			}
501
		}
502
503
		if (count($errors) > 0) {
504
			return new ErrorsException($errors);
505
		}
506
	}
507
508
	/**
509
	 * Interal mechanism to remove Actions from Group
510
	 * 
511
	 * @param Group $model
512
	 * @param mixed $data
513
	 */
514
	protected function doRemoveActions(Group $model, $data) {
515
		$errors = [];
516
		foreach ($data as $entry) {
517
			if (!isset($entry['id'])) {
518
				$errors[] = 'Missing id for Action';
519
			} else {
520
				$related = ActionQuery::create()->findOneById($entry['id']);
521
				$model->removeAction($related);
522
			}
523
		}
524
525
		if (count($errors) > 0) {
526
			return new ErrorsException($errors);
527
		}
528
	}
529
530
	/**
531
	 * Interal mechanism to remove Users from Group
532
	 * 
533
	 * @param Group $model
534
	 * @param mixed $data
535
	 */
536
	protected function doRemoveUsers(Group $model, $data) {
537
		$errors = [];
538
		foreach ($data as $entry) {
539
			if (!isset($entry['id'])) {
540
				$errors[] = 'Missing id for User';
541
			} else {
542
				$related = UserQuery::create()->findOneById($entry['id']);
543
				$model->removeUser($related);
544
			}
545
		}
546
547
		if (count($errors) > 0) {
548
			return new ErrorsException($errors);
549
		}
550
	}
551
552
	/**
553
	 * Internal update mechanism of Actions on Group
554
	 * 
555
	 * @param Group $model
556
	 * @param mixed $data
557
	 */
558
	protected function doUpdateActions(Group $model, $data) {
559
		// remove all relationships before
560
		GroupActionQuery::create()->filterByGroup($model)->delete();
561
562
		// add them
563
		$errors = [];
564
		foreach ($data as $entry) {
565
			if (!isset($entry['id'])) {
566
				$errors[] = 'Missing id for Action';
567
			} else {
568
				$related = ActionQuery::create()->findOneById($entry['id']);
569
				$model->addAction($related);
570
			}
571
		}
572
573
		if (count($errors) > 0) {
574
			throw new ErrorsException($errors);
575
		}
576
	}
577
578
	/**
579
	 * Internal update mechanism of Users on Group
580
	 * 
581
	 * @param Group $model
582
	 * @param mixed $data
583
	 */
584
	protected function doUpdateUsers(Group $model, $data) {
585
		// remove all relationships before
586
		UserGroupQuery::create()->filterByGroup($model)->delete();
587
588
		// add them
589
		$errors = [];
590
		foreach ($data as $entry) {
591
			if (!isset($entry['id'])) {
592
				$errors[] = 'Missing id for User';
593
			} else {
594
				$related = UserQuery::create()->findOneById($entry['id']);
595
				$model->addUser($related);
596
			}
597
		}
598
599
		if (count($errors) > 0) {
600
			throw new ErrorsException($errors);
601
		}
602
	}
603
604
	/**
605
	 * Returns one Group with the given id from cache
606
	 * 
607
	 * @param mixed $id
608
	 * @return Group|null
609
	 */
610
	protected function get($id) {
611
		if ($this->pool === null) {
612
			$this->pool = new Map();
613
		} else if ($this->pool->has($id)) {
614
			return $this->pool->get($id);
615
		}
616
617
		$model = GroupQuery::create()->findOneById($id);
618
		$this->pool->set($id, $model);
619
620
		return $model;
621
	}
622
623
	/**
624
	 * Returns the service container
625
	 * 
626
	 * @return ServiceContainer
627
	 */
628
	abstract protected function getServiceContainer();
629
}
630