This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace MacsiDigital\Xero\Support; |
||
4 | |||
5 | use Exception; |
||
6 | use Illuminate\Support\Collection; |
||
7 | use MacsiDigital\Xero\Facades\Xero; |
||
8 | |||
9 | abstract class Model |
||
10 | { |
||
11 | protected $attributes = []; |
||
12 | protected $queryAttributes = []; |
||
13 | protected $relationships = []; |
||
14 | protected $queries = []; |
||
15 | protected $methods = []; |
||
16 | |||
17 | public $response; |
||
18 | |||
19 | const ENDPOINT = ''; |
||
20 | const NODE_NAME = ''; |
||
21 | const KEY_FIELD = ''; |
||
22 | |||
23 | protected $client; |
||
24 | |||
25 | public function __construct() |
||
26 | { |
||
27 | $this->client = Xero::getClient(); |
||
28 | } |
||
29 | |||
30 | /** |
||
31 | * Get the resource uri of the class (Contacts) etc. |
||
32 | * |
||
33 | * @return string |
||
34 | */ |
||
35 | public static function getEndpoint() |
||
36 | { |
||
37 | return static::ENDPOINT; |
||
38 | } |
||
39 | |||
40 | /** |
||
41 | * Get the root node name. Just the unqualified classname. |
||
42 | * |
||
43 | * @return string |
||
44 | */ |
||
45 | public static function getRootNodeName() |
||
46 | { |
||
47 | return static::NODE_NAME; |
||
48 | } |
||
49 | |||
50 | /** |
||
51 | * Get the unique key field. |
||
52 | * |
||
53 | * @return string |
||
54 | */ |
||
55 | public static function getKey() |
||
56 | { |
||
57 | return static::KEY_FIELD; |
||
58 | } |
||
59 | |||
60 | /** |
||
61 | * Get the response model. |
||
62 | * |
||
63 | * @return response object |
||
64 | */ |
||
65 | public function getResponse() |
||
66 | { |
||
67 | return $this->response; |
||
68 | } |
||
69 | |||
70 | /** |
||
71 | * Get the object unique ID. |
||
72 | * |
||
73 | * @return string |
||
74 | */ |
||
75 | public function getID() |
||
76 | { |
||
77 | $index = $this->getKey(); |
||
78 | |||
79 | return $this->$index; |
||
80 | } |
||
81 | |||
82 | public function hasID() |
||
83 | { |
||
84 | $index = $this->getKey(); |
||
85 | if ($this->$index != '') { |
||
86 | return true; |
||
87 | } |
||
88 | |||
89 | return false; |
||
90 | } |
||
91 | |||
92 | public function getAttributes() |
||
93 | { |
||
94 | return $this->attributes; |
||
95 | } |
||
96 | |||
97 | /** |
||
98 | * Get an attribute from the model. |
||
99 | * |
||
100 | * @param string $key |
||
101 | * @return mixed |
||
102 | */ |
||
103 | public function getAttribute($key) |
||
104 | { |
||
105 | if (! $key) { |
||
106 | return; |
||
107 | } |
||
108 | if ($this->attributeExists($key)) { |
||
109 | return $this->getAttributeValue($key); |
||
110 | } |
||
111 | } |
||
112 | |||
113 | /** |
||
114 | * Get a plain attribute (not a relationship). |
||
115 | * |
||
116 | * @param string $key |
||
117 | * @return mixed |
||
118 | */ |
||
119 | public function getAttributeValue($key) |
||
120 | { |
||
121 | return $this->getAttributeFromArray($key); |
||
122 | } |
||
123 | |||
124 | /** |
||
125 | * Get an attribute from the $attributes array. |
||
126 | * |
||
127 | * @param string $key |
||
128 | * @return mixed |
||
129 | */ |
||
130 | protected function getAttributeFromArray($key) |
||
131 | { |
||
132 | if (isset($this->attributes[$key])) { |
||
133 | return $this->attributes[$key]; |
||
134 | } |
||
135 | } |
||
136 | |||
137 | /** |
||
138 | * Set a given attribute on the model. |
||
139 | * |
||
140 | * @param string $key |
||
141 | * @param mixed $value |
||
142 | * @return mixed |
||
143 | */ |
||
144 | public function setAttribute($key, $value) |
||
145 | { |
||
146 | if ($this->attributeExists($key)) { |
||
147 | if ($this->isRelationshipAttribute($key)) { |
||
148 | $class = new $this->relationships[$key]; |
||
149 | if (is_array($value) && in_array($class->getKey(), $value)) { |
||
150 | $class->fill($value); |
||
151 | $this->attributes[$key] = $class; |
||
152 | } elseif (is_object($value)) { |
||
153 | $this->attributes[$key] = $value; |
||
154 | } else { |
||
155 | foreach ($value as $index => $attributes) { |
||
0 ignored issues
–
show
|
|||
156 | $new_class = new $this->relationships[$key]; |
||
157 | $new_class->fill($attributes); |
||
158 | $this->attributes[$key] = []; |
||
159 | $this->attributes[$key][$index] = $new_class; |
||
160 | } |
||
161 | } |
||
162 | } else { |
||
163 | $this->attributes[$key] = $value; |
||
164 | } |
||
165 | } |
||
166 | |||
167 | return $this; |
||
168 | } |
||
169 | |||
170 | public function processRelationships() |
||
171 | { |
||
172 | foreach ($this->relationships as $key => $class) { |
||
173 | if (is_array($this->$key) && in_array($this->getKey(), $this->$key)) { |
||
174 | if (! is_object($this->$key)) { |
||
175 | $this->attributes[$key] = ($class)::make($this->$key); |
||
176 | } |
||
177 | } else { |
||
178 | foreach ($this->$key as $index => $item) { |
||
179 | if (! is_object($item)) { |
||
180 | $this->attributes[$key][$index] = ($class)::make($item); |
||
181 | } |
||
182 | } |
||
183 | } |
||
184 | } |
||
185 | |||
186 | return $this; |
||
187 | } |
||
188 | |||
189 | public function attributeExists($key) |
||
190 | { |
||
191 | return array_key_exists($key, $this->attributes); |
||
192 | } |
||
193 | |||
194 | public function isRelationshipAttribute($key) |
||
195 | { |
||
196 | return array_key_exists($key, $this->relationships); |
||
197 | } |
||
198 | |||
199 | public function unsetAttribute($key) |
||
200 | { |
||
201 | $this->setAttribute($key, ''); |
||
202 | } |
||
203 | |||
204 | /** |
||
205 | * Dynamically retrieve attributes on the model. |
||
206 | * |
||
207 | * @param string $key |
||
208 | * @return mixed |
||
209 | */ |
||
210 | public function __get($key) |
||
211 | { |
||
212 | return $this->getAttribute($key); |
||
213 | } |
||
214 | |||
215 | /** |
||
216 | * Dynamically set attributes on the model. |
||
217 | * |
||
218 | * @param string $key |
||
219 | * @param mixed $value |
||
220 | * @return void |
||
221 | */ |
||
222 | public function __set($key, $value) |
||
223 | { |
||
224 | $this->setAttribute($key, $value); |
||
225 | } |
||
226 | |||
227 | /** |
||
228 | * Determine if an attribute or relation exists on the model. |
||
229 | * |
||
230 | * @param string $key |
||
231 | * @return bool |
||
232 | */ |
||
233 | public function __isset($key) |
||
234 | { |
||
235 | return $this->attributeExists($key); |
||
236 | } |
||
237 | |||
238 | /** |
||
239 | * Unset an attribute on the model. |
||
240 | * |
||
241 | * @param string $key |
||
242 | * @return void |
||
243 | */ |
||
244 | public function __unset($key) |
||
245 | { |
||
246 | $this->unsetAttribute($key); |
||
247 | } |
||
248 | |||
249 | public function make($attributes) |
||
250 | { |
||
251 | $model = new static; |
||
252 | $model->fill($attributes); |
||
253 | |||
254 | return $model; |
||
255 | } |
||
256 | |||
257 | public function create($attributes) |
||
258 | { |
||
259 | $model = $this->make($attributes); |
||
260 | $model->save(); |
||
261 | |||
262 | return $model; |
||
263 | } |
||
264 | |||
265 | public function fill($attributes) |
||
266 | { |
||
267 | foreach ($attributes as $attribute => $value) { |
||
268 | $this->$attribute = $value; |
||
269 | } |
||
270 | |||
271 | return $this; |
||
272 | } |
||
273 | |||
274 | public function update($attributes) |
||
275 | { |
||
276 | $this->fill($attributes)->save(); |
||
277 | |||
278 | return $this; |
||
279 | } |
||
280 | |||
281 | public function save() |
||
282 | { |
||
283 | if ($this->hasID()) { |
||
284 | if (in_array('put', $this->methods)) { |
||
285 | $this->response = $this->client->post($this->getEndpoint().'/'.$this->getID(), $this->attributes); |
||
286 | if ($this->response->getStatusCode() == '200') { |
||
287 | return $this; |
||
288 | } else { |
||
289 | throw new Exception('Status Code '.$this->response->getStatusCode().' - '.$this->response->getReason()); |
||
290 | } |
||
291 | } |
||
292 | } else { |
||
293 | if (in_array('post', $this->methods)) { |
||
294 | $this->response = $this->client->post($this->getEndpoint(), $this->attributes); |
||
295 | if ($this->response->getStatusCode() == '200') { |
||
296 | $this->fill($this->collect($this->response->getBody())->first()); |
||
297 | |||
298 | return $this; |
||
299 | } else { |
||
300 | throw new Exception('Status Code '.$this->response->getStatusCode().' - '.$this->response->getReason()); |
||
301 | } |
||
302 | } |
||
303 | } |
||
304 | } |
||
305 | |||
306 | public function where($key, $operator, $value = '') |
||
307 | { |
||
308 | if (in_array($key, $this->queryAttributes)) { |
||
309 | if ($value == '') { |
||
310 | $value = $operator; |
||
311 | $operator = '='; |
||
312 | } |
||
313 | $this->queries[$key] = ['key' => $key, 'operator' => $operator, 'value' => $value]; |
||
314 | } |
||
315 | |||
316 | return $this; |
||
317 | } |
||
318 | |||
319 | public function getQueryString() |
||
320 | { |
||
321 | $query_string = ''; |
||
322 | if ($this->queries != []) { |
||
323 | $query_string .= '?where='; |
||
324 | $i = 1; |
||
325 | foreach ($this->queries as $query) { |
||
326 | if ($i > 1) { |
||
327 | $query_string .= '&'; |
||
328 | } |
||
329 | $query_string .= urlencode($query['key'].$query['operator'].'"'.$query['value'].'"'); |
||
330 | |||
331 | $i++; |
||
332 | } |
||
333 | } |
||
334 | |||
335 | return $query_string; |
||
336 | } |
||
337 | |||
338 | public function first() |
||
339 | { |
||
340 | return $this->get()->first(); |
||
341 | } |
||
342 | |||
343 | View Code Duplication | public function get() |
|
0 ignored issues
–
show
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. ![]() |
|||
344 | { |
||
345 | if (in_array('get', $this->methods)) { |
||
346 | $this->response = $this->client->get($this->getEndpoint().$this->getQueryString()); |
||
347 | if ($this->response->getStatusCode() == '200') { |
||
348 | return $this->collect($this->response->getBody()); |
||
349 | } else { |
||
350 | throw new Exception('Status Code '.$this->response->getStatusCode().' - '.$this->response->getReason()); |
||
351 | } |
||
352 | } |
||
353 | } |
||
354 | |||
355 | View Code Duplication | public function all() |
|
0 ignored issues
–
show
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. ![]() |
|||
356 | { |
||
357 | if (in_array('get', $this->methods)) { |
||
358 | $this->response = $this->client->get($this->getEndpoint()); |
||
359 | if ($this->response->getStatusCode() == '200') { |
||
360 | return $this->collect($this->response->getBody()); |
||
361 | } else { |
||
362 | throw new Exception('Status Code '.$this->response->getStatusCode().' - '.$this->response->getReason()); |
||
363 | } |
||
364 | } |
||
365 | } |
||
366 | |||
367 | View Code Duplication | public function find($id) |
|
0 ignored issues
–
show
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. ![]() |
|||
368 | { |
||
369 | if (in_array('get', $this->methods)) { |
||
370 | $this->response = $this->client->get($this->getEndpoint().'/'.$id); |
||
371 | if ($this->response->getStatusCode() == '200') { |
||
372 | return $this->collect($this->response->getBody())->first(); |
||
373 | } else { |
||
374 | throw new Exception('Status Code '.$this->response->getStatusCode().' - '.$this->response->getReason()); |
||
375 | } |
||
376 | } |
||
377 | } |
||
378 | |||
379 | public function delete($id = '') |
||
380 | { |
||
381 | if ($id == '') { |
||
382 | $id = $this->getID(); |
||
383 | } |
||
384 | if (in_array('delete', $this->methods)) { |
||
385 | $this->response = $this->client->delete($this->getEndpoint().'/'.$id); |
||
386 | if ($this->response->getStatusCode() == '200') { |
||
387 | return $this->response->getStatusCode(); |
||
388 | } else { |
||
389 | throw new Exception('Status Code '.$this->response->getStatusCode().' - '.$this->response->getReason()); |
||
390 | } |
||
391 | } |
||
392 | } |
||
393 | |||
394 | protected function collect($response) |
||
395 | { |
||
396 | $items = []; |
||
397 | foreach ($response[$this->getEndpoint()] as $item) { |
||
398 | $items[] = static::make($item); |
||
399 | } |
||
400 | |||
401 | return new Collection($items); |
||
402 | } |
||
403 | } |
||
404 |
There are different options of fixing this problem.
If you want to be on the safe side, you can add an additional type-check:
If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:
Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.