Completed
Push — master ( 287393...7ff50d )
by Raffael
18:27 queued 14:12
created

src/app/Balloon.App.Api/Controller.php (3 issues)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * balloon
7
 *
8
 * @copyright   Copryright (c) 2012-2019 gyselroth GmbH (https://gyselroth.com)
9
 * @license     GPL-3.0 https://opensource.org/licenses/GPL-3.0
10
 */
11
12
namespace Balloon\App\Api;
13
14
use Balloon\App\Api\v2\Collections as ApiCollection;
15
use Balloon\App\Api\v2\Files as ApiFile;
16
use Balloon\Filesystem;
17
use Balloon\Filesystem\Node\Collection;
18
use Balloon\Filesystem\Node\File;
19
use Balloon\Filesystem\Node\NodeInterface;
20
use Closure;
21
use Generator;
22
use Micro\Http\ExceptionInterface;
23
use Micro\Http\Response;
24
25
abstract class Controller
26
{
27
    /**
28
     * Filesystem.
29
     *
30
     * @var Filesystem
31
     */
32
    protected $fs;
33
34
    /**
35
     * @apiDefine _getNode
36
     *
37
     * @apiParam (GET Parameter) {string} id Either id or p (path) of a node must be given.
38
     * @apiParam (GET Parameter) {string} p Either id or p (path) of a node must be given.
39
     * @apiError (General Error Response) {number} status Status Code
40
     * @apiError (General Error Response) {object[]} data Error body
41
     * @apiError (General Error Response) {string} data.error Exception
42
     * @apiError (General Error Response) {string} data.message Message
43
     * @apiError (General Error Response) {number} data.code Error code
44
     *
45
     * @apiErrorExample {json} Error-Response (Invalid Parameter):
46
     * HTTP/1.1 400 Bad Request
47
     * {
48
     *      "status": 400,
49
     *      "data": {
50
     *          "error": "Balloon\\Exception\\InvalidArgument",
51
     *          "message": "invalid node id specified",
52
     *          "code": 0
53
     *      }
54
     * }
55
     *
56
     * @apiErrorExample {json} Error-Response (Insufficient Access):
57
     * HTTP/1.1 403 Forbidden
58
     * {
59
     *      "status": 403,
60
     *      "data": {
61
     *          "error": "Balloon\\Exception\\Forbidden",
62
     *          "message": "not allowed to read node 51354d073c58891f058b4580",
63
     *          "code": 40
64
     *      }
65
     * }
66
     *
67
     * @apiErrorExample {json} Error-Response (Not found):
68
     * HTTP/1.1 404 Not Found
69
     * {
70
     *      "status": 404,
71
     *      "data": {
72
     *          "error": "Balloon\\Exception\\NotFound",
73
     *          "message": "node 51354d073c58891f058b4580 not found",
74
     *          "code": 49
75
     *      }
76
     * }
77
     */
78
79
    /**
80
     * @apiDefine _multiError
81
     *
82
     * @apiErrorExample {json} Error-Response (Multi node error):
83
     * HTTP/1.1 400 Bad Request
84
     * {
85
     *     "status": 400,
86
     *     "data": [
87
     *         {
88
     *              id: "51354d073c58891f058b4580",
89
     *              name: "file.zip",
90
     *              error: "Balloon\\Exception\\Conflict",
91
     *              message: "node already exists",
92
     *              code: 30
93
     *         }
94
     *     ]
95
     * }
96
     */
97
98
    /**
99
     * @apiDefine _writeAction
100
     *
101
     * @apiErrorExample {json} Error-Response (Conflict):
102
     * HTTP/1.1 400 Bad Request
103
     * {
104
     *      "status": 400,
105
     *      "data": {
106
     *          "error": "Balloon\\Exception\\Conflict",
107
     *          "message": "a node called myname does already exists",
108
     *          "code": 17
109
     *      }
110
     * }
111
     */
112
113
    /**
114
     * @apiDefine _conflictNode
115
     * @apiParam (GET Parameter) {number} [conflict=0] Decides how to handle a conflict if a node with the same name already exists at the destination.
116
     * Possible values are:</br>
117
     *  - 0 No action</br>
118
     *  - 1 Automatically rename the node</br>
119
     *  - 2 Overwrite the destination (merge)</br>
120
     */
121
122
    /**
123
     * @apiDefine _getNodes
124
     *
125
     * @apiParam (GET Parameter) {string[]} id Either a single id as string or multiple as an array or a single p (path) as string or multiple paths as array must be given.
126
     * @apiParam (GET Parameter) {string[]} p Either a single id as string or multiple as an array or a single p (path) as string or multiple paths as array must be given.
127
     * @apiError (General Error Response) {number} status Status Code
128
     * @apiError (General Error Response) {object[]} data Error body
129
     * @apiError (General Error Response) {string} data.error Exception
130
     * @apiError (General Error Response) {string} data.message Message
131
     * @apiError (General Error Response) {number} data.code General error messages of type  Balloon\\Exception do not usually have an error code
132
     *
133
     * @apiErrorExample {json} Error-Response (Invalid Parameter):
134
     * HTTP/1.1 400 Bad Request
135
     * {
136
     *      "status": 400,
137
     *      "data": {
138
     *          "error": "Balloon\\Exception\\InvalidArgument",
139
     *          "message": "invalid node id specified",
140
     *          "code": 0
141
     *      }
142
     * }
143
     *
144
     * @apiErrorExample {json} Error-Response (Insufficient Access):
145
     * HTTP/1.1 403 Forbidden
146
     * {
147
     *      "status": 403,
148
     *      "data": {
149
     *          "error": "Balloon\\Exception\\Forbidden",
150
     *          "message": "not allowed to read node 51354d073c58891f058b4580",
151
     *          "code": 40
152
     *      }
153
     * }
154
     *
155
     * @apiErrorExample {json} Error-Response (Not found):
156
     * HTTP/1.1 404 Not Found
157
     * {
158
     *      "status": 404,
159
     *      "data": {
160
     *          "error": "Balloon\\Exception\\NotFound",
161
     *          "message": "node 51354d073c58891f058b4580 not found",
162
     *          "code": 49
163
     *      }
164
     * }
165
     */
166
167
    /**
168
     * Do bulk operations.
169
     *
170
     * @param array|string $id
171
     * @param array|string $p
172
     */
173
    protected function bulk($id, $p, Closure $action): Response
174
    {
175
        if (is_array($id) || is_array($p)) {
176
            $body = [];
177
            foreach ($this->_getNodes($id, $p) as $node) {
0 ignored issues
show
It seems like $id defined by parameter $id on line 173 can also be of type array; however, Balloon\App\Api\Controller::_getNodes() does only seem to accept string|null, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and 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...
It seems like $p defined by parameter $p on line 173 can also be of type array; however, Balloon\App\Api\Controller::_getNodes() does only seem to accept string|null, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and 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...
178
                try {
179
                    $body[(string) $node->getId()] = $action->call($this, $node);
180
                } catch (\Exception $e) {
181
                    $body[(string) $node->getId()] = [
182
                        'code' => $e instanceof ExceptionInterface ? $e->getStatusCode() : 400,
0 ignored issues
show
The class Micro\Http\ExceptionInterface does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
183
                        'data' => [
184
                            'error' => get_class($e),
185
                            'message' => $e->getMessage(),
186
                            'code' => $e->getCode(),
187
                        ],
188
                    ];
189
                }
190
            }
191
192
            return (new Response())->setCode(207)->setBody($body);
193
        }
194
195
        $body = $action->call($this, $this->_getNode($id, $p));
196
        $response = (new Response())->setCode($body['code']);
197
198
        if (isset($body['data'])) {
199
            $response->setBody($body['data']);
200
        }
201
202
        return $response;
203
    }
204
205
    /**
206
     * Get node.
207
     *
208
     * @param string $id
209
     * @param string $path
210
     * @param string $class      Force set node type
211
     * @param bool   $multiple   Allow $id to be an array
212
     * @param bool   $allow_root Allow instance of root collection
213
     * @param bool   $deleted    How to handle deleted node
214
     */
215
    protected function _getNode(
216
        ?string $id = null,
217
        ?string $path = null,
218
        ?string $class = null,
219
        bool $multiple = false,
220
        bool $allow_root = false,
221
        int $deleted = 2
222
    ): NodeInterface {
223
        if (null === $class) {
224
            switch (get_class($this)) {
225
                case ApiFile::class:
226
                    $class = File::class;
227
228
                break;
229
                case ApiCollection::class:
230
                    $class = Collection::class;
231
232
                break;
233
            }
234
        }
235
236
        return $this->fs->getNode($id, $path, $class, $multiple, $allow_root, $deleted);
237
    }
238
239
    /**
240
     * Get nodes.
241
     *
242
     * @param string $id
243
     * @param string $path
244
     * @param string $class   Force set node type
245
     * @param bool   $deleted How to handle deleted node
246
     */
247
    protected function _getNodes(
248
        $id = null,
249
        $path = null,
250
        ?string $class = null,
251
        int $deleted = 2
252
    ): Generator {
253
        if (null === $class) {
254
            switch (get_class($this)) {
255
                case ApiFile::class:
256
                    $class = File::class;
257
258
                break;
259
                case ApiCollection::class:
260
                    $class = Collection::class;
261
262
                break;
263
            }
264
        }
265
266
        return $this->fs->getNodes($id, $path, $class, $deleted);
267
    }
268
}
269