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

SessionDomainTrait::paginate()   B

Complexity

Conditions 3
Paths 4

Size

Total Lines 27
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 27
rs 8.8571
cc 3
eloc 15
nc 4
nop 1
1
<?php
2
namespace keeko\core\domain\base;
3
4
use keeko\core\event\SessionEvent;
5
use keeko\core\model\SessionQuery;
6
use keeko\core\model\Session;
7
use keeko\framework\domain\payload\Created;
8
use keeko\framework\domain\payload\Deleted;
9
use keeko\framework\domain\payload\Found;
10
use keeko\framework\domain\payload\NotDeleted;
11
use keeko\framework\domain\payload\NotFound;
12
use keeko\framework\domain\payload\NotUpdated;
13
use keeko\framework\domain\payload\NotValid;
14
use keeko\framework\domain\payload\PayloadInterface;
15
use keeko\framework\domain\payload\Updated;
16
use keeko\framework\service\ServiceContainer;
17
use keeko\framework\utils\NameUtils;
18
use keeko\framework\utils\Parameters;
19
use phootwork\collection\Map;
20
21
/**
22
 */
23
trait SessionDomainTrait {
24
25
	/**
26
	 */
27
	protected $pool;
28
29
	/**
30
	 * Creates a new Session with the provided data
31
	 * 
32
	 * @param mixed $data
33
	 * @return PayloadInterface
34
	 */
35
	public function create($data) {
36
		// hydrate
37
		$serializer = Session::getSerializer();
38
		$model = $serializer->hydrate(new Session(), $data);
39
		$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...
40
41
		// validate
42
		$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...
43
		if ($validator !== null && !$validator->validate($model)) {
44
			return new NotValid([
45
				'errors' => $validator->getValidationFailures()
46
			]);
47
		}
48
49
		// dispatch
50
		$event = new SessionEvent($model);
51
		$this->dispatch(SessionEvent::PRE_CREATE, $event);
52
		$this->dispatch(SessionEvent::PRE_SAVE, $event);
53
		$model->save();
54
		$this->dispatch(SessionEvent::POST_CREATE, $event);
55
		$this->dispatch(SessionEvent::POST_SAVE, $event);
56
		return new Created(['model' => $model]);
57
	}
58
59
	/**
60
	 * Deletes a Session with the given id
61
	 * 
62
	 * @param mixed $id
63
	 * @return PayloadInterface
64
	 */
65
	public function delete($id) {
66
		// find
67
		$model = $this->get($id);
68
69
		if ($model === null) {
70
			return new NotFound(['message' => 'Session not found.']);
71
		}
72
73
		// delete
74
		$event = new SessionEvent($model);
75
		$this->dispatch(SessionEvent::PRE_DELETE, $event);
76
		$model->delete();
77
78
		if ($model->isDeleted()) {
79
			$this->dispatch(SessionEvent::POST_DELETE, $event);
80
			return new Deleted(['model' => $model]);
81
		}
82
83
		return new NotDeleted(['message' => 'Could not delete Session']);
84
	}
85
86
	/**
87
	 * Returns a paginated result
88
	 * 
89
	 * @param Parameters $params
90
	 * @return PayloadInterface
91
	 */
92
	public function paginate(Parameters $params) {
93
		$sysPrefs = $this->getServiceContainer()->getPreferenceLoader()->getSystemPreferences();
94
		$defaultSize = $sysPrefs->getPaginationSize();
95
		$page = $params->getPage('number');
96
		$size = $params->getPage('size', $defaultSize);
97
98
		$query = SessionQuery::create();
99
100
		// sorting
101
		$sort = $params->getSort(Session::getSerializer()->getSortFields());
102
		foreach ($sort as $field => $order) {
103
			$method = 'orderBy' . NameUtils::toStudlyCase($field);
104
			$query->$method($order);
105
		}
106
107
		// filtering
108
		$filter = $params->getFilter();
109
		if (!empty($filter)) {
110
			$this->applyFilter($query, $filter);
111
		}
112
113
		// paginate
114
		$model = $query->paginate($page, $size);
115
116
		// run response
117
		return new Found(['model' => $model]);
118
	}
119
120
	/**
121
	 * Returns one Session with the given id
122
	 * 
123
	 * @param mixed $id
124
	 * @return PayloadInterface
125
	 */
126
	public function read($id) {
127
		// read
128
		$model = $this->get($id);
129
130
		// check existence
131
		if ($model === null) {
132
			return new NotFound(['message' => 'Session not found.']);
133
		}
134
135
		return new Found(['model' => $model]);
136
	}
137
138
	/**
139
	 * Sets the User id
140
	 * 
141
	 * @param mixed $id
142
	 * @param mixed $relatedId
143
	 * @return PayloadInterface
144
	 */
145
	public function setUserId($id, $relatedId) {
146
		// find
147
		$model = $this->get($id);
148
149
		if ($model === null) {
150
			return new NotFound(['message' => 'Session not found.']);
151
		}
152
153
		// update
154
		if ($this->doSetUserId($model, $relatedId)) {
155
			$event = new SessionEvent($model);
156
			$this->dispatch(SessionEvent::PRE_USER_UPDATE, $event);
157
			$this->dispatch(SessionEvent::PRE_SAVE, $event);
158
			$model->save();
159
			$this->dispatch(SessionEvent::POST_USER_UPDATE, $event);
160
			$this->dispatch(SessionEvent::POST_SAVE, $event);
161
162
			return Updated(['model' => $model]);
163
		}
164
165
		return NotUpdated(['model' => $model]);
166
	}
167
168
	/**
169
	 * Updates a Session with the given idand the provided data
170
	 * 
171
	 * @param mixed $id
172
	 * @param mixed $data
173
	 * @return PayloadInterface
174
	 */
175
	public function update($id, $data) {
176
		// find
177
		$model = $this->get($id);
178
179
		if ($model === null) {
180
			return new NotFound(['message' => 'Session not found.']);
181
		}
182
183
		// hydrate
184
		$serializer = Session::getSerializer();
185
		$model = $serializer->hydrate($model, $data);
186
		$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...
187
188
		// validate
189
		$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...
190
		if ($validator !== null && !$validator->validate($model)) {
191
			return new NotValid([
192
				'errors' => $validator->getValidationFailures()
193
			]);
194
		}
195
196
		// dispatch
197
		$event = new SessionEvent($model);
198
		$this->dispatch(SessionEvent::PRE_UPDATE, $event);
199
		$this->dispatch(SessionEvent::PRE_SAVE, $event);
200
		$rows = $model->save();
201
		$this->dispatch(SessionEvent::POST_UPDATE, $event);
202
		$this->dispatch(SessionEvent::POST_SAVE, $event);
203
204
		$payload = ['model' => $model];
205
206
		if ($rows === 0) {
207
			return new NotUpdated($payload);
208
		}
209
210
		return new Updated($payload);
211
	}
212
213
	/**
214
	 * @param mixed $query
215
	 * @param mixed $filter
216
	 * @return void
217
	 */
218
	protected function applyFilter($query, $filter) {
219
		foreach ($filter as $column => $value) {
220
			$pos = strpos($column, '.');
221
			if ($pos !== false) {
222
				$rel = NameUtils::toStudlyCase(substr($column, 0, $pos));
223
				$col = substr($column, $pos + 1);
224
				$method = 'use' . $rel . 'Query';
225
				if (method_exists($query, $method)) {
226
					$sub = $query->$method();
227
					$this->applyFilter($sub, [$col => $value]);
228
					$sub->endUse();
229
				}
230
			} else {
231
				$method = 'filterBy' . NameUtils::toStudlyCase($column);
232
				if (method_exists($query, $method)) {
233
					$query->$method($value);
234
				}
235
			}
236
		}
237
	}
238
239
	/**
240
	 * @param string $type
241
	 * @param SessionEvent $event
242
	 */
243
	protected function dispatch($type, SessionEvent $event) {
244
		$model = $event->getSession();
245
		$methods = [
246
			SessionEvent::PRE_CREATE => 'preCreate',
247
			SessionEvent::POST_CREATE => 'postCreate',
248
			SessionEvent::PRE_UPDATE => 'preUpdate',
249
			SessionEvent::POST_UPDATE => 'postUpdate',
250
			SessionEvent::PRE_DELETE => 'preDelete',
251
			SessionEvent::POST_DELETE => 'postDelete',
252
			SessionEvent::PRE_SAVE => 'preSave',
253
			SessionEvent::POST_SAVE => 'postSave'
254
		];
255
256
		if (isset($methods[$type])) {
257
			$method = $methods[$type];
258
			if (method_exists($this, $method)) {
259
				$this->$method($model);
260
			}
261
		}
262
263
		$dispatcher = $this->getServiceContainer()->getDispatcher();
264
		$dispatcher->dispatch($type, $event);
265
	}
266
267
	/**
268
	 * Internal mechanism to set the User id
269
	 * 
270
	 * @param Session $model
271
	 * @param mixed $relatedId
272
	 */
273
	protected function doSetUserId(Session $model, $relatedId) {
274
		if ($model->getUserId() !== $relatedId) {
275
			$model->setUserId($relatedId);
276
277
			return true;
278
		}
279
280
		return false;
281
	}
282
283
	/**
284
	 * Returns one Session with the given id from cache
285
	 * 
286
	 * @param mixed $id
287
	 * @return Session|null
288
	 */
289
	protected function get($id) {
290
		if ($this->pool === null) {
291
			$this->pool = new Map();
292
		} else if ($this->pool->has($id)) {
293
			return $this->pool->get($id);
294
		}
295
296
		$model = SessionQuery::create()->findOneById($id);
297
		$this->pool->set($id, $model);
298
299
		return $model;
300
	}
301
302
	/**
303
	 * Returns the service container
304
	 * 
305
	 * @return ServiceContainer
306
	 */
307
	abstract protected function getServiceContainer();
308
}
309