Test Failed
Pull Request — develop (#6719)
by Marco
63:23
created

StaticProxyFactory::transientFieldsFqns()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 19
Code Lines 11

Duplication

Lines 19
Ratio 100 %

Importance

Changes 0
Metric Value
dl 19
loc 19
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 11
nc 3
nop 1
1
<?php
2
3
4
declare(strict_types=1);
5
6
namespace Doctrine\ORM\Proxy\Factory;
7
8
use Doctrine\ORM\Configuration\ProxyConfiguration;
9
use Doctrine\ORM\EntityManagerInterface;
10
use Doctrine\ORM\EntityNotFoundException;
11
use Doctrine\ORM\Mapping\ClassMetadata;
12
use Doctrine\ORM\Mapping\TransientMetadata;
13
use Doctrine\ORM\Proxy\Proxy;
14
use ProxyManager\Configuration;
15
use ProxyManager\Factory\LazyLoadingGhostFactory;
16
use ProxyManager\Proxy\GhostObjectInterface;
17
18
/**
19
 * Static factory for proxy objects.
20
 *
21
 * @package Doctrine\ORM\Proxy\Factory
22
 * @since 3.0
23
 *
24
 * @author Benjamin Eberlei <[email protected]>
25
 * @author Guilherme Blanco <[email protected]>
26
 */
27
class StaticProxyFactory implements ProxyFactory
28
{
29
    /**
30
     * @var EntityManagerInterface
31
     */
32
    protected $entityManager;
33
34
    /**
35
     * @var ProxyGenerator
36
     */
37
    protected $generator;
38
39
    /**
40
     * @var ProxyDefinitionFactory
41
     */
42
    protected $definitionFactory;
43
44
    /**
45
     * @var array<string, ProxyDefinition>
46
     */
47
    private $definitions = [];
48
49
    /**
50
     * ProxyFactory constructor.
51
     *
52
     * @param ProxyConfiguration $configuration
53
     */
54
    public function __construct(EntityManagerInterface $entityManager, ProxyConfiguration $configuration)
55
    {
56
        $resolver          = $configuration->getResolver();
57
        //$autoGenerate      = $configuration->getAutoGenerate();
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
58
        $generator         = new ProxyGenerator();
59
        $generatorStrategy = new Strategy\ConditionalFileWriterProxyGeneratorStrategy($generator);
60
        $definitionFactory = new ProxyDefinitionFactory($entityManager, $resolver, $generatorStrategy);
61
62
        $generator->setPlaceholder('baseProxyInterface', GhostObjectInterface::class);
63
64
        $this->entityManager     = $entityManager;
65
        $this->definitionFactory = $definitionFactory;
66
    }
67
68
    /**
69
     * {@inheritdoc}
70
     */
71
    public function generateProxyClasses(array $classMetadataList) : int
72
    {
73
        $generated = 0;
74
75
        foreach ($classMetadataList as $classMetadata) {
76
            if ($classMetadata->isMappedSuperclass || $classMetadata->getReflectionClass()->isAbstract()) {
77
                continue;
78
            }
79
80
            $this->definitionFactory->build($classMetadata);
81
82
            $generated++;
83
        }
84
85
        return $generated;
86
    }
87
88
    /**
89
     * {@inheritdoc}
90
     * @throws \Doctrine\ORM\EntityNotFoundException
91
     */
92
    public function getProxy(string $className, array $identifier) : GhostObjectInterface
93
    {
94
        $metadata = $this->entityManager->getClassMetadata($className);
95
96
        $proxyInstance = (new LazyLoadingGhostFactory(new Configuration()))
97
            ->createProxy(
98
                $metadata->getClassName(),
0 ignored issues
show
Bug introduced by
The method getClassName() does not seem to exist on object<Doctrine\Common\P...\Mapping\ClassMetadata>.

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...
99
                function (
100
                    GhostObjectInterface $ghostObject,
101
                    string $method, // we don't care
102
                    array $parameters, // we don't care
103
                    & $initializer,
104
                    array $properties
0 ignored issues
show
Unused Code introduced by
The parameter $properties is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
105
                ) use ($metadata) : bool {
106
                    $originalInitializer = $initializer;
107
                    $initializer = null;
108
109
                    $persister = $this->entityManager->getUnitOfWork()->getEntityPersister($metadata->getClassName());
0 ignored issues
show
Bug introduced by
The method getClassName() does not seem to exist on object<Doctrine\Common\P...\Mapping\ClassMetadata>.

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...
110
111
                    $identifier = $persister->getIdentifier($ghostObject);
112
113
                    // @TODO how do we use `$properties` in the persister? That would be a massive optimisation
114
                    if (! $persister->loadById($identifier, $ghostObject)) {
115
                        $initializer = $originalInitializer;
116
117
                        throw EntityNotFoundException::fromClassNameAndIdentifier(
118
                            $metadata->getClassName(),
0 ignored issues
show
Bug introduced by
The method getClassName() does not seem to exist on object<Doctrine\Common\P...\Mapping\ClassMetadata>.

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...
119
                            $identifier
120
                        );
121
                    }
122
123
                    return true;
124
                },
125
                [
126
                    // @TODO this should be a constant reference, not a magic constant
127
                    'skippedProperties' => \array_merge(
128
                        $this->identifierFieldFqns($metadata),
0 ignored issues
show
Documentation introduced by
$metadata is of type object<Doctrine\Common\P...\Mapping\ClassMetadata>, but the function expects a object<Doctrine\ORM\Mapping\ClassMetadata>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
129
                        $this->transientFieldsFqns($metadata)
0 ignored issues
show
Documentation introduced by
$metadata is of type object<Doctrine\Common\P...\Mapping\ClassMetadata>, but the function expects a object<Doctrine\ORM\Mapping\ClassMetadata>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
130
                    ),
131
                ]
132
            );
133
134
        $this->transientFieldsFqns($metadata);
0 ignored issues
show
Documentation introduced by
$metadata is of type object<Doctrine\Common\P...\Mapping\ClassMetadata>, but the function expects a object<Doctrine\ORM\Mapping\ClassMetadata>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
135
        $proxyDefinition = $this->getOrCreateProxyDefinition($className);
136
        $proxyPersister  = $proxyDefinition->entityPersister;
137
138
        $proxyPersister->setIdentifier($proxyInstance, $identifier);
139
140
        return $proxyInstance;
141
    }
142
143 View Code Duplication
    private function transientFieldsFqns(ClassMetadata $metadata) : array
144
    {
145
        $transientFieldsFqns = [];
146
147
        foreach ($metadata->getDeclaredPropertiesIterator() as $name => $property) {
148
            if (! $property instanceof TransientMetadata) {
149
                continue;
150
            }
151
152
            $transientFieldsFqns[] = $this->propertyFqcn(
153
                $property
154
                    ->getDeclaringClass()
155
                    ->getReflectionClass()
156
                    ->getProperty($name) // @TODO possible NPR. This should never be null, why is it allowed to be?
157
            );
158
        }
159
160
        return $transientFieldsFqns;
161
    }
162
163 View Code Duplication
    private function identifierFieldFqns(ClassMetadata $metadata) : array
164
    {
165
        $idFieldFqcns = [];
166
167
        foreach ($metadata->getIdentifierFieldNames() as $idField) {
168
            $property = $metadata->getProperty($idField);
169
170
            $idFieldFqcns[] = $this->propertyFqcn(
171
                $property
172
                    ->getDeclaringClass()
173
                    ->getReflectionClass()
174
                    ->getProperty($idField) // @TODO possible NPR. This should never be null, why is it allowed to be?
175
            );
176
        }
177
178
        return $idFieldFqcns;
179
    }
180
181
    private function propertyFqcn(\ReflectionProperty $property) : string
182
    {
183
        if ($property->isPrivate()) {
184
            return "\0" . $property->getDeclaringClass()->getName() . "\0" . $property->getName();
0 ignored issues
show
introduced by
Consider using $property->class. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
185
        }
186
187
        if ($property->isProtected()) {
188
            return "\0*\0" . $property->getName();
189
        }
190
191
        return $property->getName();
192
    }
193
194
    /**
195
     * @param ProxyDefinition $definition
196
     *
197
     * @return Proxy
198
     */
199
    protected function createProxyInstance(ProxyDefinition $definition) : Proxy
200
    {
201
        /** @var Proxy $classMetadata */
202
        $proxyClassName = $definition->proxyClassName;
203
204
        return new $proxyClassName($definition);
205
    }
206
207
    /**
208
     * Create a proxy definition for the given class name.
209
     *
210
     * @param string $className
211
     *
212
     * @return ProxyDefinition
213
     */
214
    private function getOrCreateProxyDefinition(string $className) : ProxyDefinition
215
    {
216
        if (! isset($this->definitions[$className])) {
217
            $classMetadata = $this->entityManager->getClassMetadata($className);
218
219
            $this->definitions[$className] = $this->definitionFactory->build($classMetadata);
0 ignored issues
show
Documentation introduced by
$classMetadata is of type object<Doctrine\Common\P...\Mapping\ClassMetadata>, but the function expects a object<Doctrine\ORM\Mapping\ClassMetadata>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
220
        }
221
222
        return $this->definitions[$className];
223
    }
224
}
225