Completed
Push — master ( 7b9f4b...1cd743 )
by Andreas
13s queued 10s
created

ODM/MongoDB/Proxy/Factory/StaticProxyFactory.php (4 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\Factory;
6
7
use Closure;
8
use Doctrine\Common\NotifyPropertyChanged;
9
use Doctrine\ODM\MongoDB\DocumentManager;
10
use Doctrine\ODM\MongoDB\DocumentNotFoundException;
11
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
12
use Doctrine\ODM\MongoDB\Persisters\DocumentPersister;
13
use Doctrine\ODM\MongoDB\UnitOfWork;
14
use Doctrine\ODM\MongoDB\Utility\LifecycleEventManager;
15
use ProxyManager\Factory\LazyLoadingGhostFactory;
16
use ProxyManager\Proxy\GhostObjectInterface;
17
use ReflectionProperty;
18
use function array_filter;
19
use function count;
20
21
/**
22
 * This factory is used to create proxy objects for documents at runtime.
23
 */
24
class StaticProxyFactory implements ProxyFactory
25
{
26
    /** @var UnitOfWork The UnitOfWork this factory is bound to. */
27
    private $uow;
28
29
    /** @var LifecycleEventManager */
30
    private $lifecycleEventManager;
31
32
    /** @var LazyLoadingGhostFactory */
33
    private $proxyFactory;
34
35 1651
    public function __construct(DocumentManager $documentManager)
36
    {
37 1651
        $this->uow                   = $documentManager->getUnitOfWork();
38 1651
        $this->lifecycleEventManager = new LifecycleEventManager($documentManager, $this->uow, $documentManager->getEventManager());
39 1651
        $this->proxyFactory          = $documentManager->getConfiguration()->buildGhostObjectFactory();
40 1651
    }
41
42 98
    public function getProxy(ClassMetadata $metadata, $identifier) : GhostObjectInterface
43
    {
44 98
        $documentPersister = $this->uow->getDocumentPersister($metadata->getName());
0 ignored issues
show
Consider using $metadata->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
45
46
        $ghostObject = $this
47 98
            ->proxyFactory
48 98
            ->createProxy(
49 98
                $metadata->getName(),
0 ignored issues
show
Consider using $metadata->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
50 98
                $this->createInitializer($metadata, $documentPersister),
51
                [
52 98
                    'skippedProperties' => $this->skippedFieldsFqns($metadata),
53
                ]
54
            );
55
56 98
        $metadata->setIdentifierValue($ghostObject, $identifier);
57
58 98
        return $ghostObject;
59
    }
60
61
    /**
62
     * {@inheritdoc}
63
     *
64
     * @param ClassMetadata[] $classes
65
     */
66
    public function generateProxyClasses(array $classes) : int
67
    {
68
        $concreteClasses = array_filter($classes, static function (ClassMetadata $metadata) : bool {
69
            return ! ($metadata->isMappedSuperclass || $metadata->isQueryResultDocument || $metadata->getReflectionClass()->isAbstract());
70
        });
71
72
        foreach ($concreteClasses as $metadata) {
73
            $this
74
                ->proxyFactory
75
                ->createProxy(
76
                    $metadata->getName(),
77
                    static function () {
78
                        // empty closure, serves its purpose, for now
79
                    },
80
                    $this->skippedFieldsFqns($metadata)
81
                );
82
        }
83
84
        return count($concreteClasses);
85
    }
86
87 98
    private function createInitializer(
88
        ClassMetadata $metadata,
89
        DocumentPersister $documentPersister
90
    ) : Closure {
91
        return function (
92
            GhostObjectInterface $ghostObject,
93
            string $method,
94
            // we don't care
95
            array $parameters,
96
            // we don't care
97
            & $initializer,
98
            array $properties // we currently do not use this
99
        ) use (
100 33
            $metadata,
101 33
            $documentPersister
102
        ) : bool {
103 33
            $originalInitializer = $initializer;
104 33
            $initializer         = null;
105 33
            $identifier          = $metadata->getIdentifierValue($ghostObject);
106
107 33
            if (! $documentPersister->load(['_id' => $identifier], $ghostObject)) {
108 9
                $initializer = $originalInitializer;
109
110 9
                if (! $this->lifecycleEventManager->documentNotFound($ghostObject, $identifier)) {
111 8
                    throw DocumentNotFoundException::documentNotFound($metadata->getName(), $identifier);
0 ignored issues
show
Consider using $metadata->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
112
                }
113
            }
114
115 27
            if ($ghostObject instanceof NotifyPropertyChanged) {
0 ignored issues
show
The class Doctrine\Common\NotifyPropertyChanged does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
116 1
                $ghostObject->addPropertyChangedListener($this->uow);
117
            }
118
119 27
            return true;
120 98
        };
121
    }
122
123
    /**
124
     * @return string[]
125
     */
126 98
    private function skippedFieldsFqns(ClassMetadata $metadata) : array
127
    {
128 98
        $idFieldFqcns = [];
129
130 98
        foreach ($metadata->getIdentifierFieldNames() as $idField) {
131 98
            $idFieldFqcns[] = $this->propertyFqcn($metadata->getReflectionProperty($idField));
132
        }
133
134 98
        return $idFieldFqcns;
135
    }
136
137 98
    private function propertyFqcn(ReflectionProperty $property) : string
138
    {
139 98
        if ($property->isPrivate()) {
140 50
            return "\0" . $property->getDeclaringClass()->getName() . "\0" . $property->getName();
141
        }
142
143 54
        if ($property->isProtected()) {
144 22
            return "\0*\0" . $property->getName();
145
        }
146
147 32
        return $property->getName();
148
    }
149
}
150