RestControllerUtilitiesTrait   B
last analyzed

Complexity

Total Complexity 52

Size/Duplication

Total Lines 261
Duplicated Lines 0 %

Test Coverage

Coverage 62.99%

Importance

Changes 0
Metric Value
wmc 52
eloc 111
c 0
b 0
f 0
dl 0
loc 261
ccs 80
cts 127
cp 0.6299
rs 7.44

23 Methods

Rating   Name   Duplication   Size   Complexity  
A displayErrors() 0 15 4
A updateOperation() 0 2 1
A _validateInstance() 0 13 4
A getInclude() 0 5 2
A getRequestFormatter() 0 2 1
A getRequestParam() 0 2 1
A addError() 0 2 1
A operate_() 0 14 4
A _getResponseFormatter() 0 5 2
A _getRestServer() 0 5 2
A getRestServer() 0 2 1
A generatePagination() 0 13 3
A addViolation() 0 2 1
A updateManyToOne() 0 10 5
A getPrimaryKeysFromDatas() 0 11 3
A getAssociatedMemberValues_() 0 8 2
A addOperation() 0 2 1
A getResponseFormatter() 0 2 1
A hasErrors() 0 2 2
A getDatas() 0 2 1
A _getRequestFormatter() 0 5 2
A _setValuesToObject() 0 15 4
A getCondition() 0 14 4

How to fix   Complexity   

Complex Class

Complex classes like RestControllerUtilitiesTrait often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use RestControllerUtilitiesTrait, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Ubiquity\controllers\rest\traits;
4
5
use Ubiquity\controllers\rest\formatters\RequestFormatter;
6
use Ubiquity\controllers\rest\formatters\ResponseFormatter;
7
use Ubiquity\controllers\rest\RestServer;
8
use Ubiquity\orm\DAO;
9
use Ubiquity\utils\base\UString;
10
use Ubiquity\utils\http\URequest;
11
use Ubiquity\contents\validation\ValidatorsManager;
12
use Ubiquity\contents\validation\validators\ConstraintViolation;
13
use Ubiquity\orm\OrmUtils;
14
use Ubiquity\orm\parser\Reflexion;
15
use Ubiquity\controllers\rest\RestError;
16
17
/**
18
 * Rest controller internal utilities.
19
 * Ubiquity\controllers\rest$RestControllerUtilitiesTrait
20
 * This class is part of Ubiquity
21
 *
22
 * @author jcheron <[email protected]>
23
 * @version 1.0.6
24
 * @property ResponseFormatter $responseFormatter
25
 * @property RequestFormatter $requestFormatter
26
 * @property RestServer $server
27
 * @property string $model
28
 *
29
 */
