ProxyFactory   A
last analyzed

Complexity

Total Complexity 8

Size/Duplication

Total Lines 115
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 12

Importance

Changes 0
Metric Value
wmc 8
lcom 1
cbo 12
dl 0
loc 115
rs 10
c 0
b 0
f 0

3 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 13 1
A promise() 0 32 5
A instantiate() 0 18 2
1
<?php
2
3
/**
4
 * Spiral Framework. Cycle ProxyFactory
5
 *
6
 * @license MIT
7
 * @author  Valentin V (Vvval)
8
 */
9
10
declare(strict_types=1);
11
12
namespace Cycle\ORM\Promise;
13
14
use Cycle\ORM\ORMInterface;
15
use Cycle\ORM\Promise\Declaration\Declarations;
16
use Cycle\ORM\Promise\Declaration\Extractor;
17
use Cycle\ORM\Promise\Exception\ProxyFactoryException;
18
use Cycle\ORM\Promise\Materizalizer\EvalMaterializer;
19
use Cycle\ORM\PromiseFactoryInterface;
20
use Cycle\ORM\Schema;
21
use Doctrine\Instantiator\Exception\ExceptionInterface;
22
use Doctrine\Instantiator\Instantiator;
23
use Doctrine\Instantiator\InstantiatorInterface;
24
use ReflectionClass;
25
use ReflectionException;
26
use Spiral\Core\Container\SingletonInterface;
27
28
final class ProxyFactory implements PromiseFactoryInterface, SingletonInterface
29
{
30
    /** @var Extractor */
31
    private $extractor;
32
33
    /** @var Printer */
34
    private $printer;
35
36
    /** @var MaterializerInterface */
37
    private $materializer;
38
39
    /** @var Names */
40
    private $names;
41
42
    /** @var InstantiatorInterface */
43
    private $instantiator;
44
45
    /** @var array */
46
    private $resolved = [];
47
48
    /** @var array */
49
    private $instantiateMethods = [];
50
51
    /**
52
     * @param Extractor                  $extractor
53
     * @param Printer                    $printer
54
     * @param InstantiatorInterface|null $instantiator
55
     * @param MaterializerInterface|null $materializer
56
     * @param Names|null                 $names
57
     */
58
    public function __construct(
59
        Extractor $extractor,
60
        Printer $printer,
61
        ?InstantiatorInterface $instantiator = null,
62
        ?MaterializerInterface $materializer = null,
63
        ?Names $names = null
64
    ) {
65
        $this->extractor = $extractor;
66
        $this->printer = $printer;
67
        $this->instantiator = $instantiator ?? new Instantiator();
68
        $this->materializer = $materializer ?? new EvalMaterializer();
69
        $this->names = $names ?? new Names();
70
    }
71
72
    /**
73
     * @param ORMInterface $orm
74
     * @param string       $role
75
     * @param array        $scope
76
     * @return PromiseInterface
77
     * @throws ProxyFactoryException
78
     * @throws ExceptionInterface
79
     * @throws ReflectionException
80
     */
81
    public function promise(ORMInterface $orm, string $role, array $scope): PromiseInterface
82
    {
83
        $class = $orm->getSchema()->define($role, Schema::ENTITY);
84
        if (empty($class)) {
85
            return new PromiseOne($orm, $role, $scope);
86
        }
87
88
        try {
89
            $reflection = new ReflectionClass($class);
90
        } catch (ReflectionException $e) {
91
            throw ProxyFactoryException::wrap($e);
92
        }
93
94
        if (isset($this->resolved[$role])) {
95
            return $this->instantiate($reflection, $this->resolved[$role], $orm, $role, $scope);
96
        }
97
98
        $parent = Declarations::createParentFromReflection($reflection);
99
        $class = Declarations::createClassFromName($this->names->make($reflection), $parent);
100
101
        if (!class_exists($class->getFullName())) {
102
            $this->materializer->materialize(
103
                $this->printer->make($reflection, $class, $parent),
104
                $class->getShortName(),
105
                $reflection
106
            );
107
        }
108
109
        $this->resolved[$role] = $class->getFullName();
110
111
        return $this->instantiate($reflection, $this->resolved[$role], $orm, $role, $scope);
112
    }
113
114
    /**
115
     * @param ReflectionClass $reflection
116
     * @param string          $className
117
     * @param ORMInterface    $orm
118
     * @param string          $role
119
     * @param array           $scope
120
     * @return PromiseInterface
121
     * @throws ExceptionInterface
122
     * @throws ReflectionException
123
     */
124
    private function instantiate(
125
        ReflectionClass $reflection,
126
        string $className,
127
        ORMInterface $orm,
128
        string $role,
129
        array $scope
130
    ): PromiseInterface {
131
        if (!isset($this->instantiateMethods[$role])) {
132
            $structure = $this->extractor->extract($reflection);
133
            $this->instantiateMethods[$role] = $this->printer->initMethodName($structure);
134
        }
135
136
        /** @var PromiseInterface $instance */
137
        $instance = $this->instantiator->instantiate($className);
138
        $instance->{$this->instantiateMethods[$role]}($orm, $role, $scope);
139
140
        return $instance;
141
    }
142
}
143