This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
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 | /* |
||
6 | * This file is part of the Sonata Project package. |
||
7 | * |
||
8 | * (c) Thomas Rabaix <[email protected]> |
||
9 | * |
||
10 | * For the full copyright and license information, please view the LICENSE |
||
11 | * file that was distributed with this source code. |
||
12 | */ |
||
13 | |||
14 | namespace Sonata\DoctrineORMAdminBundle\Model; |
||
15 | |||
16 | use Doctrine\Common\Util\ClassUtils; |
||
17 | use Doctrine\DBAL\DBALException; |
||
18 | use Doctrine\DBAL\LockMode; |
||
19 | use Doctrine\DBAL\Platforms\AbstractPlatform; |
||
20 | use Doctrine\DBAL\Types\Type; |
||
21 | use Doctrine\ORM\EntityManager; |
||
22 | use Doctrine\ORM\OptimisticLockException; |
||
23 | use Doctrine\ORM\Query; |
||
24 | use Doctrine\ORM\QueryBuilder; |
||
25 | use Doctrine\ORM\UnitOfWork; |
||
26 | use Doctrine\Persistence\ManagerRegistry; |
||
27 | use Doctrine\Persistence\Mapping\ClassMetadata; |
||
28 | use Sonata\AdminBundle\Admin\FieldDescriptionInterface; |
||
29 | use Sonata\AdminBundle\Datagrid\DatagridInterface; |
||
30 | use Sonata\AdminBundle\Datagrid\ProxyQueryInterface; |
||
31 | use Sonata\AdminBundle\Exception\LockException; |
||
32 | use Sonata\AdminBundle\Exception\ModelManagerException; |
||
33 | use Sonata\AdminBundle\Model\LockInterface; |
||
34 | use Sonata\AdminBundle\Model\ModelManagerInterface; |
||
35 | use Sonata\DoctrineORMAdminBundle\Admin\FieldDescription; |
||
36 | use Sonata\DoctrineORMAdminBundle\Datagrid\OrderByToSelectWalker; |
||
37 | use Sonata\DoctrineORMAdminBundle\Datagrid\ProxyQuery; |
||
38 | use Sonata\Exporter\Source\DoctrineORMQuerySourceIterator; |
||
39 | use Symfony\Component\PropertyAccess\PropertyAccess; |
||
40 | use Symfony\Component\PropertyAccess\PropertyAccessorInterface; |
||
41 | |||
42 | class ModelManager implements ModelManagerInterface, LockInterface |
||
43 | { |
||
44 | public const ID_SEPARATOR = '~'; |
||
45 | |||
46 | /** |
||
47 | * @var ManagerRegistry |
||
48 | */ |
||
49 | protected $registry; |
||
50 | |||
51 | /** |
||
52 | * @var PropertyAccessorInterface |
||
53 | */ |
||
54 | protected $propertyAccessor; |
||
55 | |||
56 | /** |
||
57 | * @var EntityManager[] |
||
58 | */ |
||
59 | protected $cache = []; |
||
60 | |||
61 | /** |
||
62 | * NEXT_MAJOR: Make $propertyAccessor mandatory. |
||
63 | */ |
||
64 | public function __construct(ManagerRegistry $registry, ?PropertyAccessorInterface $propertyAccessor = null) |
||
65 | { |
||
66 | $this->registry = $registry; |
||
67 | |||
68 | // NEXT_MAJOR: Remove this block. |
||
69 | if (null === $propertyAccessor) { |
||
70 | @trigger_error(sprintf( |
||
0 ignored issues
–
show
|
|||
71 | 'Constructing "%s" without passing an instance of "%s" as second argument is deprecated since' |
||
72 | .' sonata-project/doctrine-orm-admin-bundle 3.x and will be mandatory in 4.0', |
||
73 | __CLASS__, |
||
74 | PropertyAccessorInterface::class |
||
75 | ), E_USER_DEPRECATED); |
||
76 | |||
77 | $propertyAccessor = PropertyAccess::createPropertyAccessor(); |
||
78 | } |
||
79 | |||
80 | $this->propertyAccessor = $propertyAccessor; |
||
81 | } |
||
82 | |||
83 | /** |
||
84 | * @param string $class |
||
85 | * |
||
86 | * @return ClassMetadata |
||
87 | */ |
||
88 | public function getMetadata($class) |
||
89 | { |
||
90 | return $this->getEntityManager($class)->getMetadataFactory()->getMetadataFor($class); |
||
91 | } |
||
92 | |||
93 | /** |
||
94 | * Returns the model's metadata holding the fully qualified property, and the last |
||
95 | * property name. |
||
96 | * |
||
97 | * @param string $baseClass The base class of the model holding the fully qualified property |
||
98 | * @param string $propertyFullName The name of the fully qualified property (dot ('.') separated |
||
99 | * property string) |
||
100 | * |
||
101 | * @return array( |
||
0 ignored issues
–
show
The doc-type
array( could not be parsed: Expected "|" or "end of type", but got "(" at position 5. (view supported doc-types)
This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types. ![]() |
|||
102 | * \Doctrine\ORM\Mapping\ClassMetadata $parentMetadata, |
||
103 | * string $lastPropertyName, |
||
104 | * array $parentAssociationMappings |
||
105 | * ) |
||
106 | */ |
||
107 | public function getParentMetadataForProperty($baseClass, $propertyFullName) |
||
108 | { |
||
109 | $nameElements = explode('.', $propertyFullName); |
||
110 | $lastPropertyName = array_pop($nameElements); |
||
111 | $class = $baseClass; |
||
112 | $parentAssociationMappings = []; |
||
113 | |||
114 | foreach ($nameElements as $nameElement) { |
||
115 | $metadata = $this->getMetadata($class); |
||
116 | |||
117 | if (isset($metadata->associationMappings[$nameElement])) { |
||
0 ignored issues
–
show
Accessing
associationMappings on the interface Doctrine\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() |
|||
118 | $parentAssociationMappings[] = $metadata->associationMappings[$nameElement]; |
||
0 ignored issues
–
show
Accessing
associationMappings on the interface Doctrine\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() |
|||
119 | $class = $metadata->getAssociationTargetClass($nameElement); |
||
120 | |||
121 | continue; |
||
122 | } |
||
123 | |||
124 | break; |
||
125 | } |
||
126 | |||
127 | $properties = \array_slice($nameElements, \count($parentAssociationMappings)); |
||
128 | $properties[] = $lastPropertyName; |
||
129 | |||
130 | return [$this->getMetadata($class), implode('.', $properties), $parentAssociationMappings]; |
||
131 | } |
||
132 | |||
133 | /** |
||
134 | * @param string $class |
||
135 | * |
||
136 | * @return bool |
||
137 | */ |
||
138 | public function hasMetadata($class) |
||
139 | { |
||
140 | return $this->getEntityManager($class)->getMetadataFactory()->hasMetadataFor($class); |
||
141 | } |
||
142 | |||
143 | public function getNewFieldDescriptionInstance($class, $name, array $options = []) |
||
144 | { |
||
145 | if (!\is_string($name)) { |
||
146 | throw new \RuntimeException('The name argument must be a string'); |
||
147 | } |
||
148 | |||
149 | if (!isset($options['route']['name'])) { |
||
150 | $options['route']['name'] = 'edit'; |
||
151 | } |
||
152 | |||
153 | if (!isset($options['route']['parameters'])) { |
||
154 | $options['route']['parameters'] = []; |
||
155 | } |
||
156 | |||
157 | list($metadata, $propertyName, $parentAssociationMappings) = $this->getParentMetadataForProperty($class, $name); |
||
158 | |||
159 | $fieldDescription = new FieldDescription(); |
||
160 | $fieldDescription->setName($name); |
||
161 | $fieldDescription->setOptions($options); |
||
162 | $fieldDescription->setParentAssociationMappings($parentAssociationMappings); |
||
163 | |||
164 | if (isset($metadata->associationMappings[$propertyName])) { |
||
0 ignored issues
–
show
Accessing
associationMappings on the interface Doctrine\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() |
|||
165 | $fieldDescription->setAssociationMapping($metadata->associationMappings[$propertyName]); |
||
0 ignored issues
–
show
Accessing
associationMappings on the interface Doctrine\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() |
|||
166 | } |
||
167 | |||
168 | if (isset($metadata->fieldMappings[$propertyName])) { |
||
0 ignored issues
–
show
Accessing
fieldMappings on the interface Doctrine\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() |
|||
169 | $fieldDescription->setFieldMapping($metadata->fieldMappings[$propertyName]); |
||
0 ignored issues
–
show
Accessing
fieldMappings on the interface Doctrine\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() |
|||
170 | } |
||
171 | |||
172 | return $fieldDescription; |
||
173 | } |
||
174 | |||
175 | public function create($object): void |
||
176 | { |
||
177 | try { |
||
178 | $entityManager = $this->getEntityManager($object); |
||
179 | $entityManager->persist($object); |
||
180 | $entityManager->flush(); |
||
181 | } catch (\PDOException $e) { |
||
182 | throw new ModelManagerException( |
||
183 | sprintf('Failed to create object: %s', ClassUtils::getClass($object)), |
||
184 | $e->getCode(), |
||
185 | $e |
||
186 | ); |
||
187 | } catch (DBALException $e) { |
||
188 | throw new ModelManagerException( |
||
189 | sprintf('Failed to create object: %s', ClassUtils::getClass($object)), |
||
190 | $e->getCode(), |
||
191 | $e |
||
192 | ); |
||
193 | } |
||
194 | } |
||
195 | |||
196 | public function update($object): void |
||
197 | { |
||
198 | try { |
||
199 | $entityManager = $this->getEntityManager($object); |
||
200 | $entityManager->persist($object); |
||
201 | $entityManager->flush(); |
||
202 | } catch (\PDOException $e) { |
||
203 | throw new ModelManagerException( |
||
204 | sprintf('Failed to update object: %s', ClassUtils::getClass($object)), |
||
205 | $e->getCode(), |
||
206 | $e |
||
207 | ); |
||
208 | } catch (DBALException $e) { |
||
209 | throw new ModelManagerException( |
||
210 | sprintf('Failed to update object: %s', ClassUtils::getClass($object)), |
||
211 | $e->getCode(), |
||
212 | $e |
||
213 | ); |
||
214 | } |
||
215 | } |
||
216 | |||
217 | public function delete($object): void |
||
218 | { |
||
219 | try { |
||
220 | $entityManager = $this->getEntityManager($object); |
||
221 | $entityManager->remove($object); |
||
222 | $entityManager->flush(); |
||
223 | } catch (\PDOException $e) { |
||
224 | throw new ModelManagerException( |
||
225 | sprintf('Failed to delete object: %s', ClassUtils::getClass($object)), |
||
226 | $e->getCode(), |
||
227 | $e |
||
228 | ); |
||
229 | } catch (DBALException $e) { |
||
230 | throw new ModelManagerException( |
||
231 | sprintf('Failed to delete object: %s', ClassUtils::getClass($object)), |
||
232 | $e->getCode(), |
||
233 | $e |
||
234 | ); |
||
235 | } |
||
236 | } |
||
237 | |||
238 | public function getLockVersion($object) |
||
239 | { |
||
240 | $metadata = $this->getMetadata(ClassUtils::getClass($object)); |
||
241 | |||
242 | if (!$metadata->isVersioned) { |
||
0 ignored issues
–
show
Accessing
isVersioned on the interface Doctrine\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() |
|||
243 | return null; |
||
244 | } |
||
245 | |||
246 | return $metadata->reflFields[$metadata->versionField]->getValue($object); |
||
0 ignored issues
–
show
Accessing
reflFields on the interface Doctrine\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() Accessing
versionField on the interface Doctrine\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() |
|||
247 | } |
||
248 | |||
249 | public function lock($object, $expectedVersion): void |
||
250 | { |
||
251 | $metadata = $this->getMetadata(ClassUtils::getClass($object)); |
||
252 | |||
253 | if (!$metadata->isVersioned) { |
||
0 ignored issues
–
show
Accessing
isVersioned on the interface Doctrine\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() |
|||
254 | return; |
||
255 | } |
||
256 | |||
257 | try { |
||
258 | $entityManager = $this->getEntityManager($object); |
||
259 | $entityManager->lock($object, LockMode::OPTIMISTIC, $expectedVersion); |
||
260 | } catch (OptimisticLockException $e) { |
||
261 | throw new LockException($e->getMessage(), $e->getCode(), $e); |
||
262 | } |
||
263 | } |
||
264 | |||
265 | public function find($class, $id) |
||
266 | { |
||
267 | if (null === $id) { |
||
268 | @trigger_error(sprintf( |
||
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||
269 | 'Passing null as argument 1 for %s() is deprecated since sonata-project/doctrine-orm-admin-bundle 3.20 and will be not allowed in version 4.0.', |
||
270 | __METHOD__ |
||
271 | ), E_USER_DEPRECATED); |
||
272 | |||
273 | return null; |
||
274 | } |
||
275 | |||
276 | $values = array_combine($this->getIdentifierFieldNames($class), explode(self::ID_SEPARATOR, (string) $id)); |
||
277 | |||
278 | return $this->getEntityManager($class)->getRepository($class)->find($values); |
||
279 | } |
||
280 | |||
281 | public function findBy($class, array $criteria = []) |
||
282 | { |
||
283 | return $this->getEntityManager($class)->getRepository($class)->findBy($criteria); |
||
284 | } |
||
285 | |||
286 | public function findOneBy($class, array $criteria = []) |
||
287 | { |
||
288 | return $this->getEntityManager($class)->getRepository($class)->findOneBy($criteria); |
||
289 | } |
||
290 | |||
291 | /** |
||
292 | * @param string|object $class |
||
293 | * |
||
294 | * @return EntityManager |
||
295 | */ |
||
296 | public function getEntityManager($class) |
||
297 | { |
||
298 | if (\is_object($class)) { |
||
299 | $class = \get_class($class); |
||
300 | } |
||
301 | |||
302 | if (!isset($this->cache[$class])) { |
||
303 | $em = $this->registry->getManagerForClass($class); |
||
304 | |||
305 | if (!$em) { |
||
306 | throw new \RuntimeException(sprintf('No entity manager defined for class %s', $class)); |
||
307 | } |
||
308 | |||
309 | $this->cache[$class] = $em; |
||
310 | } |
||
311 | |||
312 | return $this->cache[$class]; |
||
313 | } |
||
314 | |||
315 | /** |
||
316 | * NEXT_MAJOR: Remove this method. |
||
317 | * |
||
318 | * @deprecated since sonata-project/doctrine-orm-admin-bundle 3.x and will be removed in version 4.0 |
||
319 | */ |
||
320 | public function getParentFieldDescription($parentAssociationMapping, $class) |
||
321 | { |
||
322 | @trigger_error(sprintf( |
||
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||
323 | 'Method %s() is deprecated since sonata-project/doctrine-orm-admin-bundle 3.x and will be removed in 4.0', |
||
324 | __METHOD__ |
||
325 | ), E_USER_DEPRECATED); |
||
326 | |||
327 | $fieldName = $parentAssociationMapping['fieldName']; |
||
328 | |||
329 | $metadata = $this->getMetadata($class); |
||
330 | |||
331 | $associatingMapping = $metadata->associationMappings[$parentAssociationMapping]; |
||
0 ignored issues
–
show
Accessing
associationMappings on the interface Doctrine\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() |
|||
332 | |||
333 | $fieldDescription = $this->getNewFieldDescriptionInstance($class, $fieldName); |
||
334 | $fieldDescription->setName($parentAssociationMapping); |
||
0 ignored issues
–
show
$parentAssociationMapping is of type array , but the function expects a string .
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);
![]() |
|||
335 | $fieldDescription->setAssociationMapping($associatingMapping); |
||
336 | |||
337 | return $fieldDescription; |
||
338 | } |
||
339 | |||
340 | public function createQuery($class, $alias = 'o') |
||
341 | { |
||
342 | $repository = $this->getEntityManager($class)->getRepository($class); |
||
343 | |||
344 | return new ProxyQuery($repository->createQueryBuilder($alias)); |
||
345 | } |
||
346 | |||
347 | public function executeQuery($query) |
||
348 | { |
||
349 | if ($query instanceof QueryBuilder) { |
||
350 | return $query->getQuery()->execute(); |
||
351 | } |
||
352 | |||
353 | return $query->execute(); |
||
354 | } |
||
355 | |||
356 | /** |
||
357 | * NEXT_MAJOR: Remove this function. |
||
358 | * |
||
359 | * @deprecated since sonata-project/doctrine-orm-admin-bundle 3.18. To be removed in 4.0. |
||
360 | */ |
||
361 | public function getModelIdentifier($class) |
||
362 | { |
||
363 | return $this->getMetadata($class)->identifier; |
||
0 ignored issues
–
show
Accessing
identifier on the interface Doctrine\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() |
|||
364 | } |
||
365 | |||
366 | public function getIdentifierValues($entity) |
||
367 | { |
||
368 | // Fix code has an impact on performance, so disable it ... |
||
369 | //$entityManager = $this->getEntityManager($entity); |
||
370 | //if (!$entityManager->getUnitOfWork()->isInIdentityMap($entity)) { |
||
371 | // throw new \RuntimeException('Entities passed to the choice field must be managed'); |
||
372 | //} |
||
373 | |||
374 | $class = ClassUtils::getClass($entity); |
||
375 | $metadata = $this->getMetadata($class); |
||
376 | $platform = $this->getEntityManager($class)->getConnection()->getDatabasePlatform(); |
||
377 | |||
378 | $identifiers = []; |
||
379 | |||
380 | foreach ($metadata->getIdentifierValues($entity) as $name => $value) { |
||
381 | if (!\is_object($value)) { |
||
382 | $identifiers[] = $value; |
||
383 | |||
384 | continue; |
||
385 | } |
||
386 | |||
387 | $fieldType = $metadata->getTypeOfField($name); |
||
388 | $type = $fieldType && Type::hasType($fieldType) ? Type::getType($fieldType) : null; |
||
389 | if ($type) { |
||
390 | $identifiers[] = $this->getValueFromType($value, $type, $fieldType, $platform); |
||
391 | |||
392 | continue; |
||
393 | } |
||
394 | |||
395 | $identifierMetadata = $this->getMetadata(ClassUtils::getClass($value)); |
||
396 | |||
397 | foreach ($identifierMetadata->getIdentifierValues($value) as $value) { |
||
398 | $identifiers[] = $value; |
||
399 | } |
||
400 | } |
||
401 | |||
402 | return $identifiers; |
||
403 | } |
||
404 | |||
405 | public function getIdentifierFieldNames($class) |
||
406 | { |
||
407 | return $this->getMetadata($class)->getIdentifierFieldNames(); |
||
408 | } |
||
409 | |||
410 | public function getNormalizedIdentifier($entity) |
||
411 | { |
||
412 | // NEXT_MAJOR: Remove the following 2 checks and declare "object" as type for argument 1. |
||
413 | if (null === $entity) { |
||
414 | @trigger_error(sprintf( |
||
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||
415 | 'Passing null as argument 1 for %s() is deprecated since sonata-project/doctrine-orm-admin-bundle 3.20 and will be not allowed in version 4.0.', |
||
416 | __METHOD__ |
||
417 | ), E_USER_DEPRECATED); |
||
418 | |||
419 | return null; |
||
420 | } |
||
421 | |||
422 | if (!\is_object($entity)) { |
||
423 | throw new \RuntimeException('Invalid argument, object or null required'); |
||
424 | } |
||
425 | |||
426 | if (\in_array($this->getEntityManager($entity)->getUnitOfWork()->getEntityState($entity), [ |
||
427 | UnitOfWork::STATE_NEW, |
||
428 | UnitOfWork::STATE_REMOVED, |
||
429 | ], true)) { |
||
430 | // NEXT_MAJOR: Uncomment the following exception, remove the deprecation and the return statement inside this conditional block. |
||
431 | // throw new \InvalidArgumentException(sprintf( |
||
432 | // 'Can not get the normalized identifier for %s since it is in state %u.', |
||
433 | // ClassUtils::getClass($entity), |
||
434 | // $this->getEntityManager($entity)->getUnitOfWork()->getEntityState($entity) |
||
435 | // )); |
||
436 | |||
437 | @trigger_error(sprintf( |
||
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||
438 | 'Passing an object which is in state %u (new) or %u (removed) as argument 1 for %s() is deprecated since sonata-project/doctrine-orm-admin-bundle 3.20' |
||
439 | .'and will be not allowed in version 4.0.', |
||
440 | UnitOfWork::STATE_NEW, |
||
441 | UnitOfWork::STATE_REMOVED, |
||
442 | __METHOD__ |
||
443 | ), E_USER_DEPRECATED); |
||
444 | |||
445 | return null; |
||
446 | } |
||
447 | |||
448 | $values = $this->getIdentifierValues($entity); |
||
449 | |||
450 | if (0 === \count($values)) { |
||
451 | return null; |
||
452 | } |
||
453 | |||
454 | return implode(self::ID_SEPARATOR, $values); |
||
455 | } |
||
456 | |||
457 | /** |
||
458 | * {@inheritdoc} |
||
459 | * |
||
460 | * The ORM implementation does nothing special but you still should use |
||
461 | * this method when using the id in a URL to allow for future improvements. |
||
462 | */ |
||
463 | public function getUrlSafeIdentifier($entity) |
||
464 | { |
||
465 | // NEXT_MAJOR: Remove the following check and declare "object" as type for argument 1. |
||
466 | if (!\is_object($entity)) { |
||
467 | @trigger_error(sprintf( |
||
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||
468 | 'Passing other type than object for argument 1 for %s() is deprecated since sonata-project/doctrine-orm-admin-bundle 3.20 and will be not allowed in version 4.0.', |
||
469 | __METHOD__ |
||
470 | ), E_USER_DEPRECATED); |
||
471 | |||
472 | return null; |
||
473 | } |
||
474 | |||
475 | return $this->getNormalizedIdentifier($entity); |
||
476 | } |
||
477 | |||
478 | public function addIdentifiersToQuery($class, ProxyQueryInterface $queryProxy, array $idx): void |
||
479 | { |
||
480 | $fieldNames = $this->getIdentifierFieldNames($class); |
||
481 | $qb = $queryProxy->getQueryBuilder(); |
||
482 | |||
483 | $prefix = uniqid(); |
||
484 | $sqls = []; |
||
485 | foreach ($idx as $pos => $id) { |
||
486 | $ids = explode(self::ID_SEPARATOR, $id); |
||
487 | |||
488 | $ands = []; |
||
489 | foreach ($fieldNames as $posName => $name) { |
||
490 | $parameterName = sprintf('field_%s_%s_%d', $prefix, $name, $pos); |
||
491 | $ands[] = sprintf('%s.%s = :%s', current($qb->getRootAliases()), $name, $parameterName); |
||
492 | $qb->setParameter($parameterName, $ids[$posName]); |
||
493 | } |
||
494 | |||
495 | $sqls[] = implode(' AND ', $ands); |
||
496 | } |
||
497 | |||
498 | $qb->andWhere(sprintf('( %s )', implode(' OR ', $sqls))); |
||
499 | } |
||
500 | |||
501 | public function batchDelete($class, ProxyQueryInterface $queryProxy): void |
||
502 | { |
||
503 | $queryProxy->select('DISTINCT '.current($queryProxy->getRootAliases())); |
||
504 | |||
505 | try { |
||
506 | $entityManager = $this->getEntityManager($class); |
||
507 | |||
508 | $i = 0; |
||
509 | foreach ($queryProxy->getQuery()->iterate() as $pos => $object) { |
||
510 | $entityManager->remove($object[0]); |
||
511 | |||
512 | if (0 === (++$i % 20)) { |
||
513 | $entityManager->flush(); |
||
514 | $entityManager->clear(); |
||
515 | } |
||
516 | } |
||
517 | |||
518 | $entityManager->flush(); |
||
519 | $entityManager->clear(); |
||
520 | } catch (\PDOException | DBALException $e) { |
||
521 | throw new ModelManagerException('', 0, $e); |
||
522 | } |
||
523 | } |
||
524 | |||
525 | public function getDataSourceIterator(DatagridInterface $datagrid, array $fields, $firstResult = null, $maxResult = null) |
||
526 | { |
||
527 | $datagrid->buildPager(); |
||
528 | $query = $datagrid->getQuery(); |
||
529 | |||
530 | $query->select('DISTINCT '.current($query->getRootAliases())); |
||
531 | $query->setFirstResult($firstResult); |
||
532 | $query->setMaxResults($maxResult); |
||
533 | |||
534 | if ($query instanceof ProxyQueryInterface) { |
||
535 | $sortBy = $query->getSortBy(); |
||
536 | |||
537 | if (!empty($sortBy)) { |
||
538 | $query->addOrderBy($sortBy, $query->getSortOrder()); |
||
539 | $query = $query->getQuery(); |
||
540 | $query->setHint(Query::HINT_CUSTOM_TREE_WALKERS, [OrderByToSelectWalker::class]); |
||
541 | } else { |
||
542 | $query = $query->getQuery(); |
||
543 | } |
||
544 | } |
||
545 | |||
546 | return new DoctrineORMQuerySourceIterator($query, $fields); |
||
547 | } |
||
548 | |||
549 | public function getExportFields($class) |
||
550 | { |
||
551 | $metadata = $this->getEntityManager($class)->getClassMetadata($class); |
||
552 | |||
553 | return $metadata->getFieldNames(); |
||
554 | } |
||
555 | |||
556 | public function getModelInstance($class) |
||
557 | { |
||
558 | $r = new \ReflectionClass($class); |
||
559 | if ($r->isAbstract()) { |
||
560 | throw new \RuntimeException(sprintf('Cannot initialize abstract class: %s', $class)); |
||
561 | } |
||
562 | |||
563 | $constructor = $r->getConstructor(); |
||
564 | |||
565 | if (null !== $constructor && (!$constructor->isPublic() || $constructor->getNumberOfRequiredParameters() > 0)) { |
||
566 | return $r->newInstanceWithoutConstructor(); |
||
567 | } |
||
568 | |||
569 | return new $class(); |
||
570 | } |
||
571 | |||
572 | public function getSortParameters(FieldDescriptionInterface $fieldDescription, DatagridInterface $datagrid) |
||
573 | { |
||
574 | $values = $datagrid->getValues(); |
||
575 | |||
576 | if ($this->isFieldAlreadySorted($fieldDescription, $datagrid)) { |
||
577 | if ('ASC' === $values['_sort_order']) { |
||
578 | $values['_sort_order'] = 'DESC'; |
||
579 | } else { |
||
580 | $values['_sort_order'] = 'ASC'; |
||
581 | } |
||
582 | } else { |
||
583 | $values['_sort_order'] = 'ASC'; |
||
584 | } |
||
585 | |||
586 | $values['_sort_by'] = \is_string($fieldDescription->getOption('sortable')) ? $fieldDescription->getOption('sortable') : $fieldDescription->getName(); |
||
587 | |||
588 | return ['filter' => $values]; |
||
589 | } |
||
590 | |||
591 | public function getPaginationParameters(DatagridInterface $datagrid, $page) |
||
592 | { |
||
593 | $values = $datagrid->getValues(); |
||
594 | |||
595 | if (isset($values['_sort_by']) && $values['_sort_by'] instanceof FieldDescriptionInterface) { |
||
596 | $values['_sort_by'] = $values['_sort_by']->getName(); |
||
597 | } |
||
598 | $values['_page'] = $page; |
||
599 | |||
600 | return ['filter' => $values]; |
||
601 | } |
||
602 | |||
603 | public function getDefaultSortValues($class) |
||
604 | { |
||
605 | return [ |
||
606 | '_page' => 1, |
||
607 | '_per_page' => 25, |
||
608 | ]; |
||
609 | } |
||
610 | |||
611 | public function getDefaultPerPageOptions(string $class): array |
||
0 ignored issues
–
show
|
|||
612 | { |
||
613 | return [10, 25, 50, 100, 250]; |
||
614 | } |
||
615 | |||
616 | public function modelTransform($class, $instance) |
||
617 | { |
||
618 | return $instance; |
||
619 | } |
||
620 | |||
621 | public function modelReverseTransform($class, array $array = []) |
||
622 | { |
||
623 | $instance = $this->getModelInstance($class); |
||
624 | $metadata = $this->getMetadata($class); |
||
625 | |||
626 | foreach ($array as $name => $value) { |
||
627 | $property = $this->getFieldName($metadata, $name); |
||
628 | $this->propertyAccessor->setValue($instance, $property, $value); |
||
629 | } |
||
630 | |||
631 | return $instance; |
||
0 ignored issues
–
show
|
|||
632 | } |
||
633 | |||
634 | public function getModelCollectionInstance($class) |
||
635 | { |
||
636 | return new \Doctrine\Common\Collections\ArrayCollection(); |
||
637 | } |
||
638 | |||
639 | public function collectionClear(&$collection) |
||
640 | { |
||
641 | return $collection->clear(); |
||
0 ignored issues
–
show
|
|||
642 | } |
||
643 | |||
644 | public function collectionHasElement(&$collection, &$element) |
||
645 | { |
||
646 | return $collection->contains($element); |
||
0 ignored issues
–
show
|
|||
647 | } |
||
648 | |||
649 | public function collectionAddElement(&$collection, &$element) |
||
650 | { |
||
651 | return $collection->add($element); |
||
0 ignored issues
–
show
|
|||
652 | } |
||
653 | |||
654 | public function collectionRemoveElement(&$collection, &$element) |
||
655 | { |
||
656 | return $collection->removeElement($element); |
||
0 ignored issues
–
show
|
|||
657 | } |
||
658 | |||
659 | /** |
||
660 | * NEXT_MAJOR: Remove this method. |
||
661 | * |
||
662 | * @param string $property |
||
663 | * |
||
664 | * @return mixed |
||
665 | */ |
||
666 | protected function camelize($property) |
||
667 | { |
||
668 | @trigger_error(sprintf( |
||
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||
669 | 'Method %s() is deprecated since sonata-project/doctrine-orm-admin-bundle 3.x and will be removed in version 4.0.', |
||
670 | __METHOD__ |
||
671 | ), E_USER_DEPRECATED); |
||
672 | |||
673 | return str_replace(' ', '', ucwords(str_replace('_', ' ', $property))); |
||
674 | } |
||
675 | |||
676 | private function getFieldName(ClassMetadata $metadata, string $name): string |
||
677 | { |
||
678 | if (\array_key_exists($name, $metadata->fieldMappings)) { |
||
0 ignored issues
–
show
Accessing
fieldMappings on the interface Doctrine\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() |
|||
679 | return $metadata->fieldMappings[$name]['fieldName']; |
||
0 ignored issues
–
show
Accessing
fieldMappings on the interface Doctrine\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() |
|||
680 | } |
||
681 | |||
682 | if (\array_key_exists($name, $metadata->associationMappings)) { |
||
0 ignored issues
–
show
Accessing
associationMappings on the interface Doctrine\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() |
|||
683 | return $metadata->associationMappings[$name]['fieldName']; |
||
0 ignored issues
–
show
Accessing
associationMappings on the interface Doctrine\Persistence\Mapping\ClassMetadata suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() |
|||
684 | } |
||
685 | |||
686 | return $name; |
||
687 | } |
||
688 | |||
689 | private function isFieldAlreadySorted(FieldDescriptionInterface $fieldDescription, DatagridInterface $datagrid): bool |
||
690 | { |
||
691 | $values = $datagrid->getValues(); |
||
692 | |||
693 | if (!isset($values['_sort_by']) || !$values['_sort_by'] instanceof FieldDescriptionInterface) { |
||
694 | return false; |
||
695 | } |
||
696 | |||
697 | return $values['_sort_by']->getName() === $fieldDescription->getName() |
||
698 | || $values['_sort_by']->getName() === $fieldDescription->getOption('sortable'); |
||
699 | } |
||
700 | |||
701 | /** |
||
702 | * @param mixed $value |
||
703 | */ |
||
704 | private function getValueFromType($value, Type $type, string $fieldType, AbstractPlatform $platform): string |
||
705 | { |
||
706 | if ($platform->hasDoctrineTypeMappingFor($fieldType) && |
||
707 | 'binary' === $platform->getDoctrineTypeMapping($fieldType) |
||
708 | ) { |
||
709 | return (string) $type->convertToPHPValue($value, $platform); |
||
710 | } |
||
711 | |||
712 | // some libraries may have `toString()` implementation |
||
713 | if (\is_callable([$value, 'toString'])) { |
||
714 | return $value->toString(); |
||
715 | } |
||
716 | |||
717 | // final fallback to magic `__toString()` which may throw an exception in 7.4 |
||
718 | if (method_exists($value, '__toString')) { |
||
719 | return $value->__toString(); |
||
720 | } |
||
721 | |||
722 | return (string) $type->convertToDatabaseValue($value, $platform); |
||
723 | } |
||
724 | } |
||
725 |
If you suppress an error, we recommend checking for the error condition explicitly: