Failed Conditions
Push — master ( 6744b4...2b8acb )
by Marco
60:45 queued 60:36
created

lib/Doctrine/ORM/Cache/DefaultEntityHydrator.php (1 issue)

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
/*
4
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
5
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
6
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
7
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
8
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
9
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
10
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
11
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
12
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
13
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
14
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
15
 *
16
 * This software consists of voluntary contributions made by many individuals
17
 * and is licensed under the MIT license. For more information, see
18
 * <http://www.doctrine-project.org>.
19
 */
20
21
namespace Doctrine\ORM\Cache;
22
23
use Doctrine\Common\Util\ClassUtils;
24
25
use Doctrine\ORM\Query;
26
use Doctrine\ORM\Mapping\ClassMetadata;
27
use Doctrine\ORM\EntityManagerInterface;
28
use Doctrine\ORM\Utility\IdentifierFlattener;
29
30
/**
31
 * Default hydrator cache for entities
32
 *
33
 * @since   2.5
34
 * @author  Fabio B. Silva <[email protected]>
35
 */
36
class DefaultEntityHydrator implements EntityHydrator
37
{
38
    /**
39
     * @var \Doctrine\ORM\EntityManager
40
     */
41
    private $em;
42
43
    /**
44
     * @var \Doctrine\ORM\UnitOfWork
45
     */
46
    private $uow;
47
48
    /**
49
     * The IdentifierFlattener used for manipulating identifiers
50
     *
51
     * @var \Doctrine\ORM\Utility\IdentifierFlattener
52
     */
53
    private $identifierFlattener;
54
55
    /**
56
     * @var array
57
     */
58
    private static $hints = [Query::HINT_CACHE_ENABLED => true];
59
60
    /**
61
     * @param \Doctrine\ORM\EntityManagerInterface $em The entity manager.
62
     */
63 214
    public function __construct(EntityManagerInterface $em)
64
    {
65 214
        $this->em   = $em;
0 ignored issues
show
Documentation Bug introduced by
$em is of type object<Doctrine\ORM\EntityManagerInterface>, but the property $em was declared to be of type object<Doctrine\ORM\EntityManager>. Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a given class or a super-class is assigned to a property that is type hinted more strictly.

Either this assignment is in error or an instanceof check should be added for that assignment.

class Alien {}

class Dalek extends Alien {}

class Plot
{
    /** @var  Dalek */
    public $villain;
}

$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
    $plot->villain = $alien;
}
Loading history...
66 214
        $this->uow  = $em->getUnitOfWork();
67 214
        $this->identifierFlattener = new IdentifierFlattener($em->getUnitOfWork(), $em->getMetadataFactory());
68 214
    }
69
70
    /**
71
     * {@inheritdoc}
72
     */
73 116
    public function buildCacheEntry(ClassMetadata $metadata, EntityCacheKey $key, $entity)
