Completed
Push — master ( c0b3e5...c9ae9e )
by Pavel
03:09
created

FractalResponse::response()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 2
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php namespace Pz\Doctrine\Rest\Response;
2
3
use Doctrine\ORM\QueryBuilder;
4
use Doctrine\ORM\Tools\Pagination\Paginator;
5
use League\Fractal\Manager;
6
use League\Fractal\Pagination\DoctrinePaginatorAdapter;
7
use League\Fractal\Resource\Collection;
8
use League\Fractal\Resource\Item;
9
use League\Fractal\Serializer\JsonApiSerializer;
10
use League\Fractal\TransformerAbstract;
11
12
use Pz\Doctrine\Rest\Contracts\HasResourceKey;
13
use Pz\Doctrine\Rest\Request\CreateRequestInterface;
14
use Pz\Doctrine\Rest\Request\DeleteRequestInterface;
15
use Pz\Doctrine\Rest\Request\IndexRequestInterface;
16
use Pz\Doctrine\Rest\Request\ShowRequestInterface;
17
use Pz\Doctrine\Rest\Request\UpdateRequestInterface;
18
use Pz\Doctrine\Rest\RestException;
19
use Pz\Doctrine\Rest\RestRequestInterface;
20
use Pz\Doctrine\Rest\RestResponse;
21
use Pz\Doctrine\Rest\RestResponseFactory;
22
use Symfony\Component\HttpFoundation\Response;
23
24
25
class FractalResponse implements RestResponseFactory
26
{
27
    const JSON_API_CONTENT_TYPE = 'application/vnd.api+json';
28
29
    /**
30
     * @var TransformerAbstract
31
     */
32
    protected $transformer;
33
34
    /**
35
     * @var string|null
36
     */
37
    protected $baseUrl;
38
39
    /**
40
     * FractalResponse constructor.
41
     *
42
     * @param null $baseUrl
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $baseUrl is correct as it would always require null to be passed?
Loading history...
43
     */
44 12
    public function __construct($baseUrl = null)
45
    {
46 12
        $this->baseUrl = $baseUrl;
47 12
    }
48
49
    /**
50
     * @param TransformerAbstract|null $transformer
51
     *
52
     * @return TransformerAbstract
53
     */
54
    public function transformer(TransformerAbstract $transformer = null)
55
    {
56
        if ($transformer !== null) {
57
            $this->transformer = $transformer;
58
            return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type Pz\Doctrine\Rest\Response\FractalResponse which is incompatible with the documented return type League\Fractal\TransformerAbstract.
Loading history...
59
        }
60
61
        return $this->transformer;
62
    }
63
64
    /**
65
     * @param IndexRequestInterface $request
66
     * @param QueryBuilder          $qb
67
     *
68
     * @return RestResponse
69
     */
70
    public function index(RestRequestInterface $request, QueryBuilder $qb)
71
    {
72
        $paginator = new Paginator($qb, false);
73
        $generator = $this->getPaginatorRouteGenerator($request);
74
        $resource = new Collection($paginator, $this->transformer(), $this->getIndexResourceKey($qb));
75
        $resource->setPaginator(new DoctrinePaginatorAdapter($paginator, $generator));
76
77
        return $this->response(
78
            $this->fractal($request)
79
                ->parseFieldsets($request->getFields())
80
                ->createData($resource)
81
                ->toArray()
82
        );
83
    }
84
85
    /**
86
     * @param ShowRequestInterface $request
87
     * @param             $entity
88
     *
89
     * @return RestResponse
90
     */
91 View Code Duplication
    public function show(RestRequestInterface $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...
92
    {
93
        if ($entity instanceof HasResourceKey) {
94
            $resourceKey = $entity->getResourceKey();
95
        }
96
97
        return $this->response(
98
            $this->fractal($request)
99
                ->parseFieldsets($request->getFields())
100
                ->createData(new Item($entity, $this->transformer(), $resourceKey ?? null))
101
                ->toArray()
102
        );
103
    }
104
105
    /**
106
     * @param CreateRequestInterface $request
107
     * @param               $entity
108
     *
109
     * @return RestResponse
110
     */
111 1 View Code Duplication
    public function create(RestRequestInterface $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...
112
    {
113 1
        if ($entity instanceof HasResourceKey) {
114
            $resourceKey = $entity->getResourceKey();
115
        }
116
117 1
        return $this->response(
118 1
            $this->fractal($request)
119
                ->parseFieldsets($request->getFields())
120
                ->createData(new Item($entity, $this->transformer(), $resourceKey ?? null))
121
                ->toArray(),
122
            Response::HTTP_CREATED
123
        );
124
    }
125
126
    /**
127
     * @param UpdateRequestInterface $request
128
     * @param               $entity
129
     *
130
     * @return RestResponse
131
     */
132 1 View Code Duplication
    public function update(RestRequestInterface $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...
133
    {
134 1
        if ($entity instanceof HasResourceKey) {
135
            $resourceKey = $entity->getResourceKey();
136
        }
137
138 1
        return $this->response(
139 1
            $this->fractal($request)
140
                ->parseFieldsets($request->getFields())
141
                ->createData(new Item($entity, $this->transformer(), $resourceKey ?? null))
142
                ->toArray()
143
        );
144
    }
145
146
    /**
147
     * @param DeleteRequestInterface $request
148
     * @param               $entity
149
     *
150
     * @return RestResponse
151
     */
152 1
    public function delete(RestRequestInterface $request, $entity)
153
    {
154 1
        return $this->response();
155
    }
156
157
    /**
158
     * @param RestRequestInterface $request
159
     *
160
     * @return RestResponse
161
     */
162 3
    public function notFound(RestRequestInterface $request)
163
    {
164 3
        return $this->response(null, RestResponse::HTTP_NOT_FOUND);
165
    }
166
167
    /**
168
     * @param \Error|\Exception|\Pz\Doctrine\Rest\RestException $exception
169
     *
170
     * @return RestResponse
171
     * @throws \Error|\Exception|RestException
172
     */
173 8
    public function exception($exception)
174
    {
175 8
        $message = $exception->getMessage();
176
177
        switch (true) {
178 8
            case ($exception instanceof RestException):
179 5
                $httpStatus = $exception->httpStatus();
180 5
                $errors = $exception->errors();
181 5
                break;
182
183
            default:
184 3
                throw $exception;
185
                // $httpStatus = RestResponse::HTTP_INTERNAL_SERVER_ERROR;
186
                // $errors = $exception->getTrace();
187
                break;
188
        }
189
190 5
        return $this->response(['message' => $message, 'errors' => $errors], $httpStatus);
191
    }
192
193
    /**
194
     * Return configured fractal by request format.
195
     *
196
     * @param RestRequestInterface $request
197
     *
198
     * @return Manager
199
     */
200 2
    protected function fractal(RestRequestInterface $request)
201
    {
202 2
        $fractal = new Manager();
203
204 2
        if ($request->isJsonApi()) {
205
            $fractal->setSerializer(new JsonApiSerializer($this->baseUrl));
206
        }
207
208
        if ($includes = $request->http()->get('include')) {
209
            $fractal->parseIncludes($includes);
210
        }
211
212
        if ($excludes = $request->http()->get('exclude')) {
213
            $fractal->parseExcludes($excludes);
214
        }
215
216
        return $fractal;
217
    }
218
219
    /**
220
     * @param mixed $data
221
     * @param int   $httStatus
222
     *
223
     * @return RestResponse
224
     */
225 9
    protected function response($data = null, $httStatus = RestResponse::HTTP_OK)
226
    {
227 9
        return new RestResponse($data, $httStatus);
228
    }
229
230
    /**
231
     * @param QueryBuilder $qb
232
     *
233
     * @return string
234
     */
235
    protected function getIndexResourceKey(QueryBuilder $qb)
236
    {
237
        $class = $qb->getRootEntities()[0];
238
        if (isset(class_implements($class)[HasResourceKey::class])) {
239
            return call_user_func($class . '::getResourceKey');
240
        }
241
242
        return $qb->getRootAliases()[0];
243
    }
244
245
246
    /**
247
     * @param RestRequestInterface $request
248
     *
249
     * @return \Closure
250
     */
251
    protected function getPaginatorRouteGenerator($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

251
    protected function getPaginatorRouteGenerator(/** @scrutinizer ignore-unused */ $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...
252
    {
253
        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

253
        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...
254
            return null;
255
        };
256
    }
257
}
258