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

ActionDomainTrait::read()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 5
Bugs 0 Features 0
Metric Value
c 5
b 0
f 0
dl 0
loc 11
rs 9.4285
cc 2
eloc 5
nc 2
nop 1
1
<?php
2
namespace keeko\core\domain\base;
3
4
use keeko\core\event\ActionEvent;
5
use keeko\core\model\ActionQuery;
6
use keeko\core\model\Action;
7
use keeko\core\model\ApiQuery;
8
use keeko\core\model\GroupActionQuery;
9
use keeko\core\model\GroupQuery;
10
use keeko\framework\domain\payload\Created;
11
use keeko\framework\domain\payload\Deleted;
12
use keeko\framework\domain\payload\Found;
13
use keeko\framework\domain\payload\NotDeleted;
14
use keeko\framework\domain\payload\NotFound;
15
use keeko\framework\domain\payload\NotUpdated;
16
use keeko\framework\domain\payload\NotValid;
17
use keeko\framework\domain\payload\PayloadInterface;
18
use keeko\framework\domain\payload\Updated;
19
use keeko\framework\exceptions\ErrorsException;
20
use keeko\framework\service\ServiceContainer;
21
use keeko\framework\utils\NameUtils;
22
use keeko\framework\utils\Parameters;
23
use phootwork\collection\Map;
24
25
/**
26
 */
27
trait ActionDomainTrait {
28
29
	/**
30
	 */
31
	protected $pool;
32
33
	/**
34
	 * Adds Apis to Action
35
	 * 
36
	 * @param mixed $id
37
	 * @param mixed $data
38
	 * @return PayloadInterface
39
	 */
40
	public function addApis($id, $data) {
41
		// find
42
		$model = $this->get($id);
43
44
		if ($model === null) {
45
			return new NotFound(['message' => 'Action not found.']);
46
		}
47
48
		// pass add to internal logic
49
		try {
50
			$this->doAddApis($model, $data);
51
		} 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...
52
			return new NotValid(['errors' => $e->getErrors()]);
53
		}
54
55
		// save and dispatch events
56
		$event = new ActionEvent($model);
57
		$this->dispatch(ActionEvent::PRE_APIS_ADD, $event);
58
		$this->dispatch(ActionEvent::PRE_SAVE, $event);
59
		$rows = $model->save();
60
		$this->dispatch(ActionEvent::POST_APIS_ADD, $event);
61
		$this->dispatch(ActionEvent::POST_SAVE, $event);
62
63
		if ($rows > 0) {
64
			return Updated(['model' => $model]);
65
		}
66
67
		return NotUpdated(['model' => $model]);
68
	}
69
70
	/**
71
	 * Adds Groups to Action
72
	 * 
73
	 * @param mixed $id
74
	 * @param mixed $data
75
	 * @return PayloadInterface
76
	 */
77
	public function addGroups($id, $data) {
78
		// find
79
		$model = $this->get($id);
80
81
		if ($model === null) {
82
			return new NotFound(['message' => 'Action not found.']);
83
		}
84
85
		// pass add to internal logic
86
		try {
87
			$this->doAddGroups($model, $data);
88
		} 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...
89
			return new NotValid(['errors' => $e->getErrors()]);
90
		}
91
92
		// save and dispatch events
93
		$event = new ActionEvent($model);
94
		$this->dispatch(ActionEvent::PRE_GROUPS_ADD, $event);
95
		$this->dispatch(ActionEvent::PRE_SAVE, $event);
96
		$rows = $model->save();
97
		$this->dispatch(ActionEvent::POST_GROUPS_ADD, $event);
98
		$this->dispatch(ActionEvent::POST_SAVE, $event);
99
100
		if ($rows > 0) {
101
			return Updated(['model' => $model]);
102
		}
103
104
		return NotUpdated(['model' => $model]);
105
	}
106
107
	/**
108
	 * Creates a new Action with the provided data
109
	 * 
110
	 * @param mixed $data
111
	 * @return PayloadInterface
112
	 */
