ResponseConverter::start()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2.0625

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 3
c 1
b 0
f 0
dl 0
loc 7
ccs 3
cts 4
cp 0.75
rs 10
cc 2
nc 2
nop 1
crap 2.0625
1
<?php
2
3
declare(strict_types=1);
4
5
namespace jin2chen\ApiBundle\Response;
6
7
use League\Fractal\Manager as Fractal;
8
use League\Fractal\Resource\Collection;
9
use League\Fractal\Resource\ResourceAbstract;
10
use League\Fractal\Serializer\SerializerAbstract as Serializer;
11
use Symfony\Component\HttpFoundation\JsonResponse;
12
use Symfony\Component\Stopwatch\Stopwatch;
13
14
use function implode;
15
use function sprintf;
16
17
use const JSON_UNESCAPED_UNICODE;
18
19
/**
20
 * Converts a response type to an appropriate response format.
21
 */
22
final class ResponseConverter
23
{
24
    private Fractal $fractal;
25
    private ?Stopwatch $stopwatch;
26
27 2
    public function __construct(Fractal $fractal, Serializer $serializer, Stopwatch $stopwatch = null)
28
    {
29 2
        $this->fractal = $fractal;
30 2
        $this->stopwatch = $stopwatch;
31
32 2
        $this->setSerializer($serializer);
33 2
    }
34
35 2
    public function setSerializer(Serializer $serializer): self
36
    {
37 2
        $this->fractal->setSerializer($serializer);
38
39 2
        return $this;
40
    }
41
42
    public function toArray(ResponseTypeInterface $type): array
43
    {
44
        $this->processIncludes($type);
45
46
        return $this->createData($type->asResource());
47
    }
48
49 2
    public function toJson(ResponseTypeInterface $type): JsonResponse
50
    {
51 2
        $resource = $type->asResource();
52
53 2
        $this->processIncludes($type);
54
55 2
        return $this->createResponse($resource, $this->createData($resource));
56
    }
57
58 2
    private function processIncludes(ResponseTypeInterface $type): void
59
    {
60 2
        $this->profile('fractal.process_includes', fn() => $this->fractal->parseIncludes($type->getIncludes()));
61 2
    }
62
63 2
    private function createData(ResourceAbstract $resource): array
64
    {
65 2
        return (array) $this->profile(
66 2
            'fractal.create_data_array',
67 2
            fn() => $this->fractal->createData($resource)->toArray()
68 2
        );
69
    }
70
71 2
    private function createResponse(ResourceAbstract $resource, array $data): JsonResponse
72
    {
73
        /** @var JsonResponse $response */
74 2
        $response = $this->profile(
75 2
            'fractal.create_json_response',
76 2
            fn() => (new JsonResponse($data))->setEncodingOptions(JSON_UNESCAPED_UNICODE)
77 2
        );
78
79 2
        if ($resource instanceof Collection && $resource->hasPaginator()) {
80
            $paginator = $resource->getPaginator();
81
82
            $header = [];
83
            if (($paginator->getCurrentPage() - 1) > 0) {
84
                $header[] = sprintf('%s; rel="previous"', $paginator->getUrl($paginator->getCurrentPage() - 1));
85
            }
86
            if (($paginator->getCurrentPage() + 1) <= $paginator->getLastPage()) {
87
                $header[] = sprintf('%s; rel="next"', $paginator->getUrl($paginator->getCurrentPage() + 1));
88
            }
89
90
            $response->headers->add(
91
                [
92
                    'X-API-Pagination-TotalResults' => $paginator->getTotal(),
93
                    'X-API-Pagination-Page' => $paginator->getCurrentPage(),
94
                    'X-API-Pagination-PageCount' => $paginator->getLastPage(),
95
                    'X-API-Pagination-PageResults' => $paginator->getCount(),
96
                    'X-API-Pagination-PageSize' => $paginator->getPerPage(),
97
                    'Link' => implode(', ', $header),
98
                ]
99
            );
100
        }
101
102 2
        return $response;
103
    }
104
105 2
    private function profile(string $segment, callable $callback): mixed
106
    {
107 2
        $this->start($segment);
108
        /** @var mixed $return */
109 2
        $return = $callback();
110 2
        $this->stop($segment);
111
112 2
        return $return;
113
    }
114
115 2
    private function start(string $name): void
116
    {
117 2
        if (!$this->stopwatch) {
118
            return;
119
        }
120
121 2
        $this->stopwatch->start($name);
122 2
    }
123
124 2
    private function stop(string $name): void
125
    {
126 2
        if (!$this->stopwatch) {
127
            return;
128
        }
129
130 2
        $this->stopwatch->stop($name);
131 2
    }
132
}
133