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

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