113
	public function create($data) {
114
		// hydrate
115
		$serializer = Action::getSerializer();
116
		$model = $serializer->hydrate(new Action(), $data);
117
		$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...
118
119
		// validate
120
		$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...
121
		if ($validator !== null && !$validator->validate($model)) {
122
			return new NotValid([
123
				'errors' => $validator->getValidationFailures()
124
			]);
125
		}
126
127
		// dispatch
128
		$event = new ActionEvent($model);
129
		$this->dispatch(ActionEvent::PRE_CREATE, $event);
130
		$this->dispatch(ActionEvent::PRE_SAVE, $event);
131
		$model->save();
132
		$this->dispatch(ActionEvent::POST_CREATE, $event);
133
		$this->dispatch(ActionEvent::POST_SAVE, $event);
134
		return new Created(['model' => $model]);
135
	}
136
137
	/**
138
	 * Deletes a Action with the given id
139
	 * 
140
	 * @param mixed $id
141
	 * @return PayloadInterface
142
	 */
143
	public function delete($id) {
144
		// find
145
		$model = $this->get($id);
146
147
		if ($model === null) {
148
			return new NotFound(['message' => 'Action not found.']);
149
		}
150
151
		// delete
152
		$event = new ActionEvent($model);
153
		$this->dispatch(ActionEvent::PRE_DELETE, $event);
154
		$model->delete();
155
156
		if ($model->isDeleted()) {
157
			$this->dispatch(ActionEvent::POST_DELETE, $event);
158
			return new Deleted(['model' => $model]);
159
		}
160
161
		return new NotDeleted(['message' => 'Could not delete Action']);
162
	}
163
164
	/**
165
	 * Returns a paginated result
166
	 * 
167
	 * @param Parameters $params
168
	 * @return PayloadInterface
169
	 */
170
	public function paginate(Parameters $params) {
171
		$sysPrefs = $this->getServiceContainer()->getPreferenceLoader()->getSystemPreferences();
172
		$defaultSize = $sysPrefs->getPaginationSize();
173
		$page = $params->getPage('number');
174
		$size = $params->getPage('size', $defaultSize);
175
176
		$query = ActionQuery::create();
177
178
		// sorting
179
		$sort = $params->getSort(Action::getSerializer()->getSortFields());
180
		foreach ($sort as $field => $order) {
181
			$method = 'orderBy' . NameUtils::toStudlyCase($field);
182
			$query->$method($order);
183
		}
184
185
		// filtering
186
		$filter = $params->getFilter();
187
		if (!empty($filter)) {
188
			$this->applyFilter($query, $filter);
189
		}
190
191
		// paginate
192
		$model = $query->paginate($page, $size);
193
194
		// run response
195
		return new Found(['model' => $model]);
196
	}
197
198
	/**
199
	 * Returns one Action with the given id
200
	 * 
201
	 * @param mixed $id
202
	 * @return PayloadInterface
203
	 */
204
	public function read($id) {
205
		// read
206
		$model = $this->get($id);
207
208
		// check existence
209
		if ($model === null) {
210
			return new NotFound(['message' => 'Action not found.']);
211
		}
212
213
		return new Found(['model' => $model]);
214
	}
215
216
	/**
217
	 * Removes Apis from Action
218
	 * 
219
	 * @param mixed $id
220
	 * @param mixed $data
221
	 * @return PayloadInterface
222
	 */
223
	public function removeApis($id, $data) {
224
		// find
225
		$model = $this->get($id);
226
227
		if ($model === null) {
228
			return new NotFound(['message' => 'Action not found.']);
229
		}
230
231
		// pass remove to internal logic
232
		try {
233
			$this->doRemoveApis($model, $data);
234
		} 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...
235
			return new NotValid(['errors' => $e->getErrors()]);
236
		}
237
238
		// save and dispatch events
239
		$event = new ActionEvent($model);
240
		$this->dispatch(ActionEvent::PRE_APIS_REMOVE, $event);
241
		$this->dispatch(ActionEvent::PRE_SAVE, $event);
242
		$rows = $model->save();
243
		$this->dispatch(ActionEvent::POST_APIS_REMOVE, $event);
244
		$this->dispatch(ActionEvent::POST_SAVE, $event);
245
246
		if ($rows > 0) {
247
			return Updated(['model' => $model]);
248
		}
249
250
		return NotUpdated(['model' => $model]);
251
	}
252
253
	/**
254
	 * Removes Groups from Action
255
	 * 
256
	 * @param mixed $id
257
	 * @param mixed $data
258
	 * @return PayloadInterface
259
	 */
