Issues (258)

Doctrine/EventListener.php (8 issues)

1
<?php
2
/**
3
 * Copyright (C) 2018 Gerrit Addiks.
4
 * This package (including this file) was released under the terms of the GPL-3.0.
5
 * You should have received a copy of the GNU General Public License along with this program.
6
 * If not, see <http://www.gnu.org/licenses/> or send me a mail so i can send you a copy.
7
 * @license GPL-3.0
8
 * @author Gerrit Addiks <[email protected]>
9
 */
10
11
namespace Addiks\RDMBundle\Doctrine;
12
13
use Addiks\RDMBundle\Hydration\EntityHydratorInterface;
14
use Addiks\RDMBundle\Mapping\Drivers\MappingDriverInterface;
15
use Addiks\RDMBundle\Mapping\EntityMappingInterface;
16
use Addiks\RDMBundle\DataLoader\DataLoaderInterface;
17
use Doctrine\ORM\Event\LifecycleEventArgs;
18
use Doctrine\ORM\Mapping\ClassMetadata;
19
use Doctrine\ORM\Tools\SchemaTool;
20
use Doctrine\ORM\Tools\Event\GenerateSchemaTableEventArgs;
21
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
22
use Doctrine\ORM\EntityManagerInterface;
23
use Doctrine\ORM\UnitOfWork;
24
use Doctrine\DBAL\Schema\Table;
25
use Doctrine\ORM\Event\PostFlushEventArgs;
26
use Doctrine\ORM\Proxy\Proxy;
27
use Doctrine\DBAL\Schema\Column;
28
use PDOException;
29
use Doctrine\DBAL\Exception\ConnectionException;
30
31
/**
32
 * Hooks into the event's of doctrine2-ORM and forwards the entities to other objects.
33
 */
