Issues (49)

src/Data/ObjectGraphBuilder.php (2 issues)

1
<?php
2
3
namespace Vox\Data;
4
5
use Metadata\MetadataFactoryInterface;
6
use ReflectionClass;
7
use ReflectionParameter;
8
use Vox\Metadata\ClassMetadata;
9
use Vox\Metadata\PropertyMetadata;
10
11
/**
12
 * Use object's metadata to create the entire graph of empty objects in case there's no
13
 * instantiated objects on the properties marked as @var Type
14
 * 
15
 * @author Jhonatan Teixeira <[email protected]>
16
 */
17
class ObjectGraphBuilder implements ObjectGraphBuilderInterface
18
{
19
    private $storage = [];
20
    
21
    /**
22
     * @var MetadataFactoryInterface
23
     */
24
    private $metadataFactory;
25
    
26
    /**
27
     * @var PropertyAccessorInterface
28
     */
29
    private $propertyAccessor;
30
    
31
    private $visited = [];
32
33 3
    public function __construct(MetadataFactoryInterface $metadataFactory, PropertyAccessorInterface $propertyAccessor)
34
    {
35 3
        $this->metadataFactory  = $metadataFactory;
36 3
        $this->propertyAccessor = $propertyAccessor;
37 3
    }
38
    
39
    /**
40
     * @param object $object
41
     */
42 3
    public function buildObjectGraph($object)
43
    {
44 3
        if (is_string($object)) {
0 ignored issues
show
The condition is_string($object) is always false.
Loading history...
45 3
            $object = $this->createObject($object);
46
        }
47
        
48
        /* @var $metadata ClassMetadata */
49 3
        $metadata = $this->metadataFactory->getMetadataForClass(get_class($object));
50
        
51
        /* @var $propertyMetadata PropertyMetadata */
52 3
        foreach ($metadata->propertyMetadata as $propertyMetadata) {
53 3
            $type = $propertyMetadata->type;
54
            
55 3
            if (!class_exists($type)) {
56 2
                continue;
57
            }
58
            
59 3
            $dependency = $this->fetchObject($type) ?? $this->createObject($type);
60
            
61 3
            if (!in_array($type, $this->visited)) {
62 3
                $this->visited[] = $type;
63 3
                $this->buildObjectGraph($dependency);
64
            }
65
            
66 3
            $this->propertyAccessor->set($object, $propertyMetadata->name, $dependency);
67
        }
68
        
69 3
        return $object;
70
    }
71
    
72 3
    private function createObject($className)
73
    {
74 3
        $metadata = $this->metadataFactory->getMetadataForClass($className);
75
        
76
        /* @var $reflection ReflectionClass */
77 3
        $reflection = $metadata->reflection;
0 ignored issues
show
The property reflection does not seem to exist on Metadata\ClassHierarchyMetadata.
Loading history...
78
        
79 3
        $params = [];
80
        
81 3
        if ($constructor = $reflection->getConstructor()) {
82
            /* @var $injectable ReflectionParameter */
83 1
            foreach ($constructor->getParameters() as $injectable) {
84 1
                $typeReflection = $injectable->getClass();
85
86 1
                if (!$typeReflection) {
87
                    continue;
88
                }
89
90 1
                $object = $this->fetchObject($typeReflection->name) ?? $this->createObject($typeReflection->name);
91
92 1
                $this->storeObject($object);
93
94 1
                $params[] = $object;
95
            }
96
        }
97
        
98 3
        return $reflection->newInstanceArgs($params);
99
    }
100
    
101 1
    private function storeObject($object)
102
    {
103 1
        $this->storage[get_class($object)] = $object;
104 1
    }
105
    
106 3
    private function fetchObject(string $objectName)
107
    {
108 3
        return $this->storage[$objectName] ?? null;
109
    }
110
111 2
    public function clear()
112
    {
113 2
        $this->storage = $this->visited = [];
114
        
115 2
        return $this;
116
    }
117
}
118