Passed
Branch relations (30b30c)
by JHONATAN
04:09
created

YmlDriver   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 121
Duplicated Lines 0 %

Test Coverage

Coverage 95.38%

Importance

Changes 0
Metric Value
wmc 15
dl 0
loc 121
ccs 62
cts 65
cp 0.9538
rs 10
c 0
b 0
f 0

3 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 1
B loadYml() 0 25 3
D loadMetadataForClass() 0 73 11
1
<?php
2
3
namespace Vox\Metadata\Driver;
4
5
use Metadata\Driver\DriverInterface;
6
use Metadata\MethodMetadata;
7
use ProxyManager\Proxy\AccessInterceptorValueHolderInterface;
8
use ReflectionClass;
9
use ReflectionProperty;
10
use RuntimeException;
11
use Symfony\Component\Yaml\Parser;
12
use Vox\Data\Mapping\Bindings;
13
use Vox\Data\Mapping\Exclude;
14
use Vox\Metadata\ClassMetadata;
15
use Vox\Metadata\PropertyMetadata;
16
use Vox\Webservice\Mapping\BelongsTo;
17
use Vox\Webservice\Mapping\HasMany;
18
use Vox\Webservice\Mapping\HasOne;
19
use Vox\Webservice\Mapping\Id;
20
use Vox\Webservice\Mapping\Resource;
21
22
/**
23
 * Yml driver to create a class metadata information
24
 * 
25
 * @author Jhonatan Teixeira <[email protected]>
26
 */
27
class YmlDriver implements DriverInterface
28
{
29
    private $ymlParser;
30
    
31
    private $path;
32
    
33
    private $classMetadataClassName;
34
    
35
    private $propertyMetadataClassName;
36
    
37 3
    public function __construct(
38
        string $path,
39
        string $classMetadataClassName = ClassMetadata::class,
40
        string $propertyMetadataClassName = PropertyMetadata::class
41
    ) {
42 3
        $this->ymlParser                 = new Parser();
43 3
        $this->path                      = realpath($path);
44 3
        $this->classMetadataClassName    = $classMetadataClassName;
45 3
        $this->propertyMetadataClassName = $propertyMetadataClassName;
46 3
    }
47
    
48 3
    public function loadMetadataForClass(ReflectionClass $class): ClassMetadata
49
    {
50 3
        if ($class->implementsInterface(AccessInterceptorValueHolderInterface::class)) {
51
            $class = $class->getParentClass();
52
        }
53
        
54 3
        $yml = $this->loadYml($class);
55
        
56
        /* @var $classMetadata ClassMetadata */
57 3
        $classMetadata = (new ReflectionClass($this->classMetadataClassName))->newInstance($class->name);
58
        
59 3
        if (isset($yml['resource'])) {
60 2
            $resource         = new Resource();
61 2
            $resource->client = $yml['resource']['client'] ?? null;
62 2
            $resource->route  = $yml['resource']['route'] ?? null;
63 2
            $classMetadata->setAnnotations([Resource::class => $resource]);
64
        }
65
        
66 3
        foreach ($class->getMethods() as $method) {
67 3
            $classMetadata->addMethodMetadata(new MethodMetadata($class->name, $method->name));
68
        }
69
        
70
        /* @var $reflectionProperty ReflectionProperty */
71 3
        foreach ($class->getProperties() as $reflectionProperty) {
72 3
            $annotations = [];
73 3
            $annotations[Bindings::class] = $bindings = new Bindings();
74 3
            $name                         = $reflectionProperty->name;
75
76 3
            if ($name == $yml['id'] ?? null) {
77 3
                $annotations[Id::class] = new Id();
78
            }
79
            
80 3
            if (isset($yml['parameters'][$reflectionProperty->name])) {
81 3
                $config           = $yml['parameters'][$name];
82 3
                $bindings->source = $config['bindings']['source'] ?? null;
83 3
                $bindings->target = $config['bindings']['target'] ?? null;
84
85 3
                if (isset($config['belongsTo'])) {
86 2
                    $belongsTo = new BelongsTo();
87 2
                    $belongsTo->foreignField = $config['belongsTo']['foreignField'];
88 2
                    $annotations[BelongsTo::class] = $belongsTo;
89
                }
90
                
91 3
                if (isset($config['hasOne'])) {
92 1
                    $hasOne = new HasOne();
93 1
                    $hasOne->foreignField = $config['hasOne']['foreignField'];
94 1
                    $annotations[HasOne::class] = $hasOne;
95
                }
96
                
97 3
                if (isset($config['hasMany'])) {
98 1
                    $hasMany = new HasMany();
99 1
                    $hasMany->foreignField = $config['hasMany']['foreignField'];
100 1
                    $annotations[HasMany::class] = $hasMany;
101
                }
102
                
103 3
                if (isset($config['exclude'])) {
104 1
                    $exclude = new Exclude();
105 1
                    $exclude->input  = $config['exlude']['input'] ?? true;
106 1
                    $exclude->output = $config['exlude']['output'] ?? true;
107 1
                    $annotations[Exclude::class] = $exclude;
108
                }
109
            }
110
            
111
            /* @var $propertyMetadata PropertyMetadata */
112 3
            $propertyMetadata = (new ReflectionClass($this->propertyMetadataClassName))
113 3
                ->newInstance($class->name, $reflectionProperty->name);
114
            
115 3
            $propertyMetadata->setAnnotations($annotations);
116
            
117 3
            $classMetadata->addPropertyMetadata($propertyMetadata);
118
        }
119
        
120 3
        return $classMetadata;
121
    }
122
    
123 3
    private function loadYml(ReflectionClass $class)
124
    {
125 3
        $className = $class->getName();
126
        
127 3
        $path = sprintf(
128 3
            '%s/%s.yml', 
129 3
            preg_replace('/\/$/', '', $this->path), 
130 3
            str_replace('\\', DIRECTORY_SEPARATOR, $className)
131
        );
132
        
133 3
        if (is_file($path)) {
134
            return $this->ymlParser->parse(file_get_contents($path));
135
        }
136
        
137 3
        $path = sprintf(
138 3
            '%s/%s.yml', 
139 3
            preg_replace('/\/$/', '', $this->path), 
140 3
            str_replace('\\', '.', $className)
141
        );
142
        
143 3
        if (is_file($path)) {
144 3
            return $this->ymlParser->parse(file_get_contents($path));
145
        }
146
        
147
        throw new RuntimeException("metadata file not found for class $className");
148
    }
149
}
150