Completed
Push — master ( a8fe50...bce26f )
by Maciej
13s
created

lib/Doctrine/ODM/MongoDB/Proxy/ProxyFactory.php (8 issues)

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
declare(strict_types=1);
4
5
namespace Doctrine\ODM\MongoDB\Proxy;
6
7
use Doctrine\Common\EventManager;
8
use Doctrine\Common\NotifyPropertyChanged;
9
use Doctrine\Common\Persistence\Mapping\ClassMetadata as BaseClassMetadata;
10
use Doctrine\Common\Proxy\AbstractProxyFactory;
11
use Doctrine\Common\Proxy\Proxy as BaseProxy;
12
use Doctrine\Common\Proxy\ProxyDefinition;
13
use Doctrine\Common\Proxy\ProxyGenerator;
14
use Doctrine\Common\Util\ClassUtils;
15
use Doctrine\ODM\MongoDB\DocumentManager;
16
use Doctrine\ODM\MongoDB\DocumentNotFoundException;
17
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
18
use Doctrine\ODM\MongoDB\Mapping\ClassMetadataFactory;
19
use Doctrine\ODM\MongoDB\Persisters\DocumentPersister;
20
use Doctrine\ODM\MongoDB\UnitOfWork;
21
use Doctrine\ODM\MongoDB\Utility\LifecycleEventManager;
22
use ReflectionProperty;
23
use function get_class;
24
25
/**
26
 * This factory is used to create proxy objects for documents at runtime.
27
 *
28
 */
