Completed
Push — staging ( 5f9089...8e7d49 )
by Matthew
04:33
created

getIncludesFromRequest()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 8
rs 9.4285
cc 2
eloc 4
nc 2
nop 1
1
<?php
2
3
namespace Ps2alerts\Api\Controller\Endpoint;
4
5
use League\Fractal\Resource\Collection;
6
use League\Fractal\Resource\Item;
7
use Ps2alerts\Api\Contract\DatabaseAwareInterface;
8
use Ps2alerts\Api\Contract\DatabaseAwareTrait;
9
use Symfony\Component\HttpFoundation\Request;
10
use Symfony\Component\HttpFoundation\Response;
11
12
abstract class AbstractEndpointController implements
13
    DatabaseAwareInterface
14
{
15
    use DatabaseAwareTrait;
16
17
    /**
18
     * Contains the repository used for interfacing with the database
19
     *
20
     * @var Mixed | Ps2alerts\Api\Repository\AbstractEndpointRepository
21
     */
22
    protected $repository;
23
24
    /**
25
     * Stores the status code
26
     *
27
     * @var integer
28
     */
29
    protected $statusCode = 200;
30
31
    /**
32
     * Holds Fractal
33
     *
34
     * @var \League\Fractal
35
     */
36
    protected $fractal;
37
38
    /**
39
     * Holds the transformer we're going to use
40
     *
41
     * @var mixed|\Leage\Fractal\TransformerAbstract
42
     */
43
    protected $transformer;
44
45
    const CODE_WRONG_ARGS     = 'API-MALFORMED-REQUEST';
46
    const CODE_NOT_FOUND      = 'API-NOT-FOUND';
47
    const CODE_INTERNAL_ERROR = 'API-DOH';
48
    const CODE_UNAUTHORIZED   = 'API-UNAUTHORIZED';
49
    const CODE_FORBIDDEN      = 'API-DENIED';
50
    const CODE_EMPTY          = 'API-EMPTY';
51
52
    /**
53
     * Getter for statusCode
54
     *
55
     * @return int
56
     */
57
    public function getStatusCode()
58
    {
59
        return $this->statusCode;
60
    }
61
62
    /**
63
     * Setter for statusCode
64
     *
65
     * @param int $statusCode Value to set
66
     *
67
     * @return self
68
     */
69
    public function setStatusCode($statusCode)
70
    {
71
        $this->statusCode = $statusCode;
72
        return $this;
73
    }
74
75
    /**
76
     * Master function to split out appropiate calls
77
     *
78
     * @param  string                                     $kind     The kind of data we wish to return
79
     * @param  array                                      $data     The data itself
80
     * @param  \League\Fractal\TransformerAbstract        $callback The transformer class to call
81
     * @param  \Symfony\Component\HttpFoundation\Request  $request  The request itself
82
     * @param  \Symfony\Component\HttpFoundation\Response $response The response object to eventually call
83
     *
84
     * @return \Symfony\Component\HttpFoundation\Response           Eventually
85
     */
86
    protected function respond($kind, $data, $callback, Request $request, Response $response)
87
    {
88
        // Detect what embeds we need
89
        $this->getIncludesFromRequest($request);
90
        switch ($kind) {
91
            case 'item':
92
                return $this->respondWithItem($data, $callback, $response);
93
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
94
            case 'collection':
95
                return $this->respondWithCollection($data, $callback, $response);
96
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
97
            default:
98
                return $this->errorInternalError('No Response was defined. Please report this.');
0 ignored issues
show
Documentation introduced by
'No Response was defined. Please report this.' is of type string, but the function expects a object<Symfony\Component\HttpFoundation\Response>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
99
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
100
        }
101
    }
102
103
    /**
104
     * Builds an item response in Fractal then hands off to the responder
105
     *
106
     * @param  array $item                                The item to transform
107
     * @param  mixed $callback                            The Transformer to pass through to Fractal
108
     * @param  \Symfony\Component\HttpFoundation\Response The client's response
109
     *
110
     * @return array                                     The formatted array
111
     */
112 View Code Duplication
    protected function respondWithItem($item, $callback, Response $response)
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...
113
    {
114
        $resource = new Item($item, $callback);
115
        $rootScope = $this->fractal->createData($resource);
116
117
        return $this->respondWithArray($response, $rootScope->toArray());
118
    }
119
120
    /**
121
     * Builds a collection of items from Fractal then hands off to the responder
122
     *
123
     * @param  array $collection                         The collection to transform
124
     * @param  mixed $callback                           The Transformer to pass through to Fractal
125
     * @param  \Symfony\Component\HttpFoundation\Response The client's response
126
     *
127
     * @return array                                     The formatted array
128
     */
129 View Code Duplication
    protected function respondWithCollection($collection, $callback, Response $response)
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...
130
    {
131
        $resource = new Collection($collection, $callback);
132
        $rootScope = $this->fractal->createData($resource);
133
134
        return $this->respondWithArray($response, $rootScope->toArray());
135
    }
136
137
    /**
138
     * The final step where the formatted array is now sent back as a response in JSON form
139
     *
140
     * @param  \Symfony\Component\HttpFoundation\Response $response
141
     * @param  array                                     $array     The formatted array
142
     *
143
     * @return \Symfony\Component\HttpFoundation\Response           The final response
144
     */
145
    protected function respondWithArray(Response $response, array $array)
146
    {
147
        $response->setStatusCode($this->getStatusCode());
148
        $response->setContent(json_encode($array));
149
        $response->headers->set('Content-Type', 'application/json');
150
151
        // This is the end of the road. FIRE ZE RESPONSE!
152
        return $response;
153
    }
154
155
    /**
156
     * Responds gracefully with an error.
157
     *
158
     * @param  \Symfony\Component\HttpFoundation\Response  $response
159
     * @param  string                                      $message   Response message to put in the error
160
     * @param  int                                         $errorCode Error code to set
161
     *
162
     * @return array
163
     */
164
    protected function respondWithError(Response $response, $message, $errorCode)
165
    {
166
        if ($this->statusCode === 200) {
167
            trigger_error(
168
                "This Error code 200 should never be sent. Please report this to the developer.",
169
                E_USER_WARNING
170
            );
171
        }
172
173
        // Pass to responder
174
        return $this->respondWithArray($response, [
175
            'error' => [
176
                'code'      => $errorCode,
177
                'http_code' => $this->statusCode,
178
                'message'   => $message,
179
            ]
180
        ]);
181
    }
182
183
    /**
184
     * Generates a response with a 404 HTTP error and a given message.
185
     *
186
     * @param  \Symfony\Component\HttpFoundation\Response $response
187
     * @param  string                                     $message
188
     *
189
     * @return void
190
     */
191
    public function errorEmpty(Response $response, $message = 'No data / Empty')
192
    {
193
        return $this->setStatusCode(404)
194
                    ->respondWithError($response, $message, self::CODE_EMPTY);
195
    }
196
197
    /**
198
     * Generates a Response with a 403 HTTP header and a given message.
199
     *
200
     * @param  \Symfony\Component\HttpFoundation\Response $response
201
     * @param  string                                     $message
202
     *
203
     * @return void
204
     */
205
    public function errorForbidden(Response $response, $message = 'Forbidden')
206
    {
207
        return $this->setStatusCode(403)
208
                    ->respondWithError($response, $message, self::CODE_FORBIDDEN);
209
    }
210
211
    /**
212
     * Generates a Response with a 500 HTTP header and a given message.
213
     *
214
     * @param  \Symfony\Component\HttpFoundation\Response $response
215
     * @param  string                                     $message
216
     *
217
     * @return void
218
     */
219
    public function errorInternalError(Response $response, $message = 'Internal Error')
220
    {
221
        return $this->setStatusCode(500)
222
                    ->respondWithError($response, $message, self::CODE_INTERNAL_ERROR);
223
    }
224
225
    /**
226
     * Generates a Response with a 404 HTTP header and a given message.
227
     *
228
     * @param  \Symfony\Component\HttpFoundation\Response $response
229
     * @param  string                                     $message
230
     *
231
     * @return void
232
     */
233
    public function errorNotFound(Response $response, $message = 'Resource Not Found')
234
    {
235
        return $this->setStatusCode(404)
236
                    ->respondWithError($response, $message, self::CODE_NOT_FOUND);
237
    }
238
239
    /**
240
     * Generates a Response with a 401 HTTP header and a given message.
241
     *
242
     * @param  \Symfony\Component\HttpFoundation\Response $response
243
     * @param  string                                     $message
244
     *
245
     * @return void
246
     */
247
    public function errorUnauthorized(Response $response, $message = 'Unauthorized')
248
    {
249
        return $this->setStatusCode(401)
250
                    ->respondWithError($response, $message, self::CODE_UNAUTHORIZED);
251
    }
252
253
    /**
254
     * Generates a Response with a 400 HTTP header and a given message.
255
     *
256
     * @return \Symfony\Component\HttpFoundation\Response
257
     */
258
    public function errorWrongArgs(Response $response, $message = 'Wrong Arguments')
259
    {
260
        return $this->setStatusCode(400)
261
                    ->respondWithError($response, $message, self::CODE_WRONG_ARGS);
262
    }
263
264
    /**
265
     * Reads any requested includes and adds them to the item / collection
266
     *
267
     * @param  Symfony\Component\HttpFoundation\Request
268
     *
269
     * @return void
270
     */
271
    public function getIncludesFromRequest(Request $request)
272
    {
273
        $queryString = $request->query->get('embed');
274
275
        if (! empty($queryString)) {
276
            $this->fractal->parseIncludes($request->query->get('embed'));
277
        }
278
    }
279
}
280