Completed
Pull Request — master (#1419)
by Robert
11:09 queued 01:09
created

ProxyFactory::createInitializer()   C

Complexity

Conditions 14
Paths 2

Size

Total Lines 70
Code Lines 38

Duplication

Lines 61
Ratio 87.14 %

Code Coverage

Tests 18
CRAP Score 14.0285

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 61
loc 70
ccs 18
cts 19
cp 0.9474
rs 5.6188
cc 14
eloc 38
nc 2
nop 3
crap 14.0285

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\ODM\MongoDB\Proxy;
21
22
use Doctrine\Common\NotifyPropertyChanged;
23
use Doctrine\Common\Proxy\AbstractProxyFactory;
24
use Doctrine\Common\Proxy\ProxyDefinition;
25
use Doctrine\ODM\MongoDB\DocumentManager;
26
use Doctrine\ODM\MongoDB\DocumentNotFoundException;
27
use Doctrine\Common\Proxy\ProxyGenerator;
28
use Doctrine\Common\Util\ClassUtils;
29
use Doctrine\Common\Proxy\Proxy as BaseProxy;
30
use Doctrine\Common\Persistence\Mapping\ClassMetadata as BaseClassMetadata;
31
use Doctrine\ODM\MongoDB\Persisters\DocumentPersister;
32
use Doctrine\ODM\MongoDB\Utility\LifecycleEventManager;
33
use ReflectionProperty;
34
35
/**
36
 * This factory is used to create proxy objects for documents at runtime.
37
 *
38
 * @since       1.0
39
 */
40
class ProxyFactory extends AbstractProxyFactory
41
{
42
    /**
43
     * @var \Doctrine\ODM\MongoDB\Mapping\ClassMetadataFactory
44
     */
45
    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...
46
47
    /**
48
     * @var \Doctrine\ODM\MongoDB\UnitOfWork The UnitOfWork this factory is bound to.
49
     */
50
    private $uow;
51
52
    /**
53
     * @var string The namespace that contains all proxy classes.
54
     */
55
    private $proxyNamespace;
56
57
    /**
58
     * @var \Doctrine\Common\EventManager
59
     */
60
    private $lifecycleEventManager;
61
62
    /**
63
     * Initializes a new instance of the <tt>ProxyFactory</tt> class that is
64
     * connected to the given <tt>DocumentManager</tt>.
65
     *
66
     * @param \Doctrine\ODM\MongoDB\DocumentManager $documentManager The DocumentManager the new factory works for.
67
     * @param string                                $proxyDir        The directory to use for the proxy classes. It
68
     *                                                               must exist.
69
     * @param string                                $proxyNamespace  The namespace to use for the proxy classes.
70
     * @param integer                               $autoGenerate    Whether to automatically generate proxy classes.
71
     */
72 1038
    public function __construct(DocumentManager $documentManager, $proxyDir, $proxyNamespace, $autoGenerate = AbstractProxyFactory::AUTOGENERATE_NEVER)
73
    {
74 1038
        $this->metadataFactory = $documentManager->getMetadataFactory();
75 1038
        $this->uow = $documentManager->getUnitOfWork();
76 1038
        $this->proxyNamespace = $proxyNamespace;
77 1038
        $this->lifecycleEventManager = new LifecycleEventManager($documentManager, $this->uow, $documentManager->getEventManager());
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Doctrine\ODM\MongoD...ger->getEventManager()) of type object<Doctrine\ODM\Mong...\LifecycleEventManager> is incompatible with the declared type object<Doctrine\Common\EventManager> of property $lifecycleEventManager.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
78 1038
        $proxyGenerator = new ProxyGenerator($proxyDir, $proxyNamespace);
79
80 1038
        $proxyGenerator->setPlaceholder('baseProxyInterface', Proxy::class);
81
82 1038
        parent::__construct($proxyGenerator, $this->metadataFactory, $autoGenerate);
83 1038
    }
84
85
    /**
86
     * {@inheritDoc}
87
     */
88
    public function skipClass(BaseClassMetadata $class)
89
    {
90
        /* @var $class \Doctrine\ODM\Mongodb\Mapping\ClassMetadataInfo */
91
        return $class->isMappedSuperclass || $class->getReflectionClass()->isAbstract();
92
    }
93
94
    /**
95
     * {@inheritDoc}
96
     */
97 93
    public function createProxyDefinition($className)
98
    {
99
        /* @var $classMetadata \Doctrine\ODM\MongoDB\Mapping\ClassMetadataInfo */
100 93
        $classMetadata     = $this->metadataFactory->getMetadataFor($className);
101 93
        $documentPersister = $this->uow->getDocumentPersister($className);
102 93
        $reflectionId      = $classMetadata->reflFields[$classMetadata->identifier];
103
104 93
        return new ProxyDefinition(
105 93
            ClassUtils::generateProxyClassName($className, $this->proxyNamespace),
106 93
            $classMetadata->getIdentifierFieldNames(),
107 93
            $classMetadata->getReflectionProperties(),
108 93
            $this->createInitializer($classMetadata, $documentPersister, $reflectionId),
109 93
            $this->createCloner($classMetadata, $documentPersister, $reflectionId)
110
        );
111
    }
112
113
    /**
114
     * Generates a closure capable of initializing a proxy
115
     *
116
     * @param \Doctrine\Common\Persistence\Mapping\ClassMetadata $classMetadata
117
     * @param \Doctrine\ODM\MongoDB\Persisters\DocumentPersister $documentPersister
118
     * @param \ReflectionProperty                                $reflectionId
119
     *
120
     * @return \Closure
121
     *
122
     * @throws \Doctrine\ODM\MongoDB\DocumentNotFoundException
123
     */
124 93
    private function createInitializer(
125
        BaseClassMetadata $classMetadata,
126
        DocumentPersister $documentPersister,
127
        ReflectionProperty $reflectionId
128
    ) {
129 93
        if ($classMetadata->getReflectionClass()->hasMethod('__wakeup')) {
130 View Code Duplication
            return function (BaseProxy $proxy) use ($documentPersister, $reflectionId) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
131
                $proxy->__setInitializer(null);
132
                $proxy->__setCloner(null);
133
134
                if ($proxy->__isInitialized()) {
135
                    return;
136
                }
137
138
                $properties = $proxy->__getLazyProperties();
139
140
                foreach ($properties as $propertyName => $property) {
141
                    if ( ! isset($proxy->$propertyName)) {
142
                        $proxy->$propertyName = $properties[$propertyName];
143
                    }
144
                }
145
146
                $proxy->__setInitialized(true);
147
                $proxy->__wakeup();
0 ignored issues
show
Bug introduced by
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...
148
149
                $id = $reflectionId->getValue($proxy);
150
151
                if (null === $documentPersister->load(array('_id' => $id), $proxy)) {
152
                    if ( ! $this->lifecycleEventManager->documentNotFound($proxy, $id)) {
0 ignored issues
show
Bug introduced by
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...
153
                        throw DocumentNotFoundException::documentNotFound(get_class($proxy), $id);
154
                    }
155
                }
156
157
                if ($proxy instanceof NotifyPropertyChanged) {
158
                    $proxy->addPropertyChangedListener($this->uow);
159
                }
160
            };
161
        }
162
163 View Code Duplication
        return function (BaseProxy $proxy) use ($documentPersister, $reflectionId) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
164 42
            $proxy->__setInitializer(null);
165 42
            $proxy->__setCloner(null);
166
167 42
            if ($proxy->__isInitialized()) {
168 3
                return;
169
            }
170
171 42
            $properties = $proxy->__getLazyProperties();
172
173 42
            foreach ($properties as $propertyName => $property) {
174 22
                if ( ! isset($proxy->$propertyName)) {
175 22
                    $proxy->$propertyName = $properties[$propertyName];
176
                }
177
            }
178
179 42
            $proxy->__setInitialized(true);
180
181 42
            $id = $reflectionId->getValue($proxy);
182
183 42
            if (null === $documentPersister->load(array('_id' => $id), $proxy)) {
184 9
                if ( ! $this->lifecycleEventManager->documentNotFound($proxy, $id)) {
0 ignored issues
show
Bug introduced by
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...
185 8
                    throw DocumentNotFoundException::documentNotFound(get_class($proxy), $id);
186
                }
187
            }
188
189 38
            if ($proxy instanceof NotifyPropertyChanged) {
190 1
                $proxy->addPropertyChangedListener($this->uow);
191
            }
192 93
        };
