Passed
Push — master ( c4282d...8835f1 )
by Jean-Christophe
10:25
created

RestControllerUtilitiesTrait   B

Complexity

Total Complexity 48

Size/Duplication

Total Lines 244
Duplicated Lines 0 %

Test Coverage

Coverage 35.48%

Importance

Changes 3
Bugs 0 Features 1
Metric Value
wmc 48
eloc 103
c 3
b 0
f 1
dl 0
loc 244
ccs 44
cts 124
cp 0.3548
rs 8.5599

21 Methods

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