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

ModuleDomainTrait::doRemoveActions()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 15
rs 9.2
cc 4
eloc 10
nc 6
nop 2
1
<?php
2
namespace keeko\core\domain\base;
3
4
use keeko\core\event\ModuleEvent;
5
use keeko\core\model\ActionQuery;
6
use keeko\core\model\ModuleQuery;
7
use keeko\core\model\Module;
8
use keeko\framework\domain\payload\Created;
9
use keeko\framework\domain\payload\Deleted;
10
use keeko\framework\domain\payload\Found;
11
use keeko\framework\domain\payload\NotDeleted;
12
use keeko\framework\domain\payload\NotFound;
13
use keeko\framework\domain\payload\NotUpdated;
14
use keeko\framework\domain\payload\NotValid;
15
use keeko\framework\domain\payload\PayloadInterface;
16
use keeko\framework\domain\payload\Updated;
17
use keeko\framework\exceptions\ErrorsException;
18
use keeko\framework\service\ServiceContainer;
19
use keeko\framework\utils\NameUtils;
20
use keeko\framework\utils\Parameters;
21
use phootwork\collection\Map;
22
23
/**
24
 */
25
trait ModuleDomainTrait {
26
27
	/**
28
	 */
29
	protected $pool;
30
31
	/**
32
	 * Adds Actions to Module
33
	 * 
34
	 * @param mixed $id
35
	 * @param mixed $data
36
	 * @return PayloadInterface
37
	 */
38
	public function addActions($id, $data) {
39
		// find
40
		$model = $this->get($id);
41
42
		if ($model === null) {
43
			return new NotFound(['message' => 'Module not found.']);
44
		}
45
46
		// pass add to internal logic
47
		try {
48
			$this->doAddActions($model, $data);
49
		} 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...
50
			return new NotValid(['errors' => $e->getErrors()]);
51
		}
52
53
		// save and dispatch events
54
		$event = new ModuleEvent($model);
55
		$this->dispatch(ModuleEvent::PRE_ACTIONS_ADD, $event);
56
		$this->dispatch(ModuleEvent::PRE_SAVE, $event);
57
		$rows = $model->save();
58
		$this->dispatch(ModuleEvent::POST_ACTIONS_ADD, $event);
59
		$this->dispatch(ModuleEvent::POST_SAVE, $event);
60
61
		if ($rows > 0) {
62
			return Updated(['model' => $model]);
63
		}
64
65
		return NotUpdated(['model' => $model]);
66
	}
67
68
	/**
69
	 * Creates a new Module with the provided data
70
	 * 
71
	 * @param mixed $data
72
	 * @return PayloadInterface
73
	 */
74
	public function create($data) {
75
		// hydrate
76
		$serializer = Module::getSerializer();
77
		$model = $serializer->hydrate(new Module(), $data);
78
		$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...
79
80
		// validate
81
		$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...
82
		if ($validator !== null && !$validator->validate($model)) {
83
			return new NotValid([
84
				'errors' => $validator->getValidationFailures()
85
			]);
86
		}
87
88
		// dispatch
89
		$event = new ModuleEvent($model);
90
		$this->dispatch(ModuleEvent::PRE_CREATE, $event);
91
		$this->dispatch(ModuleEvent::PRE_SAVE, $event);
92
		$model->save();
93
		$this->dispatch(ModuleEvent::POST_CREATE, $event);
94
		$this->dispatch(ModuleEvent::POST_SAVE, $event);
95
		return new Created(['model' => $model]);
96
	}
97
98
	/**
99
	 * Deletes a Module with the given id
100
	 * 
101
	 * @param mixed $id
102
	 * @return PayloadInterface
103
	 */
104
	public function delete($id) {
105
		// find
106
		$model = $this->get($id);
107
108
		if ($model === null) {
109
			return new NotFound(['message' => 'Module not found.']);
110
		}
111
112
		// delete
113
		$event = new ModuleEvent($model);
114
		$this->dispatch(ModuleEvent::PRE_DELETE, $event);
115
		$model->delete();
116
117
		if ($model->isDeleted()) {
118
			$this->dispatch(ModuleEvent::POST_DELETE, $event);
119
			return new Deleted(['model' => $model]);
120
		}
121
122
		return new NotDeleted(['message' => 'Could not delete Module']);
123
	}
124
125
	/**
126
	 * Returns a paginated result
127
	 * 
128
	 * @param Parameters $params
129
	 * @return PayloadInterface
130
	 */