29
class ProxyFactory extends AbstractProxyFactory
0 ignored issues
show
Deprecated Code introduced by
The class Doctrine\Common\Proxy\AbstractProxyFactory has been deprecated with message: The Doctrine\Common\Proxy component is deprecated, please use ocramius/proxy-manager instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
30
{
31
    /** @var ClassMetadataFactory */
32
    private $metadataFactory;
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
33
34
    /** @var UnitOfWork The UnitOfWork this factory is bound to. */
35
    private $uow;
36
37
    /** @var string The namespace that contains all proxy classes. */
38
    private $proxyNamespace;
39
40
    /** @var EventManager */
41
    private $lifecycleEventManager;
42
43
    /**
44
     * Initializes a new instance of the <tt>ProxyFactory</tt> class that is
45
     * connected to the given <tt>DocumentManager</tt>.
46
     *
47
     * @param DocumentManager $documentManager The DocumentManager the new factory works for.
48
     * @param string          $proxyDir        The directory to use for the proxy classes. It
49
     *                                         must exist.
50
     * @param string          $proxyNamespace  The namespace to use for the proxy classes.
51
     * @param int             $autoGenerate    Whether to automatically generate proxy classes.
52
     */
53 1605
    public function __construct(DocumentManager $documentManager, $proxyDir, $proxyNamespace, $autoGenerate = AbstractProxyFactory::AUTOGENERATE_NEVER)
54
    {
55 1605
        $this->metadataFactory = $documentManager->getMetadataFactory();
56 1605
        $this->uow = $documentManager->getUnitOfWork();
57 1605
        $this->proxyNamespace = $proxyNamespace;
58 1605
        $this->lifecycleEventManager = new LifecycleEventManager($documentManager, $this->uow, $documentManager->getEventManager());
59 1605
        $proxyGenerator = new ProxyGenerator($proxyDir, $proxyNamespace);
0 ignored issues
show
Deprecated Code introduced by
The class Doctrine\Common\Proxy\ProxyGenerator has been deprecated with message: The Doctrine\Common\Proxy component is deprecated, please use ocramius/proxy-manager instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
60
61 1605
        $proxyGenerator->setPlaceholder('baseProxyInterface', Proxy::class);
62
63 1605
        parent::__construct($proxyGenerator, $this->metadataFactory, $autoGenerate);
64 1605
    }
65
66
    /**
67
     * {@inheritDoc}
68
     */
69
    public function skipClass(BaseClassMetadata $class)
70
    {
71
        /** @var ClassMetadata $class */
72
        return $class->isMappedSuperclass || $class->isQueryResultDocument || $class->getReflectionClass()->isAbstract();
73
    }
74
75
    /**
76
     * {@inheritDoc}
77
     */
78 104
    public function createProxyDefinition($className)
79
    {
80
        /** @var ClassMetadata $classMetadata */
81 104
        $classMetadata     = $this->metadataFactory->getMetadataFor($className);
82 104
        $documentPersister = $this->uow->getDocumentPersister($className);
83 104
        $reflectionId      = $classMetadata->reflFields[$classMetadata->identifier];
84
85 104
        return new ProxyDefinition(
0 ignored issues
show
Deprecated Code introduced by
The class Doctrine\Common\Proxy\ProxyDefinition has been deprecated with message: The Doctrine\Common\Proxy component is deprecated, please use ocramius/proxy-manager instead.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
86 104
            ClassUtils::generateProxyClassName($className, $this->proxyNamespace),
87 104
            $classMetadata->getIdentifierFieldNames(),
88 104
            $classMetadata->getReflectionProperties(),
89 104
            $this->createInitializer($classMetadata, $documentPersister, $reflectionId),
90 104
            $this->createCloner($classMetadata, $documentPersister, $reflectionId)
91
        );
92
    }
93
94
    /**
95
     * Generates a closure capable of initializing a proxy
96
     *
97
     *
98
     * @return \Closure
99
     *
100
     * @throws DocumentNotFoundException
101
     */
102 104
    private function createInitializer(
103
        BaseClassMetadata $classMetadata,
104
        DocumentPersister $documentPersister,
105
        ReflectionProperty $reflectionId
106
    ) {
107 104
        if ($classMetadata->getReflectionClass()->hasMethod('__wakeup')) {
108 View Code Duplication
            return function (BaseProxy $proxy) use ($documentPersister, $reflectionId) {
109
                $proxy->__setInitializer(null);
110
                $proxy->__setCloner(null);
111
112
                if ($proxy->__isInitialized()) {
113
                    return;
114
                }
115
116
                $properties = $proxy->__getLazyProperties();
117
118
                foreach ($properties as $propertyName => $property) {
119
                    if (isset($proxy->$propertyName)) {
120
                        continue;
121
                    }
122
123
                    $proxy->$propertyName = $properties[$propertyName];
124
                }
125
126
                $proxy->__setInitialized(true);
127
                $proxy->__wakeup();
0 ignored issues
show
The method __wakeup() does not seem to exist on object<Doctrine\Common\Proxy\Proxy>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
128
129
                $id = $reflectionId->getValue($proxy);
130
131
                if ($documentPersister->load(['_id' => $id], $proxy) === null) {
132
                    if (! $this->lifecycleEventManager->documentNotFound($proxy, $id)) {
0 ignored issues
show
The method documentNotFound() does not seem to exist on object<Doctrine\Common\EventManager>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
133
                        throw DocumentNotFoundException::documentNotFound(get_class($proxy), $id);
134
                    }
135
                }
136
137
                if (! ($proxy instanceof NotifyPropertyChanged)) {
138
                    return;
139
                }
140
141
                $proxy->addPropertyChangedListener($this->uow);
142
            };
143
        }
144
145 View Code Duplication
        return function (BaseProxy $proxy) use ($documentPersister, $reflectionId) {
146 35
            $proxy->__setInitializer(null);
147 35
            $proxy->__setCloner(null);
148
149 35
            if ($proxy->__isInitialized()) {
150
                return;
151
            }
152
153 35
            $properties = $proxy->__getLazyProperties();
154
155 35
            foreach ($properties as $propertyName => $property) {
156 12
                if (isset($proxy->$propertyName)) {
157
                    continue;
158
                }
159
160 12
                $proxy->$propertyName = $properties[$propertyName];
161
            }
162
163 35
            $proxy->__setInitialized(true);
164
165 35
            $id = $reflectionId->getValue($proxy);
166
167 35
            if ($documentPersister->load(['_id' => $id], $proxy) === null) {
168 9
                if (! $this->lifecycleEventManager->documentNotFound($proxy, $id)) {
0 ignored issues
show
The method documentNotFound() does not seem to exist on object<Doctrine\Common\EventManager>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
169 8
                    throw DocumentNotFoundException::documentNotFound(get_class($proxy), $id);
170
                }
171
            }
172
173 29
            if (! ($proxy instanceof NotifyPropertyChanged)) {
174 28
                return;
175
            }
176
177 1
            $proxy->addPropertyChangedListener($this->uow);
178 104
        };
179
    }
180
181
    /**
182
     * Generates a closure capable of finalizing a cloned proxy
183
     *
184
     *
185
     * @return \Closure
186
     *
187
     * @throws DocumentNotFoundException
188
     */
189 104
    private function createCloner(
190
        BaseClassMetadata $classMetadata,
191
        DocumentPersister $documentPersister,
192
        ReflectionProperty $reflectionId
193
    ) {
194
        return function (BaseProxy $proxy) use ($documentPersister, $classMetadata, $reflectionId) {
195
            if ($proxy->__isInitialized()) {
196
                return;
197
            }
198
199
            $proxy->__setInitialized(true);
200
            $proxy->__setInitializer(null);
201
202
            $id       = $reflectionId->getValue($proxy);
203
            $original = $documentPersister->load(['_id' => $id]);
204
205
            if ($original === null) {
206
                if (! $this->lifecycleEventManager->documentNotFound($proxy, $id)) {
0 ignored issues
show
The method documentNotFound() does not seem to exist on object<Doctrine\Common\EventManager>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
207
                    throw DocumentNotFoundException::documentNotFound(get_class($proxy), $id);
208
                }
209
            }
210
211
            foreach ($classMetadata->getReflectionClass()->getProperties() as $reflectionProperty) {
212
                $propertyName = $reflectionProperty->getName();
213
214
                if (! $classMetadata->hasField($propertyName) && ! $classMetadata->hasAssociation($propertyName)) {
215
                    continue;
216
                }
217
218
                $reflectionProperty->setAccessible(true);
219
                $reflectionProperty->setValue($proxy, $reflectionProperty->getValue($original));
220
            }
221 104
        };
222
    }
223
}
224