Completed
Push — master ( f04f52...152406 )
by Anton
03:17
created

src/ProxyFactory.php (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Spiral Framework.
4
 *
5
 * @license MIT
6
 * @author  Valentin V (Vvval)
7
 */
8
declare(strict_types=1);
9
10
namespace Cycle\ORM\Promise;
11
12
use Cycle\ORM\ORMInterface;
13
use Cycle\ORM\Promise\Declaration\Declarations;
14
use Cycle\ORM\Promise\Declaration\Extractor;
15
use Cycle\ORM\Promise\Exception\ProxyFactoryException;
16
use Cycle\ORM\Promise\Materizalizer\EvalMaterializer;
17
use Cycle\ORM\PromiseFactoryInterface;
18
use Cycle\ORM\Schema;
0 ignored issues
show
This use statement conflicts with another class in this namespace, Cycle\ORM\Promise\Schema.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
19
use Doctrine\Instantiator\Instantiator;
20
use Spiral\Core\Container\SingletonInterface;
21
22
final class ProxyFactory implements PromiseFactoryInterface, SingletonInterface
23
{
24
    /** @var Printer */
25
    private $printer;
26
27
    /** @var MaterializerInterface */
28
    private $materializer;
29
30
    /** @var Names */
31
    private $names;
32
33
    /** @var Instantiator */
34
    private $instantiator;
35
36
    /** @var Extractor */
37
    private $extractor;
38
39
    /** @var array */
40
    private $resolved = [];
41
42
    /**
43
     * @param Printer|null               $printer
44
     * @param MaterializerInterface|null $materializer
45
     * @param Names|null                 $names
46
     * @param Instantiator|null          $instantiator
47
     * @param Extractor|null             $extractor
48
     */
49
    public function __construct(
50
        Printer $printer = null,
51
        MaterializerInterface $materializer = null,
52
        Names $names = null,
53
        Instantiator $instantiator = null,
54
        Extractor $extractor = null
55
    ) {
56
        $this->printer = $printer ?? new Printer();
57
        $this->materializer = $materializer ?? new EvalMaterializer();
58
        $this->names = $names ?? new Names();
59
        $this->instantiator = $instantiator ?? new Instantiator();
60
        $this->extractor = $extractor ?? new Extractor();
61
    }
62
63
    /**
64
     * @param ORMInterface $orm
65
     * @param string       $role
66
     * @param array        $scope
67
     * @return PromiseInterface
68
     *
69
     * @throws ProxyFactoryException
70
     * @throws \Doctrine\Instantiator\Exception\ExceptionInterface
71
     */
72
    public function promise(ORMInterface $orm, string $role, array $scope): PromiseInterface
73
    {
74
        $class = $orm->getSchema()->define($role, Schema::ENTITY);
75
        if (empty($class)) {
76
            return new PromiseOne($orm, $role, $scope);
77
        }
78
79
        try {
80
            $reflection = new \ReflectionClass($class);
81
        } catch (\ReflectionException $e) {
82
            throw ProxyFactoryException::wrap($e);
83
        }
84
85
        if (isset($this->resolved[$role])) {
86
            return $this->instantiate($reflection, $this->resolved[$role], $orm, $role, $scope);
87
        }
88
89
        $parent = Declarations::createParentFromReflection($reflection);
90
        $class = Declarations::createClassFromName($this->names->make($reflection), $parent);
91
92
        if (!class_exists($class->getFullName())) {
93
            $this->materializer->materialize(
94
                $this->printer->make($reflection, $class, $parent),
95
                $class->getShortName(),
96
                $reflection
97
            );
98
        }
99
100
        $this->resolved[$role] = $class->getFullName();
101
102
        return $this->instantiate($reflection, $this->resolved[$role], $orm, $role, $scope);
103
    }
104
105
    /**
106
     * @param \ReflectionClass $reflection
107
     * @param string           $className
108
     * @param ORMInterface     $orm
109
     * @param string           $role
110
     * @param array            $scope
111
     * @return PromiseInterface
112
     *
113
     * @throws \Doctrine\Instantiator\Exception\ExceptionInterface
114
     */
115
    private function instantiate(
116
        \ReflectionClass $reflection,
117
        string $className,
118
        ORMInterface $orm,
119
        string $role,
120
        array $scope
121
    ): PromiseInterface {
122
        $structure = $this->extractor->extract($reflection);
123
124
        /** @var PromiseInterface $instance */
125
        $instance = $this->instantiator->instantiate($className);
126
        $instance->{$this->printer->initMethodName($structure)}($orm, $role, $scope);
127
128
        return $instance;
129
    }
130
}