30
trait RestControllerUtilitiesTrait {
31
	protected $errors;
32
33
	abstract public function _setResponseCode($value);
34
35 1
	protected function getDatas() {
36 1
		return $this->_getRequestFormatter ()->getDatas ( $this->model );
37
	}
38
39
	/**
40
	 *
41
	 * @param string $param
42
	 * @param string|boolean $default
43
	 * @return string|boolean
44
	 */
45 7
	protected function getRequestParam($param, $default) {
46 7
		return $_GET [$param] ?? $default;
47
	}
48
49 1
	protected function operate_($instance, $callback, $status, $exceptionMessage, $keyValues) {
50 1
		if (isset ( $instance )) {
51 1
			$result = $callback ( $instance );
52 1
			if ($result == true) {
53 1
				$formatter = $this->_getResponseFormatter ();
54 1
				echo $formatter->format ( [ "status" => $status,"data" => $formatter->cleanRestObject ( $instance ) ] );
55
			} elseif ($result === null) {
56
				$this->displayErrors ();
57
			} else {
58 1
				throw new \Exception ( $exceptionMessage );
59
			}
60
		} else {
61 1
			$this->_setResponseCode ( 404 );
62 1
			echo $this->_getResponseFormatter ()->format ( [ "message" => "No result found","keyValues" => $keyValues ] );
63
		}
64
	}
65
66 2
	protected function generatePagination(&$filter, $pageNumber, $pageSize) {
67 2
		$count = DAO::count ( $this->model, $filter );
68 2
		$pagesCount = \ceil ( $count / $pageSize );
69 2
		$pages = [ 'self' => $pageNumber,'first' => 1,'last' => $pagesCount,'pageSize' => $pageSize ];
70 2
		if ($pageNumber - 1 > 0) {
71 1
			$pages ['prev'] = $pageNumber - 1;
72
		}
73 2
		if ($pageNumber + 1 <= $pagesCount) {
74 1
			$pages ['next'] = $pageNumber + 1;
75
		}
76 2
		$offset = ($pageNumber - 1) * $pageSize;
77 2
		$filter .= ' limit ' . $offset . ',' . $pageSize;
78 2
		return $pages;
79
	}
80
81 1
	protected function updateOperation($instance, $datas, $updateMany = false) {
82 1
		return DAO::update ( $instance, $updateMany );
83
	}
84
85 1
	protected function addOperation($instance, $datas, $insertMany = false) {
86 1
		return DAO::insert ( $instance, $insertMany );
87
	}
88
89
	/**
90
	 *
91
	 * @return \Ubiquity\controllers\rest\formatters\ResponseFormatter
92
	 */
93 13
	protected function _getResponseFormatter() {
94 13
		if (! isset ( $this->responseFormatter )) {
95 13
			$this->responseFormatter = $this->getResponseFormatter ();
96
		}
97 13
		return $this->responseFormatter;
98
	}
99
100
	/**
101
	 * To override, returns the active formatter for the response.
102
	 *
103
	 * @return \Ubiquity\controllers\rest\formatters\ResponseFormatter
104
	 */
105 13
	protected function getResponseFormatter(): ResponseFormatter {
106 13
		return new ResponseFormatter ();
107
	}
108
109
	/**
110
	 *
111
	 * @return \Ubiquity\controllers\rest\formatters\RequestFormatter
112
	 */
113 13
	protected function _getRequestFormatter() {
114 13
		if (! isset ( $this->requestFormatter )) {
115 13
			$this->requestFormatter = $this->getRequestFormatter ();
116
		}
117 13
		return $this->requestFormatter;
118
	}
119
120
	/**
121
	 * To override, returns the active formatter for the request.
122
	 *
123
	 * @return \Ubiquity\controllers\rest\formatters\RequestFormatter
124
	 */
125 13
	protected function getRequestFormatter(): RequestFormatter {
126 13
		return new RequestFormatter ();
127
	}
128
129 13
	protected function _getRestServer() {
130 13
		if (! isset ( $this->server )) {
131 13
			$this->server = $this->getRestServer ();
132
		}
133 13
		return $this->server;
134
	}
135
136
	/**
137
	 * To override, returns the active RestServer
138
	 *
139
	 * @return \Ubiquity\controllers\rest\RestServer
140
	 */
141 13
	protected function getRestServer(): RestServer {
142 13
		return new RestServer ( $this->config );
143
	}
144
145
	/**
146
	 * Updates $instance with $values
147
	 * To eventually be redefined in derived classes
148
	 *
149
	 * @param object $instance the instance to update
150
	 * @param array $values
151
	 *
152
	 */
153 1
	protected function _setValuesToObject($instance, $values = [ ]) {
154 1
		if (URequest::isJSON ()) {
155 1
			if (\is_string ( $values )) {
156
				$values = \json_decode ( $values, true );
157
			}
158
		}
159 1
		$className = \get_class ( $instance );
160 1
		$fieldsInRelationForUpdate = OrmUtils::getFieldsInRelationsForUpdate_ ( $className );
161 1
		$manyToOneRelations = $fieldsInRelationForUpdate ["manyToOne"];
162
163 1
		$members = \array_keys ( $values );
164 1
		OrmUtils::setFieldToMemberNames ( $members, $fieldsInRelationForUpdate ["relations"] );
165 1
		URequest::setValuesToObject ( $instance, $values );
166 1
		if ($manyToOneRelations) {
167
			$this->updateManyToOne ( $manyToOneRelations, $members, $className, $instance, $values );
168
		}
169
	}
170
171
	protected function updateManyToOne($manyToOneRelations, $members, $className, $instance, $values) {
172
		foreach ( $manyToOneRelations as $member ) {
173
			if (\array_search ( $member, $members ) !== false) {
174
				$joinColumn = OrmUtils::getAnnotationInfoMember ( $className, "#joinColumn", $member );
175
				if ($joinColumn) {
176
					$fkClass = $joinColumn ["className"];
177
					$fkField = $joinColumn ["name"];
178
					if (isset ( $values [$fkField] )) {
179
						$fkObject = DAO::getById ( $fkClass, $values ["$fkField"] );
180
						Reflexion::setMemberValue ( $instance, $member, $fkObject );
181
					}
182
				}
183
			}
184
		}
185
	}
186
187
	/**
188
	 *
189
	 * @param string|boolean $include
190
	 * @return array|boolean
191
	 */
192 7
	protected function getInclude($include) {
193 7
		if (! UString::isBooleanStr ( $include )) {
194 1
			return \explode ( ',', $include );
195
		}
196 6
		return UString::isBooleanTrue ( $include );
197
	}
198
199
	protected function addError($code, $title, $detail = null, $source = null, $status = null) {
200
		$this->errors [] = new RestError( $code, $title, $detail, $source, $status );
201
	}
202
203 1
	protected function hasErrors() {
204 1
		return \is_array ( $this->errors ) && \count ( $this->errors ) > 0;
205
	}
206
207
	protected function displayErrors() {
208
		if ($this->hasErrors ()) {
209
			$status = 200;
210
			$errors = [ ];
211
			foreach ( $this->errors as $error ) {
212
				$errors [] = $error->asArray ();
213
				if ($error->getStatus () > $status) {
214
					$status = $error->getStatus ();
215
				}
216
			}
217
			echo $this->_getResponseFormatter ()->format ( [ 'errors' => $errors ] );
218
			$this->_setResponseCode ( $status );
219
			return true;
220
		}
221
		return false;
222
	}
223
224
	/**
225
	 *
226
	 * @param string $ids The primary key values (comma separated if pk is multiple)
227
	 * @param callable $getDatas
228
	 * @param string $member The member to load
229
	 * @param boolean|string $include if true, loads associate members with associations, if string, example : client.*,commands
230
	 * @param boolean $useCache
231
	 * @param boolean $multiple
232
	 * @throws \Exception
233
	 */
234 1
	protected function getAssociatedMemberValues_($ids, $getDatas, $member, $include = false, $useCache = false, $multiple = true) {
235 1
		$include = $this->getInclude ( $include );
236 1
		$useCache = UString::isBooleanTrue ( $useCache );
237 1
		$datas = $getDatas ( [ $this->model,$ids ], $member, $include, $useCache );
238 1
		if ($multiple) {
239 1
			echo $this->_getResponseFormatter ()->get ( $datas );
240
		} else {
241
			echo $this->_getResponseFormatter ()->getOne ( $datas );
242
		}
243
	}
244
245 1
	public function _validateInstance($instance, $members, $excludedValidators = [ ]) {
246 1
		if ($this->useValidation) {
247 1
			$isValid = true;
248 1
			$violations = ValidatorsManager::validate ( $instance, '', $excludedValidators );
249 1
			foreach ( $violations as $violation ) {
250
				if (\array_search ( $violation->getMember (), $members ) !== false) {
251
					$this->addViolation ( $violation );
252
					$isValid = false;
253
				}
254
			}
255 1
			return $isValid;
256
		}
257
		return true;
258
	}
259
260
	protected function addViolation(ConstraintViolation $violation) {
261
		$this->addError ( 406, 'Validation error', $violation->getMessage (), $violation->getMember (), $violation->getValidatorType () );
262
	}
263
264
	protected function getPrimaryKeysFromDatas($datas, $model) {
265
		$pks = OrmUtils::getKeyFields ( $model );
266
		$result = [ ];
267
		foreach ( $pks as $pk ) {
268
			if (isset ( $datas [$pk] )) {
269
				$result [] = $datas [$pk];
270
			} else {
271
				$this->addError ( 404, 'Primary key required', 'The primary key ' . $pk . ' is required!', $pk );
272
			}
273
		}
274
		return $result;
275
	}
276
277 6
	protected function getCondition($condition) {
278 6
		if (\is_array ( $condition )) {
279
			$conds = [ ];
280
			foreach ( $condition as $f => $v ) {
281
				$conds [] = $f . "='" . \urldecode ( $v ) . "'";
282
			}
283
			$condition = \implode ( ' AND ', $conds );
284
		} else {
285 6
			$condition = \urldecode ( $condition );
286
		}
287 6
		if (\strpos ( $condition, 'like' ) !== false) {
288 2
			$condition = \str_replace ( '*', '%', $condition );
289
		}
290 6
		return $condition;
291
	}
292
}
293
294