74
    {
75 116
        $data = $this->uow->getOriginalEntityData($entity);
76 116
        $data = array_merge($data, $metadata->getIdentifierValues($entity)); // why update has no identifier values ?
77
78 116
        foreach ($metadata->associationMappings as $name => $assoc) {
79 70
            if ( ! isset($data[$name])) {
80 26
                continue;
81
            }
82
83 69
            if ( ! ($assoc['type'] & ClassMetadata::TO_ONE)) {
84 59
                unset($data[$name]);
85
86 59
                continue;
87
            }
88
89 68
            if ( ! isset($assoc['cache'])) {
90 5
                $targetClassMetadata = $this->em->getClassMetadata($assoc['targetEntity']);
91 5
                $owningAssociation   = ( ! $assoc['isOwningSide'])
92 1
                    ? $targetClassMetadata->associationMappings[$assoc['mappedBy']]
93 5
                    : $assoc;
94 5
                $associationIds      = $this->identifierFlattener->flattenIdentifier(
95 5
                    $targetClassMetadata,
96 5
                    $targetClassMetadata->getIdentifierValues($data[$name])
97
                );
98
99 5
                unset($data[$name]);
100
101 5
                foreach ($associationIds as $fieldName => $fieldValue) {
102 5
                    if (isset($targetClassMetadata->fieldMappings[$fieldName])) {
103 5
                        $fieldMapping = $targetClassMetadata->fieldMappings[$fieldName];
104
105 5
                        $data[$owningAssociation['targetToSourceKeyColumns'][$fieldMapping['columnName']]] = $fieldValue;
106
107 5
                        continue;
108
                    }
109
110 1
                    $targetAssoc = $targetClassMetadata->associationMappings[$fieldName];
111
112 1
                    foreach($assoc['targetToSourceKeyColumns'] as $referencedColumn => $localColumn) {
113 1
                        if (isset($targetAssoc['sourceToTargetKeyColumns'][$referencedColumn])) {
114 1
                            $data[$localColumn] = $fieldValue;
115
                        }
116
                    }
117
                }
118
119 5
                continue;
120
            }
121
122 64
            if ( ! isset($assoc['id'])) {
123 64
                $targetClass = ClassUtils::getClass($data[$name]);
124 64
                $targetId    = $this->uow->getEntityIdentifier($data[$name]);
125 64
                $data[$name] = new AssociationCacheEntry($targetClass, $targetId);
126
127 64
                continue;
128
            }
129
130
            // handle association identifier
131 4
            $targetId = is_object($data[$name]) && $this->uow->isInIdentityMap($data[$name])
132 4
                ? $this->uow->getEntityIdentifier($data[$name])
133 4
                : $data[$name];
134
135
            // @TODO - fix it !
136
            // handle UnitOfWork#createEntity hash generation
137 4
            if ( ! is_array($targetId)) {
138
                $data[reset($assoc['joinColumnFieldNames'])] = $targetId;
139
140
                $targetEntity = $this->em->getClassMetadata($assoc['targetEntity']);
141
                $targetId     = [$targetEntity->identifier[0] => $targetId];
142
            }
143
144 4
            $data[$name] = new AssociationCacheEntry($assoc['targetEntity'], $targetId);
145
        }
146
147 116
        return new EntityCacheEntry($metadata->name, $data);
148
    }
149
150
    /**
151
     * {@inheritdoc}
152
     */
153 41
    public function loadCacheEntry(ClassMetadata $metadata, EntityCacheKey $key, EntityCacheEntry $entry, $entity = null)
154
    {
155 41
        $data  = $entry->data;
156 41
        $hints = self::$hints;
157
158 41 View Code Duplication
        if ($entity !== null) {
159 6
            $hints[Query::HINT_REFRESH]         = true;
160 6
            $hints[Query::HINT_REFRESH_ENTITY]  = $entity;
161
        }
162
163 41
        foreach ($metadata->associationMappings as $name => $assoc) {
164 34
            if ( ! isset($assoc['cache']) ||  ! isset($data[$name])) {
165 27
                continue;
166
            }
167
168 28
            $assocClass     = $data[$name]->class;
169 28
            $assocId        = $data[$name]->identifier;
170 28
            $isEagerLoad    = ($assoc['fetch'] === ClassMetadata::FETCH_EAGER || ($assoc['type'] === ClassMetadata::ONE_TO_ONE && ! $assoc['isOwningSide']));
171
172 28
            if ( ! $isEagerLoad) {
173 26
                $data[$name] = $this->em->getReference($assocClass, $assocId);
174
175 26
                continue;
176
            }
177
178 3
            $assocMetadata  = $this->em->getClassMetadata($assoc['targetEntity']);
179 3
            $assocKey       = new EntityCacheKey($assocMetadata->rootEntityName, $assocId);
180 3
            $assocPersister = $this->uow->getEntityPersister($assoc['targetEntity']);
181 3
            $assocRegion    = $assocPersister->getCacheRegion();
182 3
            $assocEntry     = $assocRegion->get($assocKey);
183
184 3
            if ($assocEntry === null) {
185
                return null;
186
            }
187
188 3
            $data[$name] = $this->uow->createEntity($assocEntry->class, $assocEntry->resolveAssociationEntries($this->em), $hints);
189
        }
190
191 41
        if ($entity !== null) {
192 6
            $this->uow->registerManaged($entity, $key->identifier, $data);
193
        }
194
195 41
        $result = $this->uow->createEntity($entry->class, $data, $hints);
196
197 41
        $this->uow->hydrationComplete();
198
199 41
        return $result;
200
    }
201
}
202