260
	public function removeGroups($id, $data) {
261
		// find
262
		$model = $this->get($id);
263
264
		if ($model === null) {
265
			return new NotFound(['message' => 'Action not found.']);
266
		}
267
268
		// pass remove to internal logic
269
		try {
270
			$this->doRemoveGroups($model, $data);
271
		} 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...
272
			return new NotValid(['errors' => $e->getErrors()]);
273
		}
274
275
		// save and dispatch events
276
		$event = new ActionEvent($model);
277
		$this->dispatch(ActionEvent::PRE_GROUPS_REMOVE, $event);
278
		$this->dispatch(ActionEvent::PRE_SAVE, $event);
279
		$rows = $model->save();
280
		$this->dispatch(ActionEvent::POST_GROUPS_REMOVE, $event);
281
		$this->dispatch(ActionEvent::POST_SAVE, $event);
282
283
		if ($rows > 0) {
284
			return Updated(['model' => $model]);
285
		}
286
287
		return NotUpdated(['model' => $model]);
288
	}
289
290
	/**
291
	 * Sets the Module id
292
	 * 
293
	 * @param mixed $id
294
	 * @param mixed $relatedId
295
	 * @return PayloadInterface
296
	 */
297
	public function setModuleId($id, $relatedId) {
298
		// find
299
		$model = $this->get($id);
300
301
		if ($model === null) {
302
			return new NotFound(['message' => 'Action not found.']);
303
		}
304
305
		// update
306
		if ($this->doSetModuleId($model, $relatedId)) {
307
			$event = new ActionEvent($model);
308
			$this->dispatch(ActionEvent::PRE_MODULE_UPDATE, $event);
309
			$this->dispatch(ActionEvent::PRE_SAVE, $event);
310
			$model->save();
311
			$this->dispatch(ActionEvent::POST_MODULE_UPDATE, $event);
312
			$this->dispatch(ActionEvent::POST_SAVE, $event);
313
314
			return Updated(['model' => $model]);
315
		}
316
317
		return NotUpdated(['model' => $model]);
318
	}
319
320
	/**
321
	 * Updates a Action with the given idand the provided data
322
	 * 
323
	 * @param mixed $id
324
	 * @param mixed $data
325
	 * @return PayloadInterface
326
	 */
327
	public function update($id, $data) {
328
		// find
329
		$model = $this->get($id);
330
331
		if ($model === null) {
332
			return new NotFound(['message' => 'Action not found.']);
333
		}
334
335
		// hydrate
336
		$serializer = Action::getSerializer();
337
		$model = $serializer->hydrate($model, $data);
338
		$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...
339
340
		// validate
341
		$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...
342
		if ($validator !== null && !$validator->validate($model)) {
343
			return new NotValid([
344
				'errors' => $validator->getValidationFailures()
345
			]);
346
		}
347
348
		// dispatch
349
		$event = new ActionEvent($model);
350
		$this->dispatch(ActionEvent::PRE_UPDATE, $event);
351
		$this->dispatch(ActionEvent::PRE_SAVE, $event);
352
		$rows = $model->save();
353
		$this->dispatch(ActionEvent::POST_UPDATE, $event);
354
		$this->dispatch(ActionEvent::POST_SAVE, $event);
355
356
		$payload = ['model' => $model];
357
358
		if ($rows === 0) {
359
			return new NotUpdated($payload);
360
		}
361
362
		return new Updated($payload);
363
	}
364
365
	/**
366
	 * Updates Apis on Action
367
	 * 
368
	 * @param mixed $id
369
	 * @param mixed $data
370
	 * @return PayloadInterface
371
	 */
372
	public function updateApis($id, $data) {
373
		// find
374
		$model = $this->get($id);
375
376
		if ($model === null) {
377
			return new NotFound(['message' => 'Action not found.']);
378
		}
379
380
		// pass update to internal logic
381
		try {
382
			$this->doUpdateApis($model, $data);
383
		} 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...
384
			return new NotValid(['errors' => $e->getErrors()]);
385
		}
386
387
		// save and dispatch events
388
		$event = new ActionEvent($model);
389
		$this->dispatch(ActionEvent::PRE_APIS_UPDATE, $event);
390
		$this->dispatch(ActionEvent::PRE_SAVE, $event);
391
		$rows = $model->save();
392
		$this->dispatch(ActionEvent::POST_APIS_UPDATE, $event);
