LazyObjectsFactory::createProxyClass()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
c 0
b 0
f 0
rs 10
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
3
namespace Isolate\LazyObjects\Proxy\Adapter\OcramiusProxyManager\Factory;
4
5
use Isolate\LazyObjects\Exception\InvalidArgumentException;
6
use Isolate\LazyObjects\Proxy\Adapter\OcramiusProxyManager\ProxyGenerator\LazyObjectsProxyGenerator;
7
use Isolate\LazyObjects\Proxy\LazyProperty;
8
use Isolate\LazyObjects\Proxy\MethodReplacement;
9
use ProxyManager\Configuration;
10
use ProxyManager\Generator\ClassGenerator;
11
use ProxyManager\Version;
12
use ReflectionClass;
13
14
/**
15
 * Factory responsible of producing proxy lazy objects
16
 */
17
class LazyObjectsFactory
18
{
19
    const GENERATE_NEVER = 0;
20
    const GENERATE_WHEN_NOT_EXISTS = 1;
21
    const GENERATE_ALWAYS = 2;
22
    /**
23
     * @var \ProxyManager\Configuration
24
     */
25
    private $configuration;
26
27
    /**
28
     * Cached checked class names
29
     *
30
     * @var string[]
31
     */
32
    private $checkedClasses = array();
33
34
    /**
35
     * @var LazyObjectsProxyGenerator|null
36
     */
37
    private $generator;
38
39
    /**
40
     * @var int
41
     */
42
    private $generationStrategy;
43
44
    /**
45
     * @param \ProxyManager\Configuration $configuration
46
     * @param int $generationStrategy
47
     */
48
    public function __construct(Configuration $configuration = null, $generationStrategy = self::GENERATE_WHEN_NOT_EXISTS)
49
    {
50
        if ($generationStrategy !== self::GENERATE_NEVER && $generationStrategy !== self::GENERATE_WHEN_NOT_EXISTS
51
            && $generationStrategy !== self::GENERATE_ALWAYS) {
52
            throw new \InvalidArgumentException("Invalid generation strategy.");
53
        }
54
55
        $this->configuration = $configuration ?: new Configuration();
56
        $this->generator = new LazyObjectsProxyGenerator();
57
        $this->generationStrategy = $generationStrategy;
58
    }
59
60
    /**
61
     * @param $instance
62
     * @param array $lazyProperties
63
     * @param array $methodReplacements
64
     * @return \Isolate\LazyObjects\WrappedObject
65
     * @throws InvalidArgumentException
66
     */
67
    public function createProxy($instance, array $lazyProperties = array(), array $methodReplacements = [])
68
    {
69
        foreach ($lazyProperties as $lazyProperty) {
70
            if (!$lazyProperty instanceof LazyProperty) {
71
                throw new InvalidArgumentException("Lazy property needs to be an instance of Isolate\\LazyObjects\\Proxy\\LazyProperty");
72
            }
73
        }
74
75
        foreach ($methodReplacements as $methodReplacement) {
76
            if (!$methodReplacement instanceof MethodReplacement) {
77
                throw new InvalidArgumentException("Method replacement needs to be an instance of Isolate\\LazyObjects\\Proxy\\MethodReplacement");
78
            }
79
        }
80
81
        $proxyClassName = $this->generateProxy(get_class($instance));
82
83
        return new $proxyClassName($instance, $lazyProperties, $methodReplacements);
84
    }
85
86
    /**
87
     * Return proxy class name
88
     *
89
     * @param string $className
90
     * @return string
91
     */
92
    public function createProxyClass($className)
93
    {
94
        return $this->generateProxy($className);
95
    }
96
97
    /**
98
     * Generate a proxy from a class name
99
     * @param  string $className
100
     * @return string proxy class name
101
     */
102
    private function generateProxy($className)
103
    {
104
        if (isset($this->checkedClasses[$className])) {
105
            return $this->checkedClasses[$className];
106
        }
107
108
        $proxyParameters = array(
109
            'className'           => $className,
110
            'factory'             => get_class($this),
111
            'proxyManagerVersion' => Version::VERSION
112
        );
113
        $proxyClassName  = $this
114
            ->configuration
115
            ->getClassNameInflector()
116
            ->getProxyClassName($className, $proxyParameters);
117
118
        $this->generateProxyClass($proxyClassName, $className, $proxyParameters);
119
120
        $this
121
            ->configuration
122
            ->getSignatureChecker()
123
            ->checkSignature(new ReflectionClass($proxyClassName), $proxyParameters);
124
125
        return $this->checkedClasses[$className] = $proxyClassName;
126
    }
127
128
    /**
129
     * Generates the provided `$proxyClassName` from the given `$className` and `$proxyParameters`
130
     * @param string $proxyClassName
131
     * @param string $className
132
     * @param array  $proxyParameters
133
     *
134
     * @return void
135
     */
136
    private function generateProxyClass($proxyClassName, $className, array $proxyParameters)
137
    {
138
        if ($this->generationStrategy === self::GENERATE_NEVER) {
139
            return ;
140
        }
141
142
        if ($this->generationStrategy === self::GENERATE_WHEN_NOT_EXISTS && class_exists($proxyClassName)) {
143
            return ;
144
        }
145
146
        $className = $this->configuration->getClassNameInflector()->getUserClassName($className);
147
        $phpClass  = new ClassGenerator($proxyClassName);
148
149
        $this->generator->generate(new ReflectionClass($className), $phpClass);
150
151
        $phpClass = $this->configuration->getClassSignatureGenerator()->addSignature($phpClass, $proxyParameters);
152
153
        $this->configuration->getGeneratorStrategy()->generate($phpClass);
154
        $this->configuration->getProxyAutoloader()->__invoke($proxyClassName);
0 ignored issues
show
Bug introduced by
The method __invoke cannot be called on $this->configuration->getProxyAutoloader() (of type callable).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
155
    }
156
}
157
158