Completed
Push — master ( 08c314...daca94 )
by Jean-Christophe
01:29
created

RestController::getOne()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 15
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 15
rs 9.4285
cc 2
eloc 12
nc 2
nop 4
1
<?php
2
3
namespace micro\controllers\rest;
4
5
use micro\controllers\Controller;
6
use micro\orm\DAO;
7
use micro\controllers\Startup;
8
use micro\utils\StrUtils;
9
use micro\cache\CacheManager;
10
use micro\utils\RequestUtils;
11
12
/**
13
 * @author jc
14
 * Abstract base class for Rest controllers
15
 *
16
 */
17
abstract class RestController extends Controller {
18
	protected $config;
19
	protected $model;
20
	protected $contentType;
21
	protected $restCache;
22
	/**
23
	 * @var ResponseFormatter
24
	 */
25
	protected $responseFormatter;
26
27
	/**
28
	 * @var RestServer
29
	 */
30
	protected $server;
31
32
	public function __construct(){
33
		if(!\headers_sent()){
34
			@\set_exception_handler(array ($this,'_errorHandler' ));
1 ignored issue
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
35
			$this->config=Startup::getConfig();
36
			$this->server=new RestServer($this->config);
37
			$this->server->cors();
38
			$this->responseFormatter=new ResponseFormatter();
39
			$this->contentType="application/json";
40
			$this->server->_setContentType($this->contentType);
41
			$this->restCache=CacheManager::getRestCacheController(\get_class($this));
42
		}
43
		parent::__construct();
44
	}
45
46
	public function isValid(){
47
		if(isset($this->restCache["authorizations"])){
48
			if(\array_search(Startup::getAction(), $this->restCache["authorizations"])!==false){
49
				return $this->server->isValid();
50
			}
51
		}
52
		return true;
53
	}
54
55
	public function onInvalidControl(){
56
		throw new \Exception('HTTP/1.1 401 Unauthorized, you need an access token for this request',401);
57
	}
58
59
	/**
60
	 * Realise the connection to the server
61
	 * To override in derived classes to define your own authentication
62
	 */
63
	public function connect(){
64
		$this->server->connect($this);
65
	}
66
67
	public function initialize(){
68
		$thisClass=\get_class($this);
69
		if(!isset($this->model))
70
			$this->model=CacheManager::getRestResource($thisClass);
71
		if(!isset($this->model)){
72
			$modelsNS=$this->config["mvcNS"]["models"];
73
			$this->model=$modelsNS."\\".$this->responseFormatter->getModel($thisClass);
74
		}
75
		$this->connectDb($this->config);
76
	}
77
78
	public function finalize(){
79
		parent::finalize();
80
		$this->server->finalizeTokens();
81
	}
82
83
84
85
	public function _errorHandler($e){
86
		$code=500;
87
		if($e->getCode()!==0)
88
			$code=$e->getCode();
89
		$this->_setResponseCode($code);
90
		echo $this->responseFormatter->formatException($e);
91
	}
92
93
	public function _setResponseCode($value){
94
		\http_response_code($value);
95
	}
96
97
	protected function connectDb($config){
98
		$db=$config["database"];
99
		if($db["dbName"]!==""){
100
			DAO::connect($db["type"],$db["dbName"],@$db["serverName"],@$db["port"],@$db["user"],@$db["password"],@$db["cache"]);
101
		}
102
	}
103
104
	/**
105
	 * Updates $instance with $values
106
	 * To eventually be redefined in derived classes
107
	 * @param object $instance the instance to update
108
	 * @param array $values
109
	 */
110
	protected function _setValuesToObject($instance,$values){
111
		RequestUtils::setValuesToObject($instance,$values);
112
	}
113
114
	/**
115
	 * Returns all objects for the resource $model
116
	 * @route("methods"=>["get"],"cache"=>true,"duration"=>1000)
117
	 */
118
	public function index() {
119
			$datas=DAO::getAll($this->model);
120
			$datas=\array_map(function($o){return $o->_rest;}, $datas);
121
			echo $this->responseFormatter->get($datas);
122
	}
123
124
	/**
125
	 * Returns a list of objects from the server
126
	 * @param string $condition the sql Where part
127
	 * @param boolean $loadManyToOne
128
	 * @param boolean $loadOneToMany
129
	 * @param boolean $useCache
130
	 */
131
	public function get($condition="1=1",$loadManyToOne=false,$loadOneToMany=false,$useCache=false){
132
		try{
133
			$condition=\urldecode($condition);
134
			$loadManyToOne=StrUtils::isBooleanTrue($loadManyToOne);
135
			$loadOneToMany=StrUtils::isBooleanTrue($loadOneToMany);
136
			$useCache=StrUtils::isBooleanTrue($useCache);
137
			$datas=DAO::getAll($this->model,$condition,$loadManyToOne,$loadOneToMany,$useCache);
138
			$datas=\array_map(function($o){return $o->_rest;}, $datas);
139
			echo $this->responseFormatter->get($datas);
140
		}catch (\Exception $e){
141
			$this->_setResponseCode(500);
142
			echo $this->responseFormatter->formatException($e);
143
		}
144
	}
145
146
	/**
147
	 * Get the first object corresponding to the $keyValues
148
	 * @param string $keyValues primary key(s) value(s) or condition
149
	 * @param boolean $loadManyToOne if true then manyToOne members are loaded.
150
	 * @param boolean $loadOneToMany if true then oneToMany members are loaded.
151
	 * @param boolean $useCache if true then response is cached
152
	 */
153
	public function getOne($keyValues,$loadManyToOne=false,$loadOneToMany=false,$useCache=false){
154
		$keyValues=\urldecode($keyValues);
155
		$loadManyToOne=StrUtils::isBooleanTrue($loadManyToOne);
156
		$loadOneToMany=StrUtils::isBooleanTrue($loadOneToMany);
157
		$useCache=StrUtils::isBooleanTrue($useCache);
158
		$data=DAO::getOne($this->model, $keyValues,$loadManyToOne,$loadOneToMany,$useCache);
159
		if(isset($data)){
160
			$_SESSION["_restInstance"]=$data;
161
			echo $this->responseFormatter->getOne($data->_rest);
162
		}
163
		else{
164
			$this->_setResponseCode(404);
165
			echo $this->responseFormatter->format(["message"=>"No result found","keyValues"=>$keyValues]);
166
		}
167
	}
168
169
	public function _format($arrayMessage){
170
		return $this->responseFormatter->format($arrayMessage);
171
	}
172
173
	/**
174
	 * @param string $member
175
	 * @param boolean $useCache
176
	 * @throws \Exception
177
	 */
178 View Code Duplication
	public function getOneToMany($member,$useCache=false){
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
179
		if(isset($_SESSION["_restInstance"])){
180
			$useCache=StrUtils::isBooleanTrue($useCache);
181
			$datas=DAO::getOneToMany($_SESSION["_restInstance"], $member,null,$useCache);
182
			$datas=\array_map(function($o){return $o->_rest;}, $datas);
183
			echo $this->responseFormatter->get($datas);
184
		}else{
185
			throw new \Exception("You have to call getOne before calling getOneToMany.");
186
		}
187
	}
188
189
	/**
190
	 * @param string $member
191
	 * @param boolean $useCache
192
	 * @throws \Exception
193
	 */
194 View Code Duplication
	public function getManyToMany($member,$useCache=false){
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
195
		if(isset($_SESSION["_restInstance"])){
196
			$useCache=StrUtils::isBooleanTrue($useCache);
197
			$datas=DAO::getManyToMany($_SESSION["_restInstance"], $member,null,$useCache);
198
			$datas=\array_map(function($o){return $o->_rest;}, $datas);
199
			echo $this->responseFormatter->get($datas);
200
		}else{
201
			throw new \Exception("You have to call getOne before calling getManyToMany.");
202
		}
203
	}
204
205
	/**
206
	 * Update an instance of $model selected by the primary key $keyValues
207
	 * Require members values in $_POST array
208
	 * @param array $keyValues
209
	 * @authorization
210
	 */
211 View Code Duplication
	public function update(...$keyValues){
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
212
		$instance=DAO::getOne($this->model, $keyValues);
213
		if(isset($instance)){
214
			$this->_setValuesToObject($instance,RequestUtils::getInput());
0 ignored issues
show
Bug introduced by
It seems like \micro\utils\RequestUtils::getInput() targeting micro\utils\RequestUtils::getInput() can also be of type null; however, micro\controllers\rest\R...r::_setValuesToObject() does only seem to accept array, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
215
			$result=DAO::update($instance);
216
			if($result){
217
				echo $this->responseFormatter->format(["status"=>"updated","data"=>$instance->_rest]);
218
			}else{
219
				throw new \Exception("Unable to update the instance");
220
			}
221
		}else{
222
			$this->_setResponseCode(404);
223
			echo $this->responseFormatter->format(["message"=>"No result found","keyValues"=>$keyValues]);
224
		}
225
	}
226
227
	/**
228
	 * Insert a new instance of $model
229
	 * Require members values in $_POST array
230
	 * @authorization
231
	 */
232
	public function add(){
233
		$model=$this->model;
234
		$instance=new $model();
235
		if(isset($instance)){
236
			$this->_setValuesToObject($instance,RequestUtils::getInput());
0 ignored issues
show
Bug introduced by
It seems like \micro\utils\RequestUtils::getInput() targeting micro\utils\RequestUtils::getInput() can also be of type null; however, micro\controllers\rest\R...r::_setValuesToObject() does only seem to accept array, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
237
			$result=DAO::insert($instance);
238
			if($result){
239
				echo $this->responseFormatter->format(["status"=>"inserted","data"=>$instance->_rest]);
240
			}else{
241
				throw new \Exception("Unable to insert the instance");
242
			}
243
		}else{
244
			$this->_setResponseCode(500);
245
			echo $this->responseFormatter->format(["message"=>"Unable to create ".$model." instance"]);
246
		}
247
	}
248
249
	/**
250
	 * Delete the instance of $model selected by the primary key $keyValues
251
	 * Requires an authorization with access token
252
	 * @param array $keyValues
253
	 * @route("methods"=>["delete"])
254
	 * @authorization
255
	 */
256 View Code Duplication
	public function delete(...$keyValues){
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
257
		$instance=DAO::getOne($this->model, $keyValues);
258
		if(isset($instance)){
259
			$result=DAO::remove($instance);
260
			if($result){
261
				echo $this->responseFormatter->format(["status"=>"deleted","data"=>$instance->_rest]);
262
			}else{
263
				throw new \Exception("Unable to delete the instance");
264
			}
265
		}else{
266
			$this->_setResponseCode(404);
267
			echo $this->responseFormatter->format(["message"=>"No result found","keyValues"=>$keyValues]);
268
		}
269
	}
270
}
271