Passed
Pull Request — master (#52)
by Daniel
05:20
created

UploadableNormalizer::denormalize()   A

Complexity

Conditions 6
Paths 7

Size

Total Lines 32
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 17
dl 0
loc 32
ccs 0
cts 16
cp 0
rs 9.0777
c 1
b 0
f 0
cc 6
nc 7
nop 4
crap 42
1
<?php
2
3
/*
4
 * This file is part of the Silverback API Component Bundle Project
5
 *
6
 * (c) Daniel West <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace Silverback\ApiComponentBundle\Serializer\Normalizer;
15
16
use ApiPlatform\Core\EventListener\DeserializeListener;
17
use ApiPlatform\Core\Metadata\Resource\ToggleableOperationAttributeTrait;
18
use ApiPlatform\Core\Util\RequestAttributesExtractor;
19
use Ramsey\Uuid\Uuid;
20
use Silverback\ApiComponentBundle\AnnotationReader\UploadableAnnotationReader;
21
use Silverback\ApiComponentBundle\Model\Uploadable\Base64EncodedFile;
22
use Silverback\ApiComponentBundle\Model\Uploadable\UploadedBase64EncodedFile;
23
use Symfony\Component\HttpFoundation\File\Exception\FileException;
24
use Symfony\Component\HttpFoundation\RequestStack;
25
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
26
use Symfony\Component\Serializer\Normalizer\CacheableSupportsMethodInterface;
27
use Symfony\Component\Serializer\Normalizer\ContextAwareDenormalizerInterface;
28
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface;
29
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareTrait;
30
31
/**
32
 * @author Vincent Chalamon <[email protected]>
33
 */
34
final class UploadableNormalizer implements CacheableSupportsMethodInterface, ContextAwareDenormalizerInterface, DenormalizerAwareInterface
35
{
36
    use ToggleableOperationAttributeTrait;
37
    use DenormalizerAwareTrait;
38
39
    private const ALREADY_CALLED = 'UPLOADABLE_NORMALIZER_ALREADY_CALLED';
40
41
    private UploadableAnnotationReader $uploadableHelper;
42
    private RequestStack $requestStack;
43
44
    public function __construct(UploadableAnnotationReader $uploadableHelper, RequestStack $requestStack)
45
    {
46
        $this->uploadableHelper = $uploadableHelper;
47
        $this->requestStack = $requestStack;
48
    }
49
50
    /**
51
     * {@inheritdoc}
52
     */
53
    public function denormalize($data, $type, $format = null, array $context = [])
54
    {
55
        $context[self::ALREADY_CALLED] = true;
56
57
        foreach ($data as $fieldName => $value) {
58
            try {
59
                $reflectionProperty = new \ReflectionProperty($type, $fieldName);
60
            } catch (\ReflectionException $exception) {
61
                // Property does not exist on class: just ignore it.
62
                continue;
63
            }
64
65
            // Property is not an UploadableField: just ignore it.
66
            if (!$this->uploadableHelper->isFieldConfigured($reflectionProperty)) {
67
                continue;
68
            }
69
70
            // Value is empty: set it to null.
71
            if (empty($value)) {
72
                $data[$fieldName] = null;
73
                continue;
74
            }
75
76
            try {
77
                $file = new Base64EncodedFile($value);
78
                $data[$fieldName] = new UploadedBase64EncodedFile($file, Uuid::uuid4() . '.' . $file->getExtension());
79
            } catch (FileException $exception) {
80
                throw new NotNormalizableValueException($exception->getMessage());
81
            }
82
        }
83
84
        return $this->denormalizer->denormalize($data, $type, $format, $context);
85
    }
86
87
    /**
88
     * {@inheritdoc}
89
     */
90
    public function supportsDenormalization($data, $type, $format = null, array $context = []): bool
91
    {
92
        $request = $this->requestStack->getMasterRequest();
93
        if (!$request) {
94
            $isDisabled = false;
95
        } else {
96
            $attributes = RequestAttributesExtractor::extractAttributes($request);
97
            $isDisabled = $this->isOperationAttributeDisabled($attributes, DeserializeListener::OPERATION_ATTRIBUTE_KEY);
98
        }
99
100
        return !$isDisabled && !isset($context[self::ALREADY_CALLED]) && $this->uploadableHelper->isConfigured($type);
101
    }
102
103
    public function hasCacheableSupportsMethod(): bool
104
    {
105
        return false;
106
    }
107
}
108