ApiResourceMetadataParser   A
last analyzed

Complexity

Total Complexity 21

Size/Duplication

Total Lines 117
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
wmc 21
lcom 1
cbo 4
dl 0
loc 117
rs 10
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A supports() 0 4 1
A parse() 0 6 1
B doParse() 0 32 5
C resolveActualType() 0 51 13
1
<?php
2
3
/*
4
 * This file is part of the "elao/api-resources-metadata" package.
5
 *
6
 * Copyright (C) 2016 Elao
7
 *
8
 * @author Elao <[email protected]>
9
 */
10
11
namespace Elao\ApiResourcesMetadata\Bridge\Nelmio\ApiDoc\Parser;
12
13
use Elao\ApiResourcesMetadata\Attribute\ResourceAttributeMetadata;
14
use Elao\ApiResourcesMetadata\Resource\Factory\ResourceMetadataFactory;
15
use Elao\ApiResourcesMetadata\Resource\ResourceIndex;
16
use Nelmio\ApiDocBundle\DataTypes;
17
use Nelmio\ApiDocBundle\Parser\ParserInterface;
18
19
class ApiResourceMetadataParser implements ParserInterface
20
{
21
    /** @var ResourceMetadataFactory */
22
    private $metadataFactory;
23
24
    /** @var ResourceIndex */
25
    private $resourceIndex;
26
27
    public function __construct(ResourceIndex $resourceIndex, ResourceMetadataFactory $metadataFactory)
28
    {
29
        $this->metadataFactory = $metadataFactory;
30
        $this->resourceIndex = $resourceIndex;
31
    }
32
33
    /**
34
     * {@inheritdoc}
35
     */
36
    public function supports(array $item)
37
    {
38
        return $this->resourceIndex->has($item['class']);
39
    }
40
41
    /**
42
     * {@inheritdoc}
43
     */
44
    public function parse(array $item)
45
    {
46
        $class = $item['class'];
47
48
        return $this->doParse($class);
49
    }
50
51
    private function doParse($class)
52
    {
53
        $data = [];
54
55
        $resourceMetadata = $this->metadataFactory->getMetadataFor($class);
56
57
        foreach ($resourceMetadata->getAttributes() as $attributeMetadata) {
58
            list($actualType, $subType) = $this->resolveActualType($attributeMetadata);
59
60
            $attributeData = [
61
                'dataType' => $attributeMetadata->getType(),
62
                'actualType' => $actualType,
63
                'required' => $attributeMetadata->isRequired(),
64
                'description' => $attributeMetadata->getDescription() ?: '',
65
                'readonly' => null,
66
            ];
67
68
            if ($subType) {
69
                $attributeData['subType'] = $subType;
70
                $attributeData['dataType'] = null; // ApiDocExtractor will generate it
71
72
                if ($this->supports(['class' => $subType])) {
73
                    $attributeData['subType'] = $this->resourceIndex->getShortName($subType);
74
                    $attributeData['children'] = $this->doParse($subType);
75
                }
76
            }
77
78
            $data[$attributeMetadata->getName()] = $attributeData;
79
        }
80
81
        return $data;
82
    }
83
84
    private function resolveActualType(ResourceAttributeMetadata $attributeMetadata)
85
    {
86
        $originalTypeClass = ltrim($attributeMetadata->getOriginalType(), '\\');
87
88
        if (in_array($originalTypeClass, [\DateTime::class, \DateTimeImmutable::class, \DateTimeInterface::class], true)) {
89
            return [DataTypes::DATETIME, null];
90
        }
91
92
        $type = $attributeMetadata->getType();
93
94
        $actualType = null;
95
        $subType = null;
96
97
        // If it's a collection of models
98
        if (false !== strpos($type, '[]')) {
99
            $actualType = DataTypes::COLLECTION;
100
        } elseif (class_exists($type)) {
101
            $actualType = DataTypes::MODEL;
102
        }
103
104
        $type = str_replace('[]', '', $type, $count);
105
106
        switch ($type) {
107
            case 'bool':
108
            case 'boolean':
109
                $type = DataTypes::BOOLEAN;
110
                break;
111
            case 'int':
112
            case 'integer':
113
                $type = DataTypes::INTEGER;
114
                break;
115
            case 'double':
116
            case 'float':
117
                $type = DataTypes::FLOAT;
118
                break;
119
            case 'file':
120
                $type = DataTypes::FILE;
121
                break;
122
            case 'string':
123
                $type = DataTypes::STRING;
124
                break;
125
        }
126
127
        if (in_array($actualType, [DataTypes::COLLECTION, DataTypes::MODEL])) {
128
            $subType = $type;
129
        } else {
130
            $actualType = $type;
131
        }
132
133
        return [$actualType, $subType];
134
    }
135
}
136