393
		$this->dispatch(ActionEvent::POST_SAVE, $event);
394
395
		if ($rows > 0) {
396
			return Updated(['model' => $model]);
397
		}
398
399
		return NotUpdated(['model' => $model]);
400
	}
401
402
	/**
403
	 * Updates Groups on Action
404
	 * 
405
	 * @param mixed $id
406
	 * @param mixed $data
407
	 * @return PayloadInterface
408
	 */
409
	public function updateGroups($id, $data) {
410
		// find
411
		$model = $this->get($id);
412
413
		if ($model === null) {
414
			return new NotFound(['message' => 'Action not found.']);
415
		}
416
417
		// pass update to internal logic
418
		try {
419
			$this->doUpdateGroups($model, $data);
420
		} 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...
421
			return new NotValid(['errors' => $e->getErrors()]);
422
		}
423
424
		// save and dispatch events
425
		$event = new ActionEvent($model);
426
		$this->dispatch(ActionEvent::PRE_GROUPS_UPDATE, $event);
427
		$this->dispatch(ActionEvent::PRE_SAVE, $event);
428
		$rows = $model->save();
429
		$this->dispatch(ActionEvent::POST_GROUPS_UPDATE, $event);
430
		$this->dispatch(ActionEvent::POST_SAVE, $event);
431
432
		if ($rows > 0) {
433
			return Updated(['model' => $model]);
434
		}
435
436
		return NotUpdated(['model' => $model]);
437
	}
438
439
	/**
440
	 * @param mixed $query
441
	 * @param mixed $filter
442
	 * @return void
443
	 */
444
	protected function applyFilter($query, $filter) {
445
		foreach ($filter as $column => $value) {
446
			$pos = strpos($column, '.');
447
			if ($pos !== false) {
448
				$rel = NameUtils::toStudlyCase(substr($column, 0, $pos));
449
				$col = substr($column, $pos + 1);
450
				$method = 'use' . $rel . 'Query';
451
				if (method_exists($query, $method)) {
452
					$sub = $query->$method();
453
					$this->applyFilter($sub, [$col => $value]);
454
					$sub->endUse();
455
				}
456
			} else {
457
				$method = 'filterBy' . NameUtils::toStudlyCase($column);
458
				if (method_exists($query, $method)) {
459
					$query->$method($value);
460
				}
461
			}
462
		}
463
	}
464
465
	/**
466
	 * @param string $type
467
	 * @param ActionEvent $event
468
	 */
469
	protected function dispatch($type, ActionEvent $event) {
470
		$model = $event->getAction();
471
		$methods = [
472
			ActionEvent::PRE_CREATE => 'preCreate',
473
			ActionEvent::POST_CREATE => 'postCreate',
474
			ActionEvent::PRE_UPDATE => 'preUpdate',
475
			ActionEvent::POST_UPDATE => 'postUpdate',
476
			ActionEvent::PRE_DELETE => 'preDelete',
477
			ActionEvent::POST_DELETE => 'postDelete',
478
			ActionEvent::PRE_SAVE => 'preSave',
479
			ActionEvent::POST_SAVE => 'postSave'
480
		];
481
482
		if (isset($methods[$type])) {
483
			$method = $methods[$type];
484
			if (method_exists($this, $method)) {
485
				$this->$method($model);
486
			}
487
		}
488
489
		$dispatcher = $this->getServiceContainer()->getDispatcher();
490
		$dispatcher->dispatch($type, $event);
491
	}
492
493
	/**
494
	 * Interal mechanism to add Apis to Action
495
	 * 
496
	 * @param Action $model
497
	 * @param mixed $data
498
	 */
499
	protected function doAddApis(Action $model, $data) {
500
		$errors = [];
501
		foreach ($data as $entry) {
502
			if (!isset($entry['id'])) {
503
				$errors[] = 'Missing id for Api';
504
			} else {
505
				$related = ApiQuery::create()->findOneById($entry['id']);
506
				$model->addApi($related);
507
			}
508
		}
509
510
		if (count($errors) > 0) {
511
			return new ErrorsException($errors);
512
		}
513
	}
514
515
	/**
516
	 * Interal mechanism to add Groups to Action
517
	 * 
518
	 * @param Action $model
519
	 * @param mixed $data
520
	 */
