Failed Conditions
Pull Request — 2.6 (#7882)
by
unknown
06:45
created

ProxyFactory   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 167
Duplicated Lines 0 %

Test Coverage

Coverage 95.24%

Importance

Changes 0
Metric Value
wmc 17
eloc 63
dl 0
loc 167
ccs 60
cts 63
cp 0.9524
rs 10
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A skipClass() 0 6 3
A __construct() 0 11 1
A createCloner() 0 28 6
A createProxyDefinition() 0 11 1
B createInitializer() 0 39 6
1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\ORM\Proxy;
21
22
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
23
use Doctrine\Common\Proxy\AbstractProxyFactory;
24
use Doctrine\Common\Proxy\Proxy as BaseProxy;
25
use Doctrine\Common\Proxy\ProxyDefinition;
26
use Doctrine\Common\Proxy\ProxyGenerator;
27
use Doctrine\Common\Util\ClassUtils;
28
use Doctrine\ORM\EntityManagerInterface;
29
use Doctrine\ORM\Persisters\Entity\EntityPersister;
30
use Doctrine\ORM\EntityNotFoundException;
31
use Doctrine\ORM\Utility\IdentifierFlattener;
32
33
/**
34
 * This factory is used to create proxy objects for entities at runtime.
35
 *
36
 * @author Roman Borschel <[email protected]>
37
 * @author Giorgio Sironi <[email protected]>
38
 * @author Marco Pivetta  <[email protected]>
39
 * @since 2.0
40
 */
41
class ProxyFactory extends AbstractProxyFactory
0 ignored issues
show
Deprecated Code introduced by
The class Doctrine\Common\Proxy\AbstractProxyFactory has been deprecated: The Doctrine\Common\Proxy component is deprecated, please use ocramius/proxy-manager instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

41
class ProxyFactory extends /** @scrutinizer ignore-deprecated */ AbstractProxyFactory
Loading history...
42
{
43
    /**
44
     * @var EntityManagerInterface The EntityManager this factory is bound to.
45
     */
46
    private $em;
47
48
    /**
49
     * @var \Doctrine\ORM\UnitOfWork The UnitOfWork this factory uses to retrieve persisters
50
     */
51
    private $uow;
52
53
    /**
54
     * @var string
55
     */
56
    private $proxyNs;
57
58
    /**
59
     * The IdentifierFlattener used for manipulating identifiers
60
     *
61
     * @var \Doctrine\ORM\Utility\IdentifierFlattener
62
     */
63
    private $identifierFlattener;
64
65
    /**
66
     * Initializes a new instance of the <tt>ProxyFactory</tt> class that is
67
     * connected to the given <tt>EntityManager</tt>.
68
     *
69
     * @param EntityManagerInterface $em           The EntityManager the new factory works for.
70
     * @param string                 $proxyDir     The directory to use for the proxy classes. It must exist.
71
     * @param string                 $proxyNs      The namespace to use for the proxy classes.
72
     * @param boolean|int            $autoGenerate The strategy for automatically generating proxy classes. Possible
73
     *                                             values are constants of Doctrine\Common\Proxy\AbstractProxyFactory.
74
     */
75 1626
    public function __construct(EntityManagerInterface $em, $proxyDir, $proxyNs, $autoGenerate = AbstractProxyFactory::AUTOGENERATE_NEVER)
76
    {
77 1626
        $proxyGenerator = new ProxyGenerator($proxyDir, $proxyNs);
0 ignored issues
show
Deprecated Code introduced by
The class Doctrine\Common\Proxy\ProxyGenerator has been deprecated: The Doctrine\Common\Proxy component is deprecated, please use ocramius/proxy-manager instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

77
        $proxyGenerator = /** @scrutinizer ignore-deprecated */ new ProxyGenerator($proxyDir, $proxyNs);
Loading history...
78
79 1626
        $proxyGenerator->setPlaceholder('baseProxyInterface', Proxy::class);
80 1626
        parent::__construct($proxyGenerator, $em->getMetadataFactory(), $autoGenerate);
81
82 1626
        $this->em                  = $em;
83 1626
        $this->uow                 = $em->getUnitOfWork();
84 1626
        $this->proxyNs             = $proxyNs;
85 1626
        $this->identifierFlattener = new IdentifierFlattener($this->uow, $em->getMetadataFactory());
86 1626
    }
87
88
    /**
89
     * {@inheritDoc}
90
     */
91 3
    protected function skipClass(ClassMetadata $metadata)
92
    {
93
        /* @var $metadata \Doctrine\ORM\Mapping\ClassMetadataInfo */
94 3
        return $metadata->isMappedSuperclass
0 ignored issues
show
Bug introduced by
Accessing isMappedSuperclass on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
95 2
            || $metadata->isEmbeddedClass
0 ignored issues
show
Bug introduced by
Accessing isEmbeddedClass on the interface Doctrine\Common\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
96 3
            || $metadata->getReflectionClass()->isAbstract();
97
    }
98
99
    /**
100
     * {@inheritDoc}
101
     */
102 23
    protected function createProxyDefinition($className)
103
    {
104 23
        $classMetadata   = $this->em->getClassMetadata($className);
105 23
        $entityPersister = $this->uow->getEntityPersister($className);
106
107 23
        return new ProxyDefinition(
0 ignored issues
show
Deprecated Code introduced by
The class Doctrine\Common\Proxy\ProxyDefinition has been deprecated: The Doctrine\Common\Proxy component is deprecated, please use ocramius/proxy-manager instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

107
        return /** @scrutinizer ignore-deprecated */ new ProxyDefinition(
Loading history...
108 23
            ClassUtils::generateProxyClassName($className, $this->proxyNs),
109 23
            $classMetadata->getIdentifierFieldNames(),
110 23
            $classMetadata->getReflectionProperties(),
0 ignored issues
show
Bug introduced by
The method getReflectionProperties() does not exist on Doctrine\Common\Persistence\Mapping\ClassMetadata. Did you maybe mean getReflectionClass()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

110
            $classMetadata->/** @scrutinizer ignore-call */ 
111
                            getReflectionProperties(),

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...
111 23
            $this->createInitializer($classMetadata, $entityPersister),
112 23
            $this->createCloner($classMetadata, $entityPersister)
113
        );
114
    }
115
116
    /**
117
     * Creates a closure capable of initializing a proxy
118
     *
119
     * @param \Doctrine\Common\Persistence\Mapping\ClassMetadata $classMetadata
120
     * @param \Doctrine\ORM\Persisters\Entity\EntityPersister    $entityPersister
121
     *
122
     * @return \Closure
123
     *
124
     * @throws \Doctrine\ORM\EntityNotFoundException
125
     */
126 23
    private function createInitializer(ClassMetadata $classMetadata, EntityPersister $entityPersister)
127
    {
128 23
        $wakeupProxy = $classMetadata->getReflectionClass()->hasMethod('__wakeup');
129
130
        return function (BaseProxy $proxy) use ($entityPersister, $classMetadata, $wakeupProxy) {
131 11
            $initializer = $proxy->__getInitializer();
132 11
            $cloner      = $proxy->__getCloner();
133
134 11
            $proxy->__setInitializer(null);
135 11
            $proxy->__setCloner(null);
136
137 11
            if ($proxy->__isInitialized()) {
138 1
                return;
139
            }
140
141 10
            $properties = $proxy->__getLazyProperties();
142
143 10
            foreach ($properties as $propertyName => $property) {
144 4
                if ( ! isset($proxy->$propertyName)) {
145 4
                    $proxy->$propertyName = $properties[$propertyName];
146
                }
147
            }
148
149 10
            $proxy->__setInitialized(true);
150
151 10
            if ($wakeupProxy) {
152
                $proxy->__wakeup();
0 ignored issues
show
Bug introduced by
The method __wakeup() does not exist on Doctrine\Common\Proxy\Proxy. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

152
                $proxy->/** @scrutinizer ignore-call */ 
153
                        __wakeup();

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...
153
            }
154
155 10
            $identifier = $classMetadata->getIdentifierValues($proxy);
156
157 10
            if (null === $entityPersister->loadById($identifier, $proxy)) {
158 1
                $proxy->__setInitializer($initializer);
159 1
                $proxy->__setCloner($cloner);
160 1
                $proxy->__setInitialized(false);
161
162 1
                throw EntityNotFoundException::fromClassNameAndIdentifier(
163 1
                    $classMetadata->getName(),
164 1
                    $this->identifierFlattener->flattenIdentifier($classMetadata, $identifier)
165
                );
166
            }
167 23
        };
168
    }
169
170
    /**
171
     * Creates a closure capable of finalizing state a cloned proxy
172
     *
173
     * @param \Doctrine\Common\Persistence\Mapping\ClassMetadata $classMetadata
174
     * @param \Doctrine\ORM\Persisters\Entity\EntityPersister    $entityPersister
175
     *
176
     * @return \Closure
177
     *
178
     * @throws \Doctrine\ORM\EntityNotFoundException
179
     */
180 23
    private function createCloner(ClassMetadata $classMetadata, EntityPersister $entityPersister)
181
    {
182
        return function (BaseProxy $proxy) use ($entityPersister, $classMetadata) {
183 2
            if ($proxy->__isInitialized()) {
184
                return;
185
            }
186
187 2
            $proxy->__setInitialized(true);
188 2
            $proxy->__setInitializer(null);
189
190 2
            $class      = $entityPersister->getClassMetadata();
191 2
            $identifier = $classMetadata->getIdentifierValues($proxy);
192 2
            $original   = $entityPersister->loadById($identifier);
193
194 2
            if (null === $original) {
195 1
                throw EntityNotFoundException::fromClassNameAndIdentifier(
196 1
                    $classMetadata->getName(),
197 1
                    $this->identifierFlattener->flattenIdentifier($classMetadata, $identifier)
198
                );
199
            }
200
201 1
            foreach ($class->getReflectionProperties() as $property) {
202 1
                if ( ! $class->hasField($property->name) && ! $class->hasAssociation($property->name)) {
203
                    continue;
204
                }
205
206 1
                $property->setAccessible(true);
207 1
                $property->setValue($proxy, $property->getValue($original));
208
            }
209 23
        };
210
    }
211
}
212