193
    }
194
195
    /**
196
     * Generates a closure capable of finalizing a cloned proxy
197
     *
198
     * @param \Doctrine\Common\Persistence\Mapping\ClassMetadata $classMetadata
199
     * @param \Doctrine\ODM\MongoDB\Persisters\DocumentPersister $documentPersister
200
     * @param \ReflectionProperty                                $reflectionId
201
     *
202
     * @return \Closure
203
     *
204
     * @throws \Doctrine\ODM\MongoDB\DocumentNotFoundException
205
     */
206
    private function createCloner(
207
        BaseClassMetadata $classMetadata,
208
        DocumentPersister $documentPersister,
209
        ReflectionProperty $reflectionId
210
    ) {
211 93
        return function (BaseProxy $proxy) use ($documentPersister, $classMetadata, $reflectionId) {
212
            if ($proxy->__isInitialized()) {
213
                return;
214
            }
215
216
            $proxy->__setInitialized(true);
217
            $proxy->__setInitializer(null);
218
219
            $id       = $reflectionId->getValue($proxy);
220
            $original = $documentPersister->load(array('_id' => $id));
221
222
            if (null === $original) {
223
                if ( ! $this->lifecycleEventManager->documentNotFound($proxy, $id)) {
0 ignored issues
show
Bug introduced by
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...
224
                    throw DocumentNotFoundException::documentNotFound(get_class($proxy), $id);
225
                }
226
            }
227
228
            foreach ($classMetadata->getReflectionClass()->getProperties() as $reflectionProperty) {
229
                $propertyName = $reflectionProperty->getName();
230
231
                if ($classMetadata->hasField($propertyName) || $classMetadata->hasAssociation($propertyName)) {
232
                    $reflectionProperty->setAccessible(true);
233
                    $reflectionProperty->setValue($proxy, $reflectionProperty->getValue($original));
234
                }
235
            }
236 93
        };
237
    }
238
}
239