Passed
Push — master ( 8b9203...a62a07 )
by Kévin
03:38
created

FormatsResourceMetadataFactory   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 95
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 44
dl 0
loc 95
rs 10
c 1
b 0
f 0
wmc 21

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
B create() 0 25 7
A normalizeFormats() 0 22 5
B normalize() 0 19 8
1
<?php
2
3
/*
4
 * This file is part of the API Platform project.
5
 *
6
 * (c) Kévin Dunglas <[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 ApiPlatform\Core\Metadata\Resource\Factory;
15
16
use ApiPlatform\Core\Exception\InvalidArgumentException;
17
use ApiPlatform\Core\Exception\ResourceClassNotFoundException;
18
use ApiPlatform\Core\Metadata\Resource\ResourceMetadata;
19
20
/**
21
 * Normalizes enabled formats.
22
 *
23
 * Formats hierarchy:
24
 * * resource formats
25
 *   * resource input/output formats
26
 *     * operation formats
27
 *       * operation input/output formats
28
 *
29
 * @author Kévin Dunglas <[email protected]>
30
 */
31
final class FormatsResourceMetadataFactory implements ResourceMetadataFactoryInterface
32
{
33
    private $decorated;
34
    private $formats;
35
    private $patchFormats;
36
37
    public function __construct(ResourceMetadataFactoryInterface $decorated, array $formats, array $patchFormats)
38
    {
39
        $this->decorated = $decorated;
40
        $this->formats = $formats;
41
        $this->patchFormats = $patchFormats;
42
    }
43
44
    /**
45
     * Adds the formats attributes.
46
     *
47
     * @see OperationResourceMetadataFactory
48
     *
49
     * @throws ResourceClassNotFoundException
50
     */
51
    public function create(string $resourceClass): ResourceMetadata
52
    {
53
        $resourceMetadata = $this->decorated->create($resourceClass);
54
        $rawResourceFormats = $resourceMetadata->getAttribute('formats');
55
        $resourceFormats = null === $rawResourceFormats ? $this->formats : $this->normalizeFormats($rawResourceFormats);
56
57
        $rawResourceInputFormats = $resourceMetadata->getAttribute('input_formats');
58
        $rawResourceOutputFormats = $resourceMetadata->getAttribute('output_formats');
59
60
        $resourceInputFormats = $rawResourceInputFormats ? $this->normalizeFormats($rawResourceInputFormats) : $resourceFormats;
61
        $resourceOutputFormats = $rawResourceOutputFormats ? $this->normalizeFormats($rawResourceOutputFormats) : $resourceFormats;
62
63
        if (null !== $collectionOperations = $resourceMetadata->getCollectionOperations()) {
64
            $resourceMetadata = $resourceMetadata->withCollectionOperations($this->normalize($resourceInputFormats, $resourceOutputFormats, $collectionOperations));
65
        }
66
67
        if (null !== $itemOperations = $resourceMetadata->getItemOperations()) {
68
            $resourceMetadata = $resourceMetadata->withItemOperations($this->normalize($resourceInputFormats, $resourceOutputFormats, $itemOperations));
69
        }
70
71
        if (null !== $subresourceOperations = $resourceMetadata->getSubresourceOperations()) {
72
            $resourceMetadata = $resourceMetadata->withSubresourceOperations($this->normalize($resourceInputFormats, $resourceOutputFormats, $subresourceOperations));
73
        }
74
75
        return $resourceMetadata;
76
    }
77
78
    private function normalize(array $resourceInputFormats, array $resourceOutputFormats, array $operations): array
79
    {
80
        $newOperations = [];
81
        foreach ($operations as $operationName => $operation) {
82
            if ('PATCH' === ($operation['method'] ?? '') && !isset($operation['formats']) && !isset($operation['input_formats'])) {
83
                $operation['input_formats'] = $this->patchFormats;
84
            }
85
86
            if (isset($operation['formats'])) {
87
                $operation['formats'] = $this->normalizeFormats($operation['formats']);
88
            }
89
90
            $operation['input_formats'] = isset($operation['input_formats']) ? $this->normalizeFormats($operation['input_formats']) : $operation['formats'] ?? $resourceInputFormats;
91
            $operation['output_formats'] = isset($operation['output_formats']) ? $this->normalizeFormats($operation['output_formats']) : $operation['formats'] ?? $resourceOutputFormats;
92
93
            $newOperations[$operationName] = $operation;
94
        }
95
96
        return $newOperations;
97
    }
98
99
    /**
100
     * @param array|string $currentFormats
101
     *
102
     * @throws InvalidArgumentException
103
     */
104
    private function normalizeFormats($currentFormats): array
105
    {
106
        $currentFormats = (array) $currentFormats;
107
108
        $normalizedFormats = [];
109
        foreach ($currentFormats as $format => $value) {
110
            if (!is_numeric($format)) {
111
                $normalizedFormats[$format] = (array) $value;
112
                continue;
113
            }
114
            if (!\is_string($value)) {
115
                throw new InvalidArgumentException(sprintf("The 'formats' attributes value must be a string when trying to include an already configured format, %s given.", \gettype($value)));
116
            }
117
            if (\array_key_exists($value, $this->formats)) {
118
                $normalizedFormats[$value] = $this->formats[$value];
119
                continue;
120
            }
121
122
            throw new InvalidArgumentException(sprintf("You either need to add the format '%s' to your project configuration or declare a mime type for it in your annotation.", $value));
123
        }
124
125
        return $normalizedFormats;
126
    }
127
}
128