34
final class EventListener
35
{
36
37
    /**
38
     * @var EntityHydratorInterface
39
     */
40
    private $entityHydrator;
41
42
    /**
43
     * @var MappingDriverInterface
44
     */
45
    private $mappingDriver;
46
47
    /**
48
     * @var DataLoaderInterface
49
     */
50
    private $dbalDataLoader;
51
52
    /**
53
     * @var array<class-string, bool>
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<class-string, bool> at position 2 could not be parsed: Unknown type name 'class-string' at position 2 in array<class-string, bool>.
Loading history...
54
     */
55 10
    private $hasRdmMappingForClass = array();
56
57
    public function __construct(
58
        EntityHydratorInterface $entityHydrator,
59
        MappingDriverInterface $mappingDriver,
60 10
        DataLoaderInterface $dbalDataLoader
61 10
    ) {
62 10
        $this->entityHydrator = $entityHydrator;
63
        $this->mappingDriver = $mappingDriver;
64
        $this->dbalDataLoader = $dbalDataLoader;
65 3
    }
66
67
    public function postLoad(LifecycleEventArgs $arguments): void
68 3
    {
69
        /** @var object $entity */
70
        $entity = $arguments->getEntity();
0 ignored issues
show
Deprecated Code introduced by
The function Doctrine\ORM\Event\LifecycleEventArgs::getEntity() has been deprecated: 2.13. Use {@see getObject} instead. ( Ignorable by Annotation )

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

70
        $entity = /** @scrutinizer ignore-deprecated */ $arguments->getEntity();

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
71 3
72
        /** @var EntityManagerInterface $entityManager */
73 3
        $entityManager = $arguments->getEntityManager();
0 ignored issues
show
Deprecated Code introduced by
The function Doctrine\ORM\Event\Lifec...rgs::getEntityManager() has been deprecated: 2.13. Use {@see getObjectManager} instead. ( Ignorable by Annotation )

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

73
        $entityManager = /** @scrutinizer ignore-deprecated */ $arguments->getEntityManager();

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
74
75
        $this->entityHydrator->hydrateEntity($entity, $entityManager);
76 3
    }
77
78
    public function prePersist(LifecycleEventArgs $arguments): void
79 3
    {
80
        /** @var object $entity */
81
        $entity = $arguments->getEntity();
0 ignored issues
show
Deprecated Code introduced by
The function Doctrine\ORM\Event\LifecycleEventArgs::getEntity() has been deprecated: 2.13. Use {@see getObject} instead. ( Ignorable by Annotation )

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

81
        $entity = /** @scrutinizer ignore-deprecated */ $arguments->getEntity();

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
82 3
83
        /** @var EntityManagerInterface $entityManager */
84 3
        $entityManager = $arguments->getEntityManager();
0 ignored issues
show
Deprecated Code introduced by
The function Doctrine\ORM\Event\Lifec...rgs::getEntityManager() has been deprecated: 2.13. Use {@see getObjectManager} instead. ( Ignorable by Annotation )

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

84
        $entityManager = /** @scrutinizer ignore-deprecated */ $arguments->getEntityManager();

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
85 3
86
        if (!($entity instanceof Proxy)) {
87
            $this->entityHydrator->assertHydrationOnEntity($entity, $entityManager);
88
        }
89 5
    }
90
91
    public function postFlush(PostFlushEventArgs $arguments): void
92 5
    {
93
        /** @var EntityManagerInterface $entityManager */
94
        $entityManager = $arguments->getEntityManager();
0 ignored issues
show
Deprecated Code introduced by
The function Doctrine\ORM\Event\PostF...rgs::getEntityManager() has been deprecated: 2.13. Use {@see getObjectManager} instead. ( Ignorable by Annotation )

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

94
        $entityManager = /** @scrutinizer ignore-deprecated */ $arguments->getEntityManager();

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
95 5
96
        /** @var UnitOfWork $unitOfWork */
97
        $unitOfWork = $entityManager->getUnitOfWork();
98 5
99 5
        /** @param class-string $className */
100 1
        foreach ($unitOfWork->getIdentityMap() as $className => $entities) {
101
            if (!$this->hasRdmMappingForClass($className)) {
102
                continue;
103 4
            }
104
105
            foreach ($entities as $entity) {
106 4
                /** @var object $entity */
107 4
108
                if (!$this->isUnitializedProxy($entity)) {
109
                    if ($unitOfWork->isScheduledForDelete($entity)) {
110
                        $this->dbalDataLoader->removeDBALDataForEntity($entity, $entityManager);
111 4
112
                    } else {
113
                        $this->dbalDataLoader->storeDBALDataForEntity($entity, $entityManager);
114
                    }
115
                }
116
            }
117
        }
118 5
    }
119
120
    public function loadClassMetadata(LoadClassMetadataEventArgs $arguments): void
121 5
    {
122
        /** @var EntityManagerInterface $entityManager */
123
        $entityManager = $arguments->getEntityManager();
124 5
125
        /** @var ClassMetadata $classMetadata */
126 5
        $classMetadata = $arguments->getClassMetadata();
127
128
        try {
129
            $this->dbalDataLoader->prepareOnMetadataLoad($entityManager, $classMetadata);
130
131
        } catch (PDOException | ConnectionException $exception) {
132
            var_dump($exception->getMessage());
0 ignored issues
show
Security Debugging Code introduced by
var_dump($exception->getMessage()) looks like debug code. Are you sure you do not want to remove it?
Loading history...
133
            if (!str_contains($exception->getMessage(), 'No such file or directory')) {
134
                throw $exception;
135
            }
136 2
        }
137
    }
138
139 2
    /**
140
     * Invoked when doctrine has generated a table-definition in the target-schema.
141
     * Collects the additional schema-columns from the mapping and add's them to the table.
142 2
     *
143
     * Dispatched in:
144
     * @see SchemaTool::getSchemaFromMetadata
145 2
     */
146
    public function postGenerateSchemaTable(GenerateSchemaTableEventArgs $arguments): void
147
    {
148 2
        /** @var Table $table */
149
        $table = $arguments->getClassTable();
150 2
151
        /** @var ClassMetadata $classMetadata */
152 2
        $classMetadata = $arguments->getClassMetadata();
153
154 2
        /** @var class-string $className */
155
        $className = $classMetadata->getName();
156
157
        /** @var ?EntityMappingInterface $entityMapping */
158 2
        $entityMapping = $this->mappingDriver->loadRDMMetadataForClass($className);
159
160 2
        if ($entityMapping instanceof EntityMappingInterface) {
161 2
            /** @var array<Column> $additionalColumns */
162
            $additionalColumns = $entityMapping->collectDBALColumns();
163 2
164 2
            foreach ($additionalColumns as $column) {
165
                /** @var Column $column */
166
167
                /** @var string $columnName */
168
                $columnName = $column->getName();
169
170
                if (!$table->hasColumn($columnName)) {
171
                    
172 5
                    /** @var array<string, mixed> $columnConfig */
173
                    $columnConfig = $column->toArray();
174 5
                    unset($columnConfig['name']);
175
                    
176 5
                    $table->addColumn(
177
                        $columnName,
178
                        $column->getType()->getName(),
179 5
                        $columnConfig
180 5
                    );
181
                }
182
            }
183 5
        }
184 5
    }
185
186
    /** @param class-string $className */
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string.
Loading history...
187 5
    private function hasRdmMappingForClass(string $className): bool
188
    {
189
        if (!isset($this->hasRdmMappingForClass[$className])) {
190
            /** @var class-string $currentClassName */
191
            $currentClassName = $className;
192
193 4
            do {
194
                $this->hasRdmMappingForClass[$className] = is_object(
195
                    $this->mappingDriver->loadRDMMetadataForClass($currentClassName)
196 4
                );
197
198 4
                $currentClassName = current(class_parents($currentClassName));
199
            } while (class_exists($currentClassName) && !$this->hasRdmMappingForClass[$className]);
200
        }
201
202 4
        return $this->hasRdmMappingForClass[$className];
203
    }
204
205
    /**
206
     * @param object $entity
207
     */
208
    private function isUnitializedProxy($entity): bool
209
    {
210
        /** @var bool $isUnitializedProxy */
211
        $isUnitializedProxy = false;
212
213
        if ($entity instanceof Proxy && !$entity->__isInitialized()) {
214
            $isUnitializedProxy = true;
215
        }
216
217
        return $isUnitializedProxy;
218
    }
219
220
}
221