PropertyInfoLoader::__construct()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 2
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\Resource\Loader;
12
13
use Elao\ApiResourcesMetadata\Attribute\ResourceAttributeMetadata;
14
use Elao\ApiResourcesMetadata\Resource\ResourceMetadata;
15
use phpDocumentor\Reflection\DocBlockFactory;
16
use phpDocumentor\Reflection\DocBlockFactoryInterface;
17
use phpDocumentor\Reflection\Types\ContextFactory;
18
use Symfony\Component\PropertyInfo\PropertyInfoExtractor;
19
use Symfony\Component\PropertyInfo\Type;
20
21
class PropertyInfoLoader implements LoaderInterface
22
{
23
    /** @var PropertyInfoExtractor */
24
    private $extractor;
25
26
    /** @var DocBlockFactoryInterface */
27
    private $docBlockFactory;
28
29
    /** @var ContextFactory */
30
    private $contextFactory;
31
32
    public function __construct(PropertyInfoExtractor $extractor, DocBlockFactoryInterface $docBlockFactory = null)
33
    {
34
        $this->extractor = $extractor;
35
        $this->docBlockFactory = $docBlockFactory ?: DocBlockFactory::createInstance();
36
        $this->contextFactory = new ContextFactory();
37
    }
38
39
    public function loadResourceMetadata(ResourceMetadata $resourceMetadata): bool
40
    {
41
        $class = $resourceMetadata->getClass();
42
43
        if (!class_exists($class)) {
44
            return false;
45
        }
46
47
        $resourceMetadata->getDescription() ?: $resourceMetadata->setDescription($this->getClassDocBlock($class));
48
49
        foreach ((array) $this->extractor->getProperties($class) as $name) {
50
            $attributeMetadata = $resourceMetadata->getAttribute($name) ?? new ResourceAttributeMetadata($name);
51
52
            if (!empty($description = $this->extractor->getLongDescription($class, $name))) {
53
                $attributeMetadata->getDescription() ?: $attributeMetadata->setDescription($description);
54
            }
55
56
            /** @var Type[] $types */
57
            $types = $this->extractor->getTypes($class, $name);
58
59
            if (isset($types[0])) {
60
                $type = $types[0];
61
                $attributeMetadata->setRequired(!$type->isNullable());
62
63
                $phpType = $types[0]->getBuiltinType();
64
                if ($type->isCollection()) {
65
                    $collectionValueType = $type->getCollectionValueType();
66
67
                    if ($collectionValueType) {
68
                        if (Type::BUILTIN_TYPE_OBJECT === $collectionValueType->getBuiltinType()) {
69
                            $phpType = $collectionValueType->getClassName();
70
                        } else {
71
                            $phpType = $collectionValueType->getBuiltinType();
72
                        }
73
74
                        $phpType .= '[]';
75
                    }
76
                }
77
78
                if (Type::BUILTIN_TYPE_OBJECT === $type->getBuiltinType()) {
79
                    $phpType = $type->getClassName();
80
                }
81
82
                $attributeMetadata->getOriginalType() ?: $attributeMetadata->setOriginalType($phpType);
83
                $attributeMetadata->getType() ?: $attributeMetadata->setType($phpType);
84
            }
85
86
            if ($description = $this->extractor->getShortDescription($class, $name)) {
87
                $attributeMetadata->setDescription($description);
88
            }
89
90
            $resourceMetadata->addAttribute($attributeMetadata);
91
        }
92
93
        return true;
94
    }
95
96
    /**
97
     * @param string $class
98
     *
99
     * @return string
100
     */
101
    private function getClassDocBlock(string $class)
102
    {
103
        $reflectionProperty = new \ReflectionClass($class);
104
105
        try {
106
            return (string) $this->docBlockFactory->create(
107
                $reflectionProperty,
108
                $this->contextFactory->createFromReflector($reflectionProperty)
109
            )->getSummary();
110
        } catch (\InvalidArgumentException $e) {
111
            return '';
112
        }
113
    }
114
}
115