Completed
Push — master ( eef030...971488 )
by Pavel
02:06
created

FractalResponseFactory::delete()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 2
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php namespace Pz\Doctrine\Rest\Response;
2
3
use Pz\Doctrine\Rest\Contracts\JsonApiResource;
4
use League\Fractal\Manager;
5
use League\Fractal\Pagination\DoctrinePaginatorAdapter;
6
use League\Fractal\Resource\Collection;
7
use League\Fractal\Resource\Item;
8
use League\Fractal\Serializer\JsonApiSerializer;
9
use League\Fractal\TransformerAbstract;
10
11
use Pz\Doctrine\Rest\RestException;
12
use Pz\Doctrine\Rest\RestRequest;
13
use Pz\Doctrine\Rest\RestResponse;
14
use Pz\Doctrine\Rest\RestResponseFactory;
15
16
use Doctrine\ORM\QueryBuilder;
17
use Doctrine\ORM\Tools\Pagination\Paginator;
18
19
use Symfony\Component\HttpFoundation\Response;
20
21
class FractalResponseFactory implements RestResponseFactory
22
{
23
    const JSON_API_CONTENT_TYPE = 'application/vnd.api+json';
24
25
    /**
26
     * @var TransformerAbstract
27
     */
28
    protected $transformer;
29
30
    /**
31
     * @var string|null
32
     */
33
    protected $baseUrl;
34
35
    /**
36
     * FractalResponse constructor.
37
     *
38
     * @param string|null              $baseUrl
39
     * @param TransformerAbstract|null $transformer
40
     */
41 6
    public function __construct($baseUrl = null, TransformerAbstract $transformer = null)
42
    {
43 6
        $this->baseUrl = $baseUrl;
44 6
        $this->transformer($transformer);
45 6
    }
46
47
    /**
48
     * @param TransformerAbstract|null $transformer
49
     *
50
     * @return TransformerAbstract
51
     */
52 6
    public function transformer(TransformerAbstract $transformer = null)
53
    {
54 6
        if ($transformer !== null) {
55 6
            $this->transformer = $transformer;
56 6
            return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type Pz\Doctrine\Rest\Response\FractalResponseFactory which is incompatible with the documented return type League\Fractal\TransformerAbstract.
Loading history...
57
        }
58
59 6
        return $this->transformer;
60
    }
61
62
    /**
63
     * @param RestRequest  $request
64
     * @param QueryBuilder $qb
65
     *
66
     * @return RestResponse
67
     */
68 6
    public function index(RestRequest $request, QueryBuilder $qb)
69
    {
70 6
        $headers = [];
71 6
        $resourceKey = $this->getIndexResourceKey($qb);
72 6
        $paginator = new Paginator($qb, false);
73 6
        $resource = new Collection($paginator, $this->transformer(), $resourceKey);
74
75 6
        if ($request->getLimit()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $request->getLimit() of type null|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
76 2
            $resource->setPaginator(new DoctrinePaginatorAdapter($paginator,
77 2
                function(int $page) use ($resourceKey, $request) {
78 1
                    return "{$this->baseUrl}/$resourceKey?" . http_build_query([
79
                        'page' => [
80 1
                            'number'    => $page,
81 1
                            'size'      => $request->getLimit()
82
                        ]
83
                    ]);
84 2
                }
85
            ));
86
        }
87
88 6
        if ($request->isAcceptJsonApi()) {
89 6
            $headers['Content-Type'] = static::JSON_API_CONTENT_TYPE;
90
        }
91
92 6
        return $this->response(
93 6
            $this->fractal($request)
94 6
                ->parseFieldsets($request->getFields())
95 6
                ->createData($resource)
96 6
                ->toArray(),
97 6
            RestResponse::HTTP_OK,
98 6
            $headers
99
        );
100
    }
101
102
    /**
103
     * @param RestRequest $request
104
     * @param object      $entity
105
     *
106
     * @return RestResponse
107
     */
108 View Code Duplication
    public function show(RestRequest $request, $entity)
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...
109
    {
110
        $headers = [];
111
        $resourceKey = null;
112
113
        if ($entity instanceof JsonApiResource) {
114
            $resourceKey = $entity->getResourceKey();
115
116
            if ($request->isAcceptJsonApi()) {
117
                $headers['Location'] = $this->linkJsonApiResource($entity);
118
                $headers['Content-Type'] = static::JSON_API_CONTENT_TYPE;
119
            }
120
        }
121
122
        return $this->response(
123
            $this->fractal($request)
124
                ->parseFieldsets($request->getFields())
125
                ->createData(new Item($entity, $this->transformer(), $resourceKey ?? null))
126
                ->toArray(),
127
            RestResponse::HTTP_OK,
128
            $headers
129
        );
130
    }
131
132
    /**
133
     * @param RestRequest $request
134
     * @param object      $entity
135
     *
136
     * @return RestResponse
137
     */
138 View Code Duplication
    public function create(RestRequest $request, $entity)
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...
139
    {
140
        $headers = [];
141
        $resourceKey = null;
142
143
        if ($entity instanceof JsonApiResource) {
144
            $resourceKey = $entity->getResourceKey();
145
146
            if ($request->isAcceptJsonApi()) {
147
                $headers['Location'] = $this->linkJsonApiResource($entity);
148
                $headers['Content-Type'] = static::JSON_API_CONTENT_TYPE;
149
            }
150
        }
151
152
        return $this->response(
153
            $this->fractal($request)
154
                ->parseFieldsets($request->getFields())
155
                ->createData(new Item($entity, $this->transformer(), $resourceKey))
156
                ->toArray(),
157
            Response::HTTP_CREATED,
158
            $headers
159
        );
160
    }
161
162
    /**
163
     * @param RestRequest $request
164
     * @param object      $entity
165
     *
166
     * @return RestResponse
167
     */
168 View Code Duplication
    public function update(RestRequest $request, $entity)
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...
169
    {
170
        $headers = [];
171
        $resourceKey = null;
172
173
        if ($entity instanceof JsonApiResource) {
174
            $resourceKey = $entity->getResourceKey();
175
176
            if ($request->isAcceptJsonApi()) {
177
                $headers['Location'] = $this->linkJsonApiResource($entity);
178
                $headers['Content-Type'] = static::JSON_API_CONTENT_TYPE;
179
            }
180
        }
181
182
        return $this->response(
183
            $this->fractal($request)
184
                ->parseFieldsets($request->getFields())
185
                ->createData(new Item($entity, $this->transformer(), $resourceKey))
186
                ->toArray(),
187
            Response::HTTP_OK,
188
            $headers
189
        );
190
    }
191
192
    /**
193
     * @param RestRequest $request
194
     * @param object      $entity
195
     *
196
     * @return RestResponse
197
     */
198
    public function delete(RestRequest $request, $entity)
199
    {
200
        return $this->response(null, RestResponse::HTTP_NO_CONTENT);
201
    }
202
203
    /**
204
     * @param RestRequest $request
205
     *
206
     * @return RestResponse
207
     */
208
    public function notFound(RestRequest $request)
209
    {
210
        return $this->response(null, RestResponse::HTTP_NOT_FOUND);
211
    }
212
213
    /**
214
     * @param \Error|\Exception|\Pz\Doctrine\Rest\RestException $exception
215
     *
216
     * @return RestResponse
217
     * @throws \Error|\Exception|RestException
218
     */
219
    public function exception($exception)
220
    {
221
        $message = $exception->getMessage();
222
223
        switch (true) {
224
            case ($exception instanceof RestException):
225
                $httpStatus = $exception->httpStatus();
226
                $errors = $exception->errors();
227
                break;
228
229
            default:
230
                throw $exception;
231
                // $httpStatus = RestResponse::HTTP_INTERNAL_SERVER_ERROR;
232
                // $errors = $exception->getTrace();
233
                break;
234
        }
235
236
        return $this->response(['message' => $message, 'errors' => $errors], $httpStatus);
237
    }
238
239
    /**
240
     * Return configured fractal by request format.
241
     *
242
     * @param RestRequest $request
243
     *
244
     * @return Manager
245
     */
246 6
    protected function fractal(RestRequest $request)
247
    {
248 6
        $fractal = new Manager();
249
250 6
        if ($request->isAcceptJsonApi()) {
251 6
            $fractal->setSerializer(new JsonApiSerializer($this->baseUrl));
252
        }
253
254 6
        if ($includes = $request->getInclude()) {
255 2
            $fractal->parseIncludes($includes);
256
        }
257
258 6
        if ($excludes = $request->getExclude()) {
259
            $fractal->parseExcludes($excludes);
260
        }
261
262 6
        return $fractal;
263
    }
264
265
    /**
266
     * @param mixed $data
267
     * @param int   $httStatus
268
     * @param array $headers
269
     *
270
     * @return RestResponse
271
     */
272 6
    protected function response($data = null, $httStatus = RestResponse::HTTP_OK, array $headers = [])
273
    {
274 6
        return new RestResponse($data, $httStatus, $headers);
275
    }
276
277
    /**
278
     * @param QueryBuilder $qb
279
     *
280
     * @return string
281
     */
282 6
    protected function getIndexResourceKey(QueryBuilder $qb)
283
    {
284 6
        $class = $qb->getRootEntities()[0];
285 6
        if (isset(class_implements($class)[JsonApiResource::class])) {
286 6
            return call_user_func($class . '::getResourceKey');
287
        }
288
289
        return $qb->getRootAliases()[0];
290
    }
291
292
    /**
293
     * @param JsonApiResource $resource
294
     *
295
     * @return string|null
296
     */
297
    protected function linkJsonApiResource(JsonApiResource $resource)
298
    {
299
        return sprintf('%s/%s/%s', $this->baseUrl, $resource->getResourceKey(), $resource->getId());
300
    }
301
302
    /**
303
     * @param RestRequest $request
304
     *
305
     * @return \Closure
306
     */
307
    protected function getPaginatorRouteGenerator(RestRequest $request)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

307
    protected function getPaginatorRouteGenerator(/** @scrutinizer ignore-unused */ RestRequest $request)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
308
    {
309
        return function(int $page) {
0 ignored issues
show
Unused Code introduced by
The parameter $page is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

309
        return function(/** @scrutinizer ignore-unused */ int $page) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
310
            return null;
311
        };
312
    }
313
}
314