131
	public function paginate(Parameters $params) {
132
		$sysPrefs = $this->getServiceContainer()->getPreferenceLoader()->getSystemPreferences();
133
		$defaultSize = $sysPrefs->getPaginationSize();
134
		$page = $params->getPage('number');
135
		$size = $params->getPage('size', $defaultSize);
136
137
		$query = ModuleQuery::create();
138
139
		// sorting
140
		$sort = $params->getSort(Module::getSerializer()->getSortFields());
141
		foreach ($sort as $field => $order) {
142
			$method = 'orderBy' . NameUtils::toStudlyCase($field);
143
			$query->$method($order);
144
		}
145
146
		// filtering
147
		$filter = $params->getFilter();
148
		if (!empty($filter)) {
149
			$this->applyFilter($query, $filter);
150
		}
151
152
		// paginate
153
		$model = $query->paginate($page, $size);
154
155
		// run response
156
		return new Found(['model' => $model]);
157
	}
158
159
	/**
160
	 * Returns one Module with the given id
161
	 * 
162
	 * @param mixed $id
163
	 * @return PayloadInterface
164
	 */
165
	public function read($id) {
166
		// read
167
		$model = $this->get($id);
168
169
		// check existence
170
		if ($model === null) {
171
			return new NotFound(['message' => 'Module not found.']);
172
		}
173
174
		return new Found(['model' => $model]);
175
	}
176
177
	/**
178
	 * Removes Actions from Module
179
	 * 
180
	 * @param mixed $id
181
	 * @param mixed $data
182
	 * @return PayloadInterface
183
	 */
184
	public function removeActions($id, $data) {
185
		// find
186
		$model = $this->get($id);
187
188
		if ($model === null) {
189
			return new NotFound(['message' => 'Module not found.']);
190
		}
191
192
		// pass remove to internal logic
193
		try {
194
			$this->doRemoveActions($model, $data);
195
		} 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...
196
			return new NotValid(['errors' => $e->getErrors()]);
197
		}
198
199
		// save and dispatch events
200
		$event = new ModuleEvent($model);
201
		$this->dispatch(ModuleEvent::PRE_ACTIONS_REMOVE, $event);
202
		$this->dispatch(ModuleEvent::PRE_SAVE, $event);
203
		$rows = $model->save();
204
		$this->dispatch(ModuleEvent::POST_ACTIONS_REMOVE, $event);
205
		$this->dispatch(ModuleEvent::POST_SAVE, $event);
206
207
		if ($rows > 0) {
208
			return Updated(['model' => $model]);
209
		}
210
211
		return NotUpdated(['model' => $model]);
212
	}
213
214
	/**
215
	 * Updates a Module with the given idand the provided data
216
	 * 
217
	 * @param mixed $id
218
	 * @param mixed $data
219
	 * @return PayloadInterface
220
	 */
221
	public function update($id, $data) {
222
		// find
223
		$model = $this->get($id);
224
225
		if ($model === null) {
226
			return new NotFound(['message' => 'Module not found.']);
227
		}
228
229
		// hydrate
230
		$serializer = Module::getSerializer();
231
		$model = $serializer->hydrate($model, $data);
232
		$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...
233
234
		// validate
235
		$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...
236
		if ($validator !== null && !$validator->validate($model)) {
237
			return new NotValid([
238
				'errors' => $validator->getValidationFailures()
239
			]);
240
		}
241
242
		// dispatch
243
		$event = new ModuleEvent($model);
244
		$this->dispatch(ModuleEvent::PRE_UPDATE, $event);
245
		$this->dispatch(ModuleEvent::PRE_SAVE, $event);
246
		$rows = $model->save();
247
		$this->dispatch(ModuleEvent::POST_UPDATE, $event);
248
		$this->dispatch(ModuleEvent::POST_SAVE, $event);
249
250
		$payload = ['model' => $model];
251
252
		if ($rows === 0) {
253
			return new NotUpdated($payload);
254
		}
255
256
		return new Updated($payload);
257
	}
258
259
	/**
260
	 * Updates Actions on Module
261
	 * 
262
	 * @param mixed $id
263
	 * @param mixed $data
264
	 * @return PayloadInterface
265
	 */
266
	public function updateActions($id, $data) {
267
		// find
268
		$model = $this->get($id);
269
270
		if ($model === null) {
271
			return new NotFound(['message' => 'Module not found.']);
272
		}
273
274
		// pass update to internal logic
275
		try {
276
			$this->doUpdateActions($model, $data);
277
		} 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...
278
			return new NotValid(['errors' => $e->getErrors()]);
279
		}
280
281
		// save and dispatch events
282
		$event = new ModuleEvent($model);
283
		$this->dispatch(ModuleEvent::PRE_ACTIONS_UPDATE, $event);
284
		$this->dispatch(ModuleEvent::PRE_SAVE, $event);
285
		$rows = $model->save();
286
		$this->dispatch(ModuleEvent::POST_ACTIONS_UPDATE, $event);
287
		$this->dispatch(ModuleEvent::POST_SAVE, $event);
288
289
		if ($rows > 0) {
290
			return Updated(['model' => $model]);
291
		}
