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

ApplicationDomainTrait::dispatch()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 23
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 23
rs 9.0856
cc 3
eloc 17
nc 3
nop 2
1
<?php
2
namespace keeko\core\domain\base;
3
4
use keeko\core\event\ApplicationEvent;
5
use keeko\core\model\ApplicationQuery;
6
use keeko\core\model\Application;
7
use keeko\core\model\ApplicationUriQuery;
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 ApplicationDomainTrait {
26
27
	/**
28
	 */
29
	protected $pool;
30
31
	/**
32
	 * Adds ApplicationUris to Application
33
	 * 
34
	 * @param mixed $id
35
	 * @param mixed $data
36
	 * @return PayloadInterface
37
	 */
38
	public function addApplicationUris($id, $data) {
39
		// find
40
		$model = $this->get($id);
41
42
		if ($model === null) {
43
			return new NotFound(['message' => 'Application not found.']);
44
		}
45
46
		// pass add to internal logic
47
		try {
48
			$this->doAddApplicationUris($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 ApplicationEvent($model);
55
		$this->dispatch(ApplicationEvent::PRE_APPLICATION_URIS_ADD, $event);
56
		$this->dispatch(ApplicationEvent::PRE_SAVE, $event);
57
		$rows = $model->save();
58
		$this->dispatch(ApplicationEvent::POST_APPLICATION_URIS_ADD, $event);
59
		$this->dispatch(ApplicationEvent::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 Application with the provided data
70
	 * 
71
	 * @param mixed $data
72
	 * @return PayloadInterface
73
	 */
74
	public function create($data) {
75
		// hydrate
76
		$serializer = Application::getSerializer();
77
		$model = $serializer->hydrate(new Application(), $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 ApplicationEvent($model);
90
		$this->dispatch(ApplicationEvent::PRE_CREATE, $event);
91
		$this->dispatch(ApplicationEvent::PRE_SAVE, $event);
92
		$model->save();
93
		$this->dispatch(ApplicationEvent::POST_CREATE, $event);
94
		$this->dispatch(ApplicationEvent::POST_SAVE, $event);
95
		return new Created(['model' => $model]);
96
	}
97
98
	/**
99
	 * Deletes a Application 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' => 'Application not found.']);
110
		}
111
112
		// delete
113
		$event = new ApplicationEvent($model);
114
		$this->dispatch(ApplicationEvent::PRE_DELETE, $event);
115
		$model->delete();
116
117
		if ($model->isDeleted()) {
118
			$this->dispatch(ApplicationEvent::POST_DELETE, $event);
119
			return new Deleted(['model' => $model]);
120
		}
121
122
		return new NotDeleted(['message' => 'Could not delete Application']);
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 = ApplicationQuery::create();
138
139
		// sorting
140
		$sort = $params->getSort(Application::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 Application 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' => 'Application not found.']);
172
		}
173
174
		return new Found(['model' => $model]);
175
	}
176
177
	/**
178
	 * Removes ApplicationUris from Application
179
	 * 
180
	 * @param mixed $id
181
	 * @param mixed $data
182
	 * @return PayloadInterface
183
	 */
184
	public function removeApplicationUris($id, $data) {
185
		// find
186
		$model = $this->get($id);
187
188
		if ($model === null) {
189
			return new NotFound(['message' => 'Application not found.']);
190
		}
191
192
		// pass remove to internal logic
193
		try {
194
			$this->doRemoveApplicationUris($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 ApplicationEvent($model);
201
		$this->dispatch(ApplicationEvent::PRE_APPLICATION_URIS_REMOVE, $event);
202
		$this->dispatch(ApplicationEvent::PRE_SAVE, $event);
203
		$rows = $model->save();
204
		$this->dispatch(ApplicationEvent::POST_APPLICATION_URIS_REMOVE, $event);
205
		$this->dispatch(ApplicationEvent::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 Application 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' => 'Application not found.']);
227
		}
228
229
		// hydrate
230
		$serializer = Application::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 ApplicationEvent($model);
244
		$this->dispatch(ApplicationEvent::PRE_UPDATE, $event);
245
		$this->dispatch(ApplicationEvent::PRE_SAVE, $event);
246
		$rows = $model->save();
247
		$this->dispatch(ApplicationEvent::POST_UPDATE, $event);
248
		$this->dispatch(ApplicationEvent::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 ApplicationUris on Application
261
	 * 
262
	 * @param mixed $id
263
	 * @param mixed $data
264
	 * @return PayloadInterface
265
	 */
266
	public function updateApplicationUris($id, $data) {
267
		// find
268
		$model = $this->get($id);
269
270
		if ($model === null) {
271
			return new NotFound(['message' => 'Application not found.']);
272
		}
273
274
		// pass update to internal logic
275
		try {
276
			$this->doUpdateApplicationUris($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 ApplicationEvent($model);
283
		$this->dispatch(ApplicationEvent::PRE_APPLICATION_URIS_UPDATE, $event);
284
		$this->dispatch(ApplicationEvent::PRE_SAVE, $event);
285
		$rows = $model->save();
286
		$this->dispatch(ApplicationEvent::POST_APPLICATION_URIS_UPDATE, $event);
287
		$this->dispatch(ApplicationEvent::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 ApplicationEvent $event
325
	 */
326
	protected function dispatch($type, ApplicationEvent $event) {
327
		$model = $event->getApplication();
328
		$methods = [
329
			ApplicationEvent::PRE_CREATE => 'preCreate',
330
			ApplicationEvent::POST_CREATE => 'postCreate',
331
			ApplicationEvent::PRE_UPDATE => 'preUpdate',
332
			ApplicationEvent::POST_UPDATE => 'postUpdate',
333
			ApplicationEvent::PRE_DELETE => 'preDelete',
334
			ApplicationEvent::POST_DELETE => 'postDelete',
335
			ApplicationEvent::PRE_SAVE => 'preSave',
336
			ApplicationEvent::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 ApplicationUris to Application
352
	 * 
353
	 * @param Application $model
354
	 * @param mixed $data
355
	 */
356
	protected function doAddApplicationUris(Application $model, $data) {
357
		$errors = [];
358
		foreach ($data as $entry) {
359
			if (!isset($entry['id'])) {
360
				$errors[] = 'Missing id for ApplicationUri';
361
			} else {
362
				$related = ApplicationUriQuery::create()->findOneById($entry['id']);
363
				$model->addApplicationUri($related);
364
			}
365
		}
366
367
		if (count($errors) > 0) {
368
			return new ErrorsException($errors);
369
		}
370
	}
371
372
	/**
373
	 * Interal mechanism to remove ApplicationUris from Application
374
	 * 
375
	 * @param Application $model
376
	 * @param mixed $data
377
	 */
378
	protected function doRemoveApplicationUris(Application $model, $data) {
379
		$errors = [];
380
		foreach ($data as $entry) {
381
			if (!isset($entry['id'])) {
382
				$errors[] = 'Missing id for ApplicationUri';
383
			} else {
384
				$related = ApplicationUriQuery::create()->findOneById($entry['id']);
385
				$model->removeApplicationUri($related);
386
			}
387
		}
388
389
		if (count($errors) > 0) {
390
			return new ErrorsException($errors);
391
		}
392
	}
393
394
	/**
395
	 * Internal update mechanism of ApplicationUris on Application
396
	 * 
397
	 * @param Application $model
398
	 * @param mixed $data
399
	 */
400
	protected function doUpdateApplicationUris(Application $model, $data) {
401
		// remove all relationships before
402
		ApplicationUriQuery::create()->filterByApplication($model)->delete();
403
404
		// add them
405
		$errors = [];
406
		foreach ($data as $entry) {
407
			if (!isset($entry['id'])) {
408
				$errors[] = 'Missing id for ApplicationUri';
409
			} else {
410
				$related = ApplicationUriQuery::create()->findOneById($entry['id']);
411
				$model->addApplicationUri($related);
412
			}
413
		}
414
415
		if (count($errors) > 0) {
416
			throw new ErrorsException($errors);
417
		}
418
	}
419
420
	/**
421
	 * Returns one Application with the given id from cache
422
	 * 
423
	 * @param mixed $id
424
	 * @return Application|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 = ApplicationQuery::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