521
	protected function doAddGroups(Action $model, $data) {
522
		$errors = [];
523
		foreach ($data as $entry) {
524
			if (!isset($entry['id'])) {
525
				$errors[] = 'Missing id for Group';
526
			} else {
527
				$related = GroupQuery::create()->findOneById($entry['id']);
528
				$model->addGroup($related);
529
			}
530
		}
531
532
		if (count($errors) > 0) {
533
			return new ErrorsException($errors);
534
		}
535
	}
536
537
	/**
538
	 * Interal mechanism to remove Apis from Action
539
	 * 
540
	 * @param Action $model
541
	 * @param mixed $data
542
	 */
543
	protected function doRemoveApis(Action $model, $data) {
544
		$errors = [];
545
		foreach ($data as $entry) {
546
			if (!isset($entry['id'])) {
547
				$errors[] = 'Missing id for Api';
548
			} else {
549
				$related = ApiQuery::create()->findOneById($entry['id']);
550
				$model->removeApi($related);
551
			}
552
		}
553
554
		if (count($errors) > 0) {
555
			return new ErrorsException($errors);
556
		}
557
	}
558
559
	/**
560
	 * Interal mechanism to remove Groups from Action
561
	 * 
562
	 * @param Action $model
563
	 * @param mixed $data
564
	 */
565
	protected function doRemoveGroups(Action $model, $data) {
566
		$errors = [];
567
		foreach ($data as $entry) {
568
			if (!isset($entry['id'])) {
569
				$errors[] = 'Missing id for Group';
570
			} else {
571
				$related = GroupQuery::create()->findOneById($entry['id']);
572
				$model->removeGroup($related);
573
			}
574
		}
575
576
		if (count($errors) > 0) {
577
			return new ErrorsException($errors);
578
		}
579
	}
580
581
	/**
582
	 * Internal mechanism to set the Module id
583
	 * 
584
	 * @param Action $model
585
	 * @param mixed $relatedId
586
	 */
587
	protected function doSetModuleId(Action $model, $relatedId) {
588
		if ($model->getModuleId() !== $relatedId) {
589
			$model->setModuleId($relatedId);
590
591
			return true;
592
		}
593
594
		return false;
595
	}
596
597
	/**
598
	 * Internal update mechanism of Apis on Action
599
	 * 
600
	 * @param Action $model
601
	 * @param mixed $data
602
	 */
603
	protected function doUpdateApis(Action $model, $data) {
604
		// remove all relationships before
605
		ApiQuery::create()->filterByAction($model)->delete();
606
607
		// add them
608
		$errors = [];
609
		foreach ($data as $entry) {
610
			if (!isset($entry['id'])) {
611
				$errors[] = 'Missing id for Api';
612
			} else {
613
				$related = ApiQuery::create()->findOneById($entry['id']);
614
				$model->addApi($related);
615
			}
616
		}
617
618
		if (count($errors) > 0) {
619
			throw new ErrorsException($errors);
620
		}
621
	}
622
623
	/**
624
	 * Internal update mechanism of Groups on Action
625
	 * 
626
	 * @param Action $model
627
	 * @param mixed $data
628
	 */
629
	protected function doUpdateGroups(Action $model, $data) {
630
		// remove all relationships before
631
		GroupActionQuery::create()->filterByAction($model)->delete();
632
633
		// add them
634
		$errors = [];
635
		foreach ($data as $entry) {
636
			if (!isset($entry['id'])) {
637
				$errors[] = 'Missing id for Group';
638
			} else {
639
				$related = GroupQuery::create()->findOneById($entry['id']);
640
				$model->addGroup($related);
641
			}
642
		}
643
644
		if (count($errors) > 0) {
645
			throw new ErrorsException($errors);
646
		}
647
	}
648
649
	/**
650
	 * Returns one Action with the given id from cache
651
	 * 
652
	 * @param mixed $id
653
	 * @return Action|null
654
	 */
655
	protected function get($id) {
656
		if ($this->pool === null) {
657
			$this->pool = new Map();
658
		} else if ($this->pool->has($id)) {
659
			return $this->pool->get($id);
660
		}
661
662
		$model = ActionQuery::create()->findOneById($id);
663
		$this->pool->set($id, $model);
664
665
		return $model;
666
	}
667
668
	/**
669
	 * Returns the service container
670
	 * 
671
	 * @return ServiceContainer
672
	 */
673
	abstract protected function getServiceContainer();
674
}
675