292
293
		return NotUpdated(['model' => $model]);
294
	}
295
296
	/**
297
	 * @param mixed $query
298
	 * @param mixed $filter
299
	 * @return void
300
	 */
301
	protected function applyFilter($query, $filter) {
302
		foreach ($filter as $column => $value) {
303
			$pos = strpos($column, '.');
304
			if ($pos !== false) {
305
				$rel = NameUtils::toStudlyCase(substr($column, 0, $pos));
306
				$col = substr($column, $pos + 1);
307
				$method = 'use' . $rel . 'Query';
308
				if (method_exists($query, $method)) {
309
					$sub = $query->$method();
310
					$this->applyFilter($sub, [$col => $value]);
311
					$sub->endUse();
312
				}
313
			} else {
314
				$method = 'filterBy' . NameUtils::toStudlyCase($column);
315
				if (method_exists($query, $method)) {
316
					$query->$method($value);
317
				}
318
			}
319
		}
320
	}
321
322
	/**
323
	 * @param string $type
324
	 * @param ModuleEvent $event
325
	 */
326
	protected function dispatch($type, ModuleEvent $event) {
327
		$model = $event->getModule();
328
		$methods = [
329
			ModuleEvent::PRE_CREATE => 'preCreate',
330
			ModuleEvent::POST_CREATE => 'postCreate',
331
			ModuleEvent::PRE_UPDATE => 'preUpdate',
332
			ModuleEvent::POST_UPDATE => 'postUpdate',
333
			ModuleEvent::PRE_DELETE => 'preDelete',
334
			ModuleEvent::POST_DELETE => 'postDelete',
335
			ModuleEvent::PRE_SAVE => 'preSave',
336
			ModuleEvent::POST_SAVE => 'postSave'
337
		];
338
339
		if (isset($methods[$type])) {
340
			$method = $methods[$type];
341
			if (method_exists($this, $method)) {
342
				$this->$method($model);
343
			}
344
		}
345
346
		$dispatcher = $this->getServiceContainer()->getDispatcher();
347
		$dispatcher->dispatch($type, $event);
348
	}
349
350
	/**
351
	 * Interal mechanism to add Actions to Module
352
	 * 
353
	 * @param Module $model
354
	 * @param mixed $data
355
	 */
356
	protected function doAddActions(Module $model, $data) {
357
		$errors = [];
358
		foreach ($data as $entry) {
359
			if (!isset($entry['id'])) {
360
				$errors[] = 'Missing id for Action';
361
			} else {
362
				$related = ActionQuery::create()->findOneById($entry['id']);
363
				$model->addAction($related);
364
			}
365
		}
366
367
		if (count($errors) > 0) {
368
			return new ErrorsException($errors);
369
		}
370
	}
371
372
	/**
373
	 * Interal mechanism to remove Actions from Module
374
	 * 
375
	 * @param Module $model
376
	 * @param mixed $data
377
	 */
378
	protected function doRemoveActions(Module $model, $data) {
379
		$errors = [];
380
		foreach ($data as $entry) {
381
			if (!isset($entry['id'])) {
382
				$errors[] = 'Missing id for Action';
383
			} else {
384
				$related = ActionQuery::create()->findOneById($entry['id']);
385
				$model->removeAction($related);
386
			}
387
		}
388
389
		if (count($errors) > 0) {
390
			return new ErrorsException($errors);
391
		}
392
	}
393
394
	/**
395
	 * Internal update mechanism of Actions on Module
396
	 * 
397
	 * @param Module $model
398
	 * @param mixed $data
399
	 */
400
	protected function doUpdateActions(Module $model, $data) {
401
		// remove all relationships before
402
		ActionQuery::create()->filterByModule($model)->delete();
403
404
		// add them
405
		$errors = [];
406
		foreach ($data as $entry) {
407
			if (!isset($entry['id'])) {
408
				$errors[] = 'Missing id for Action';
409
			} else {
410
				$related = ActionQuery::create()->findOneById($entry['id']);
411
				$model->addAction($related);
412
			}
413
		}
414
415
		if (count($errors) > 0) {
416
			throw new ErrorsException($errors);
417
		}
418
	}
419
420
	/**
421
	 * Returns one Module with the given id from cache
422
	 * 
423
	 * @param mixed $id
424
	 * @return Module|null
425
	 */
426
	protected function get($id) {
427
		if ($this->pool === null) {
428
			$this->pool = new Map();
429
		} else if ($this->pool->has($id)) {
430
			return $this->pool->get($id);
431
		}
432
433
		$model = ModuleQuery::create()->findOneById($id);
434
		$this->pool->set($id, $model);
435
436
		return $model;
437
	}
438
439
	/**
440
	 * Returns the service container
441
	 * 
442
	 * @return ServiceContainer
443
	 */
444
	abstract protected function getServiceContainer();
445
}
446