Completed
Push — master ( 0be8e1...585ca2 )
by Daniel
59:26 queued 46:02
created

FileUploadAction::__invoke()   B

Complexity

Conditions 10
Paths 9

Size

Total Lines 71
Code Lines 38

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 110

Importance

Changes 0
Metric Value
eloc 38
dl 0
loc 71
ccs 0
cts 25
cp 0
rs 7.6666
c 0
b 0
f 0
cc 10
nc 9
nop 3
crap 110

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Silverback\ApiComponentBundle\Controller;
4
5
use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
6
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
7
use InvalidArgumentException;
8
use RuntimeException;
9
use Silverback\ApiComponentBundle\Entity\Component\FileInterface;
10
use Silverback\ApiComponentBundle\File\Uploader\FileUploader;
11
use Silverback\ApiComponentBundle\Serializer\ApiContextBuilder;
12
use Symfony\Component\HttpFoundation\BinaryFileResponse;
13
use Symfony\Component\HttpFoundation\Request;
14
use Symfony\Component\HttpFoundation\Response;
15
use Symfony\Component\PropertyAccess\PropertyAccess;
16
use Symfony\Component\Routing\Annotation\Route;
17
use Symfony\Component\Routing\Matcher\UrlMatcherInterface;
18
use Symfony\Component\Routing\RequestContext;
19
use Symfony\Component\Serializer\SerializerInterface;
20
21
class FileUploadAction
22
{
23
    private $urlMatcher;
24
    private $itemDataProvider;
25
    private $uploader;
26
    private $serializer;
27
    private $resourceMetadataFactory;
28
    private $apiContextBuilder;
29
30
    public function __construct(
31
        UrlMatcherInterface $urlMatcher,
32
        ItemDataProviderInterface $itemDataProvider,
33
        FileUploader $uploader,
34
        SerializerInterface $serializer,
35
        ResourceMetadataFactoryInterface $resourceMetadataFactory,
36
        ApiContextBuilder $apiContextBuilder
37
    ) {
38
        $this->urlMatcher = $urlMatcher;
39
        $this->itemDataProvider = $itemDataProvider;
40
        $this->uploader = $uploader;
41
        $this->serializer = $serializer;
42
        $this->resourceMetadataFactory = $resourceMetadataFactory;
43
        $this->apiContextBuilder = $apiContextBuilder;
44
    }
45
46
    /**
47
     * @param Request $request
48
     * @param string $field
49
     * @param string $id
50
     * @Route(
51
     *     name="files_upload",
52
     *     path="/files/{field}/{id}.{_format}",
53
     *     requirements={"field"="\w+", "id"=".+"},
54
     *     defaults={"_format"="jsonld"},
55
     *     methods={"POST", "PUT", "GET"}
56
     * )
57
     * @return Response
58
     */
59
    public function __invoke(Request $request, string $field, string $id)
60
    {
61
        $contentType = $request->headers->get('CONTENT_TYPE');
62
        $_format = $request->attributes->get('_format') ?: $request->getFormat($contentType);
63
64
        /**
65
         * MATCH THE ID TO A ROUTE TO FIND RESOURCE CLASS AND ID
66
         * @var array|null $route
67
         */
68
        $ctx = new RequestContext();
69
        $ctx->fromRequest($request);
70
        $ctx->setMethod('GET');
71
        $this->urlMatcher->setContext($ctx);
72
        $route = $this->urlMatcher->match($id);
73
        if (empty($route)) {
74
            return new Response(sprintf('No route found for id %s', $id), Response::HTTP_BAD_REQUEST);
75
        }
76
77
        /**
78
         * GET THE ENTITY
79
         */
80
        $entity = $this->itemDataProvider->getItem($route['_api_resource_class'], $route['id']);
81
        if (!$entity) {
82
            return new Response(sprintf('Entity not found from provider %s (ID: %s)', $route['_api_resource_class'], $route['id']), Response::HTTP_BAD_REQUEST);
83
        }
84
        if (!($entity instanceof FileInterface)) {
85
            return new Response(sprintf('Provider %s does not implement %s', $route['_api_resource_class'], FileInterface::class), Response::HTTP_BAD_REQUEST);
86
        }
87
        $method = strtolower($request->getMethod());
88
89
        if ($method === 'get') {
90
            $propertyAccessor = PropertyAccess::createPropertyAccessor();
91
            $filePath = $propertyAccessor->getValue($entity, $field);
92
            return new BinaryFileResponse($filePath);
93
        }
94
95
        /**
96
         * CHECK WE HAVE A FILE - WASTE OF TIME DOING ANYTHING ELSE OTHERWISE
97
         */
98
        if (!$request->files->count()) {
99
            return new Response('No files have been submitted', Response::HTTP_BAD_REQUEST);
100
        }
101
102
        /**
103
         * UPLOAD THE FILE
104
         */
105
        $files = $request->files->all();
106
        try {
107
            $entity = $this->uploader->upload($entity, $field, reset($files), $method);
108
        } catch (InvalidArgumentException $exception) {
109
            return new Response($exception->getMessage(), Response::HTTP_BAD_REQUEST);
110
        } catch (RuntimeException $exception) {
111
            return new Response($exception->getMessage(), Response::HTTP_INTERNAL_SERVER_ERROR);
112
        }
113
114
        /**
115
         * Return the entity back in the format requested
116
         */
117
        $resourceMetadata = $this->resourceMetadataFactory->create($route['_api_resource_class']);
118
        $serializerGroups = $resourceMetadata->getOperationAttribute(
119
            ['item_operation_name' => $method],
120
            'serializer_groups',
121
            [],
122
            true
123
        );
124
        $customGroups = $this->apiContextBuilder->getGroups($route['_api_resource_class'], true);
125
        if (\count($customGroups)) {
126
            $serializerGroups = array_merge($serializerGroups ?? [], ...$customGroups);
127
        }
128
        $serializedData = $this->serializer->serialize($entity, $_format, ['groups' => $serializerGroups]);
129
        return new Response($serializedData, Response::HTTP_OK);
130
    }
131
}
132