From 5907f232fce71999d8b5de8eb8e493141d48344b Mon Sep 17 00:00:00 2001 From: Romain Monteil Date: Tue, 1 Jul 2025 23:55:48 +0200 Subject: [PATCH 1/3] Use getFieldValue and setFieldValue methods Add sluggable test with embeddable Update CHANGELOG --- CHANGELOG.md | 1 + phpstan-baseline.neon | 90 +++++++++++++---- src/AbstractTrackingListener.php | 11 +-- src/Loggable/LoggableListener.php | 2 +- src/Loggable/Mapping/Event/Adapter/ODM.php | 2 +- src/Mapping/MappedEventSubscriber.php | 2 +- .../ReferenceIntegrityListener.php | 35 ++++--- src/References/Mapping/Event/Adapter/ODM.php | 4 +- src/References/Mapping/Event/Adapter/ORM.php | 6 +- .../Handler/InversedRelativeSlugHandler.php | 4 +- src/Sluggable/Handler/TreeSlugHandler.php | 4 +- src/Sluggable/SluggableListener.php | 14 +-- src/SoftDeleteable/SoftDeleteableListener.php | 5 +- src/Sortable/Mapping/Event/Adapter/ODM.php | 2 +- src/Sortable/SortableListener.php | 18 ++-- src/Tool/Wrapper/EntityWrapper.php | 4 +- src/Tool/Wrapper/MongoDocumentWrapper.php | 4 +- .../Repository/TranslationRepository.php | 14 +-- .../Repository/TranslationRepository.php | 14 +-- src/Translatable/TranslatableListener.php | 2 +- .../Repository/ClosureTreeRepository.php | 4 +- .../Repository/NestedTreeRepository.php | 33 +++---- src/Tree/Hydrator/ORM/TreeObjectHydrator.php | 4 +- .../Strategy/AbstractMaterializedPath.php | 48 +++------- .../Strategy/ODM/MongoDB/MaterializedPath.php | 8 +- src/Tree/Strategy/ORM/Closure.php | 12 +-- src/Tree/Strategy/ORM/Nested.php | 40 ++++---- src/Uploadable/UploadableListener.php | 5 +- .../Sluggable/Fixture/Embeddable/Address.php | 86 +++++++++++++++++ .../Sluggable/Fixture/Embeddable/User.php | 96 +++++++++++++++++++ .../Sluggable/SluggableEmbeddableTest.php | 55 +++++++++++ 31 files changed, 443 insertions(+), 186 deletions(-) create mode 100644 tests/Gedmo/Sluggable/Fixture/Embeddable/Address.php create mode 100644 tests/Gedmo/Sluggable/Fixture/Embeddable/User.php create mode 100644 tests/Gedmo/Sluggable/SluggableEmbeddableTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index d303164147..6fbc55774c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ a release. ### Changed - Sluggable: Replaced abandoned `behat/transliterator` with `symfony/string` for default transliteration and urlization steps (#2985) +- Use `getFieldValue` and `setFieldValue` methods to support `doctrine/orm` >= 3.4 (#2966) ## [3.20.1] - 2025-09-14 ### Fixed diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 3a0d96376b..2a8058ceca 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1,11 +1,17 @@ parameters: ignoreErrors: - - message: '#^Call to an undefined method Doctrine\\Persistence\\Mapping\\ClassMetadata\\:\:getReflectionProperty\(\)\.$#' + message: '#^Call to an undefined method Doctrine\\Persistence\\Mapping\\ClassMetadata\\:\:getFieldValue\(\)\.$#' identifier: method.notFound count: 4 path: src/AbstractTrackingListener.php + - + message: '#^Call to an undefined method Doctrine\\Persistence\\Mapping\\ClassMetadata\\:\:setFieldValue\(\)\.$#' + identifier: method.notFound + count: 1 + path: src/AbstractTrackingListener.php + - message: '#^Call to an undefined method Doctrine\\Persistence\\ObjectManager\:\:getUnitOfWork\(\)\.$#' identifier: method.notFound @@ -73,13 +79,13 @@ parameters: path: src/Loggable/Entity/Repository/LogEntryRepository.php - - message: '#^Call to an undefined method Doctrine\\Persistence\\Mapping\\ClassMetadata\\>\:\:getReflectionProperty\(\)\.$#' + message: '#^Call to an undefined method Doctrine\\Persistence\\Mapping\\ClassMetadata\\>\:\:newInstance\(\)\.$#' identifier: method.notFound count: 1 path: src/Loggable/LoggableListener.php - - message: '#^Call to an undefined method Doctrine\\Persistence\\Mapping\\ClassMetadata\\>\:\:newInstance\(\)\.$#' + message: '#^Call to an undefined method Doctrine\\Persistence\\Mapping\\ClassMetadata\\>\:\:setFieldValue\(\)\.$#' identifier: method.notFound count: 1 path: src/Loggable/LoggableListener.php @@ -205,7 +211,7 @@ parameters: path: src/Mapping/ExtensionMetadataFactory.php - - message: '#^Call to an undefined method Doctrine\\Persistence\\Mapping\\ClassMetadata\\:\:getReflectionProperty\(\)\.$#' + message: '#^Call to an undefined method Doctrine\\Persistence\\Mapping\\ClassMetadata\\:\:setFieldValue\(\)\.$#' identifier: method.notFound count: 1 path: src/Mapping/MappedEventSubscriber.php @@ -235,7 +241,7 @@ parameters: path: src/ReferenceIntegrity/ReferenceIntegrityListener.php - - message: '#^Call to an undefined method Doctrine\\Persistence\\Mapping\\ClassMetadata\\:\:getReflectionProperty\(\)\.$#' + message: '#^Call to an undefined method Doctrine\\Persistence\\Mapping\\ClassMetadata\\:\:getFieldValue\(\)\.$#' identifier: method.notFound count: 3 path: src/ReferenceIntegrity/ReferenceIntegrityListener.php @@ -252,6 +258,12 @@ parameters: count: 1 path: src/ReferenceIntegrity/ReferenceIntegrityListener.php + - + message: '#^Call to an undefined method Doctrine\\Persistence\\Mapping\\ClassMetadata\\:\:setFieldValue\(\)\.$#' + identifier: method.notFound + count: 4 + path: src/ReferenceIntegrity/ReferenceIntegrityListener.php + - message: '#^Access to offset ''inherited'' on an unknown class Doctrine\\ODM\\MongoDB\\Mapping\\AssociationFieldMapping\.$#' identifier: class.notFound @@ -259,7 +271,7 @@ parameters: path: src/References/Mapping/Driver/Attribute.php - - message: '#^Call to an undefined method Doctrine\\Persistence\\Mapping\\ClassMetadata\\:\:getReflectionProperty\(\)\.$#' + message: '#^Call to an undefined method Doctrine\\Persistence\\Mapping\\ClassMetadata\\:\:getFieldValue\(\)\.$#' identifier: method.notFound count: 1 path: src/References/Mapping/Event/Adapter/ODM.php @@ -283,7 +295,7 @@ parameters: path: src/References/Mapping/Event/Adapter/ODM.php - - message: '#^Call to an undefined method Doctrine\\Persistence\\Mapping\\ClassMetadata\\:\:getReflectionProperty\(\)\.$#' + message: '#^Call to an undefined method Doctrine\\Persistence\\Mapping\\ClassMetadata\\:\:getFieldValue\(\)\.$#' identifier: method.notFound count: 2 path: src/References/Mapping/Event/Adapter/ORM.php @@ -343,9 +355,15 @@ parameters: path: src/References/ReferencesListener.php - - message: '#^Call to an undefined method Doctrine\\Persistence\\Mapping\\ClassMetadata\\:\:getReflectionProperty\(\)\.$#' + message: '#^Call to an undefined method Doctrine\\Persistence\\Mapping\\ClassMetadata\\:\:getFieldValue\(\)\.$#' identifier: method.notFound - count: 2 + count: 1 + path: src/Sluggable/Handler/InversedRelativeSlugHandler.php + + - + message: '#^Call to an undefined method Doctrine\\Persistence\\Mapping\\ClassMetadata\\:\:setFieldValue\(\)\.$#' + identifier: method.notFound + count: 1 path: src/Sluggable/Handler/InversedRelativeSlugHandler.php - @@ -361,9 +379,15 @@ parameters: path: src/Sluggable/Handler/RelativeSlugHandler.php - - message: '#^Call to an undefined method Doctrine\\Persistence\\Mapping\\ClassMetadata\\:\:getReflectionProperty\(\)\.$#' + message: '#^Call to an undefined method Doctrine\\Persistence\\Mapping\\ClassMetadata\\:\:getFieldValue\(\)\.$#' identifier: method.notFound - count: 2 + count: 1 + path: src/Sluggable/Handler/TreeSlugHandler.php + + - + message: '#^Call to an undefined method Doctrine\\Persistence\\Mapping\\ClassMetadata\\:\:setFieldValue\(\)\.$#' + identifier: method.notFound + count: 1 path: src/Sluggable/Handler/TreeSlugHandler.php - @@ -421,9 +445,15 @@ parameters: path: src/Sluggable/SluggableListener.php - - message: '#^Call to an undefined method Doctrine\\Persistence\\Mapping\\ClassMetadata\\:\:getReflectionProperty\(\)\.$#' + message: '#^Call to an undefined method Doctrine\\Persistence\\Mapping\\ClassMetadata\\:\:getFieldValue\(\)\.$#' identifier: method.notFound - count: 7 + count: 5 + path: src/Sluggable/SluggableListener.php + + - + message: '#^Call to an undefined method Doctrine\\Persistence\\Mapping\\ClassMetadata\\:\:setFieldValue\(\)\.$#' + identifier: method.notFound + count: 2 path: src/Sluggable/SluggableListener.php - @@ -493,9 +523,15 @@ parameters: path: src/Sortable/Mapping/Driver/Yaml.php - - message: '#^Call to an undefined method Doctrine\\Persistence\\Mapping\\ClassMetadata\\:\:getReflectionProperty\(\)\.$#' + message: '#^Call to an undefined method Doctrine\\Persistence\\Mapping\\ClassMetadata\\:\:getFieldValue\(\)\.$#' + identifier: method.notFound + count: 8 + path: src/Sortable/SortableListener.php + + - + message: '#^Call to an undefined method Doctrine\\Persistence\\Mapping\\ClassMetadata\\:\:setFieldValue\(\)\.$#' identifier: method.notFound - count: 9 + count: 1 path: src/Sortable/SortableListener.php - @@ -631,7 +667,7 @@ parameters: path: src/Translatable/Query/TreeWalker/TranslationWalker.php - - message: '#^Call to an undefined method Doctrine\\Persistence\\Mapping\\ClassMetadata\\:\:getReflectionProperty\(\)\.$#' + message: '#^Call to an undefined method Doctrine\\Persistence\\Mapping\\ClassMetadata\\:\:getFieldValue\(\)\.$#' identifier: method.notFound count: 1 path: src/Translatable/TranslatableListener.php @@ -853,15 +889,15 @@ parameters: path: src/Tree/Strategy/AbstractMaterializedPath.php - - message: '#^Call to an undefined method Doctrine\\Persistence\\Mapping\\ClassMetadata\\:\:getIdentifierValue\(\)\.$#' + message: '#^Call to an undefined method Doctrine\\Persistence\\Mapping\\ClassMetadata\\:\:getFieldValue\(\)\.$#' identifier: method.notFound - count: 1 + count: 8 path: src/Tree/Strategy/AbstractMaterializedPath.php - - message: '#^Call to an undefined method Doctrine\\Persistence\\Mapping\\ClassMetadata\\:\:getReflectionProperty\(\)\.$#' + message: '#^Call to an undefined method Doctrine\\Persistence\\Mapping\\ClassMetadata\\:\:getIdentifierValue\(\)\.$#' identifier: method.notFound - count: 10 + count: 1 path: src/Tree/Strategy/AbstractMaterializedPath.php - @@ -870,6 +906,12 @@ parameters: count: 1 path: src/Tree/Strategy/AbstractMaterializedPath.php + - + message: '#^Call to an undefined method Doctrine\\Persistence\\Mapping\\ClassMetadata\\:\:setFieldValue\(\)\.$#' + identifier: method.notFound + count: 4 + path: src/Tree/Strategy/AbstractMaterializedPath.php + - message: '#^Call to an undefined method Doctrine\\Persistence\\ObjectManager\:\:getReference\(\)\.$#' identifier: method.notFound @@ -973,7 +1015,13 @@ parameters: path: src/Uploadable/MimeType/MimeTypeGuesser.php - - message: '#^Call to an undefined method Doctrine\\Persistence\\Mapping\\ClassMetadata\\:\:getReflectionProperty\(\)\.$#' + message: '#^Call to an undefined method Doctrine\\Persistence\\Mapping\\ClassMetadata\\:\:getFieldValue\(\)\.$#' + identifier: method.notFound + count: 1 + path: src/Uploadable/UploadableListener.php + + - + message: '#^Call to an undefined method Doctrine\\Persistence\\Mapping\\ClassMetadata\\:\:setFieldValue\(\)\.$#' identifier: method.notFound count: 1 path: src/Uploadable/UploadableListener.php diff --git a/src/AbstractTrackingListener.php b/src/AbstractTrackingListener.php index a818601ffc..47293cded3 100644 --- a/src/AbstractTrackingListener.php +++ b/src/AbstractTrackingListener.php @@ -149,7 +149,7 @@ public function onFlush(EventArgs $args) } $objectMeta = $om->getClassMetadata(get_class($changingObject)); $om->initializeObject($changingObject); - $value = $objectMeta->getReflectionProperty($trackedChild)->getValue($changingObject); + $value = $objectMeta->getFieldValue($changingObject, $trackedChild); } else { $value = $changes[1]; } @@ -189,14 +189,14 @@ public function prePersist(EventArgs $args) if ($config = $this->getConfiguration($om, $meta->getName())) { if (isset($config['update'])) { foreach ($config['update'] as $field) { - if (null === $meta->getReflectionProperty($field)->getValue($object)) { // let manual values + if (null === $meta->getFieldValue($object, $field)) { // let manual values $this->updateField($object, $ea, $meta, $field); } } } if (isset($config['create'])) { foreach ($config['create'] as $field) { - if (null === $meta->getReflectionProperty($field)->getValue($object)) { // let manual values + if (null === $meta->getFieldValue($object, $field)) { // let manual values $this->updateField($object, $ea, $meta, $field); } } @@ -227,8 +227,7 @@ abstract protected function getFieldValue($meta, $field, $eventAdapter); */ protected function updateField($object, $eventAdapter, $meta, $field) { - $property = $meta->getReflectionProperty($field); - $oldValue = $property->getValue($object); + $oldValue = $meta->getFieldValue($object, $field); $newValue = $this->getFieldValue($meta, $field, $eventAdapter); // if field value is reference, persist object @@ -241,7 +240,7 @@ protected function updateField($object, $eventAdapter, $meta, $field) } } - $property->setValue($object, $newValue); + $meta->setFieldValue($object, $field, $newValue); if ($object instanceof NotifyPropertyChanged) { $uow = $eventAdapter->getObjectManager()->getUnitOfWork(); diff --git a/src/Loggable/LoggableListener.php b/src/Loggable/LoggableListener.php index 7fd66df1eb..2c7836be9d 100644 --- a/src/Loggable/LoggableListener.php +++ b/src/Loggable/LoggableListener.php @@ -173,7 +173,7 @@ public function postPersist(EventArgs $args) $logEntryMeta = $om->getClassMetadata(get_class($logEntry)); $id = $wrapped->getIdentifier(false, true); - $logEntryMeta->getReflectionProperty('objectId')->setValue($logEntry, $id); + $logEntryMeta->setFieldValue($logEntry, 'objectId', $id); $uow->scheduleExtraUpdate($logEntry, [ 'objectId' => [null, $id], ]); diff --git a/src/Loggable/Mapping/Event/Adapter/ODM.php b/src/Loggable/Mapping/Event/Adapter/ODM.php index d193949591..281ee1766c 100644 --- a/src/Loggable/Mapping/Event/Adapter/ODM.php +++ b/src/Loggable/Mapping/Event/Adapter/ODM.php @@ -43,7 +43,7 @@ public function getNewVersion($meta, $object) $dm = $this->getObjectManager(); $objectMeta = $dm->getClassMetadata(get_class($object)); $identifierField = $this->getSingleIdentifierFieldName($objectMeta); - $objectId = $objectMeta->getReflectionProperty($identifierField)->getValue($object); + $objectId = $objectMeta->getFieldValue($object, $identifierField); $qb = $dm->createQueryBuilder($meta->getName()); $qb->select('version'); diff --git a/src/Mapping/MappedEventSubscriber.php b/src/Mapping/MappedEventSubscriber.php index d5b87c5388..640e5cb984 100644 --- a/src/Mapping/MappedEventSubscriber.php +++ b/src/Mapping/MappedEventSubscriber.php @@ -307,7 +307,7 @@ protected function setFieldValue(AdapterInterface $adapter, $object, $field, $ol $meta = $manager->getClassMetadata(get_class($object)); $uow = $manager->getUnitOfWork(); - $meta->getReflectionProperty($field)->setValue($object, $newValue); + $meta->setFieldValue($object, $field, $newValue); $uow->propertyChanged($object, $field, $oldValue, $newValue); $adapter->recomputeSingleObjectChangeSet($uow, $meta, $object); } diff --git a/src/ReferenceIntegrity/ReferenceIntegrityListener.php b/src/ReferenceIntegrity/ReferenceIntegrityListener.php index c6113ee60d..f3502b04ed 100644 --- a/src/ReferenceIntegrity/ReferenceIntegrityListener.php +++ b/src/ReferenceIntegrity/ReferenceIntegrityListener.php @@ -76,8 +76,7 @@ public function preRemove(EventArgs $args) if ($config = $this->getConfiguration($om, $meta->getName())) { foreach ($config['referenceIntegrity'] as $property => $action) { - $reflProp = $meta->getReflectionProperty($property); - $refDoc = $reflProp->getValue($object); + $refDoc = $meta->getFieldValue($object, $property); $fieldMapping = $meta->getFieldMapping($property); switch ($action) { @@ -90,19 +89,19 @@ public function preRemove(EventArgs $args) $subMeta = $om->getClassMetadata($fieldMapping->targetDocument ?? $fieldMapping['targetDocument']); - if (!$subMeta->hasField($fieldMapping->mappedBy ?? $fieldMapping['mappedBy'])) { - throw new InvalidMappingException(sprintf('Unable to find reference integrity [%s] as mapped property in entity - %s', $fieldMapping->mappedBy ?? $fieldMapping['mappedBy'], $fieldMapping->targetDocument ?? $fieldMapping['targetDocument'])); - } + $mappedByField = $fieldMapping->mappedBy ?? $fieldMapping['mappedBy']; - $refReflProp = $subMeta->getReflectionProperty($fieldMapping->mappedBy ?? $fieldMapping['mappedBy']); + if (!$subMeta->hasField($mappedByField)) { + throw new InvalidMappingException(sprintf('Unable to find reference integrity [%s] as mapped property in entity - %s', $mappedByField, $fieldMapping->targetDocument ?? $fieldMapping['targetDocument'])); + } if ($meta->isCollectionValuedReference($property)) { foreach ($refDoc as $refObj) { - $refReflProp->setValue($refObj, null); + $subMeta->setFieldValue($refObj, $mappedByField, null); $om->persist($refObj); } } else { - $refReflProp->setValue($refDoc, null); + $subMeta->setFieldValue($refDoc, $mappedByField, null); $om->persist($refDoc); } @@ -116,27 +115,27 @@ public function preRemove(EventArgs $args) $subMeta = $om->getClassMetadata($fieldMapping->targetDocument ?? $fieldMapping['targetDocument']); - if (!$subMeta->hasField($fieldMapping->mappedBy ?? $fieldMapping['mappedBy'])) { - throw new InvalidMappingException(sprintf('Unable to find reference integrity [%s] as mapped property in entity - %s', $fieldMapping->mappedBy ?? $fieldMapping['mappedBy'], $fieldMapping->targetDocument ?? $fieldMapping['targetDocument'])); - } + $mappedByField = $fieldMapping->mappedBy ?? $fieldMapping['mappedBy']; - if (!$subMeta->isCollectionValuedReference($fieldMapping->mappedBy ?? $fieldMapping['mappedBy'])) { - throw new InvalidMappingException(sprintf('Reference integrity [%s] mapped property in entity - %s should be a Reference Many', $fieldMapping->mappedBy ?? $fieldMapping['mappedBy'], $fieldMapping->targetDocument ?? $fieldMapping['targetDocument'])); + if (!$subMeta->hasField($mappedByField)) { + throw new InvalidMappingException(sprintf('Unable to find reference integrity [%s] as mapped property in entity - %s', $mappedByField, $fieldMapping->targetDocument ?? $fieldMapping['targetDocument'])); } - $refReflProp = $subMeta->getReflectionProperty($fieldMapping->mappedBy ?? $fieldMapping['mappedBy']); + if (!$subMeta->isCollectionValuedReference($mappedByField)) { + throw new InvalidMappingException(sprintf('Reference integrity [%s] mapped property in entity - %s should be a Reference Many', $mappedByField, $fieldMapping->targetDocument ?? $fieldMapping['targetDocument'])); + } if ($meta->isCollectionValuedReference($property)) { foreach ($refDoc as $refObj) { - $collection = $refReflProp->getValue($refObj); + $collection = $subMeta->getFieldValue($refObj, $mappedByField); $collection->removeElement($object); - $refReflProp->setValue($refObj, $collection); + $subMeta->setFieldValue($refObj, $mappedByField, $collection); $om->persist($refObj); } } elseif (is_object($refDoc)) { - $collection = $refReflProp->getValue($refDoc); + $collection = $subMeta->getFieldValue($refDoc, $mappedByField); $collection->removeElement($object); - $refReflProp->setValue($refDoc, $collection); + $subMeta->setFieldValue($refDoc, $mappedByField, $collection); $om->persist($refDoc); } diff --git a/src/References/Mapping/Event/Adapter/ODM.php b/src/References/Mapping/Event/Adapter/ODM.php index b302171467..4b24e7ac31 100644 --- a/src/References/Mapping/Event/Adapter/ODM.php +++ b/src/References/Mapping/Event/Adapter/ODM.php @@ -38,7 +38,7 @@ public function getIdentifier($om, $object, $single = true) $meta = $om->getClassMetadata(get_class($object)); $id = []; foreach ($meta->getIdentifier() as $name) { - $id[$name] = $meta->getReflectionProperty($name)->getValue($object); + $id[$name] = $meta->getFieldValue($object, $name); // return null if one of identifiers is missing if (!$id[$name]) { return null; @@ -73,7 +73,7 @@ public function extractIdentifier($om, $object, $single = true) if ($object instanceof GhostObjectInterface) { $id = $om->getUnitOfWork()->getDocumentIdentifier($object); } else { - $id = $meta->getReflectionProperty($meta->getIdentifier()[0])->getValue($object); + $id = $meta->getFieldValue($object, $meta->getIdentifier()[0]); } if ($single || !$id) { diff --git a/src/References/Mapping/Event/Adapter/ORM.php b/src/References/Mapping/Event/Adapter/ORM.php index 1f116c122a..294fb09832 100644 --- a/src/References/Mapping/Event/Adapter/ORM.php +++ b/src/References/Mapping/Event/Adapter/ORM.php @@ -38,7 +38,7 @@ public function getIdentifier($om, $object, $single = true) if ($object instanceof GhostObjectInterface) { $id = $om->getUnitOfWork()->getDocumentIdentifier($object); } else { - $id = $meta->getReflectionProperty($meta->getIdentifier()[0])->getValue($object); + $id = $meta->getFieldValue($object, $meta->getIdentifier()[0]); } if ($single || !$id) { @@ -51,7 +51,7 @@ public function getIdentifier($om, $object, $single = true) if ($om instanceof PhpcrDocumentManager) { $meta = $om->getClassMetadata(get_class($object)); assert(1 === count($meta->getIdentifier())); - $id = $meta->getReflectionProperty($meta->getIdentifier()[0])->getValue($object); + $id = $meta->getFieldValue($object, $meta->getIdentifier()[0]); if ($single || !$id) { return $id; @@ -85,7 +85,7 @@ public function extractIdentifier($om, $object, $single = true) $meta = $om->getClassMetadata(get_class($object)); $id = []; foreach ($meta->getIdentifier() as $name) { - $id[$name] = $meta->getReflectionProperty($name)->getValue($object); + $id[$name] = $meta->getFieldValue($object, $name); // return null if one of identifiers is missing if (!$id[$name]) { return null; diff --git a/src/Sluggable/Handler/InversedRelativeSlugHandler.php b/src/Sluggable/Handler/InversedRelativeSlugHandler.php index b8ac0483bb..3eea7e29d6 100644 --- a/src/Sluggable/Handler/InversedRelativeSlugHandler.php +++ b/src/Sluggable/Handler/InversedRelativeSlugHandler.php @@ -105,10 +105,10 @@ public function onSlugCompletion(SluggableAdapter $ea, array &$config, $object, continue; } - $objectSlug = (string) $meta->getReflectionProperty($mappedByConfig['slug'])->getValue($object); + $objectSlug = (string) $meta->getFieldValue($object, $mappedByConfig['slug']); if (preg_match("@^{$oldSlug}@smi", $objectSlug)) { $objectSlug = str_replace($oldSlug, $slug, $objectSlug); - $meta->getReflectionProperty($mappedByConfig['slug'])->setValue($object, $objectSlug); + $meta->setFieldValue($object, $mappedByConfig['slug'], $objectSlug); $ea->setOriginalObjectProperty($uow, $object, $mappedByConfig['slug'], $objectSlug); } } diff --git a/src/Sluggable/Handler/TreeSlugHandler.php b/src/Sluggable/Handler/TreeSlugHandler.php index 65616da7dd..4798e7a042 100644 --- a/src/Sluggable/Handler/TreeSlugHandler.php +++ b/src/Sluggable/Handler/TreeSlugHandler.php @@ -137,10 +137,10 @@ public function onSlugCompletion(SluggableAdapter $ea, array &$config, $object, continue; } - $objectSlug = (string) $meta->getReflectionProperty($config['slug'])->getValue($object); + $objectSlug = (string) $meta->getFieldValue($object, $config['slug']); if (preg_match("@^{$target}{$config['pathSeparator']}@smi", $objectSlug)) { $objectSlug = str_replace($target, $slug, $objectSlug); - $meta->getReflectionProperty($config['slug'])->setValue($object, $objectSlug); + $meta->setFieldValue($object, $config['slug'], $objectSlug); $ea->setOriginalObjectProperty($uow, $object, $config['slug'], $objectSlug); } } diff --git a/src/Sluggable/SluggableListener.php b/src/Sluggable/SluggableListener.php index 1f0df30657..9ddd8401be 100644 --- a/src/Sluggable/SluggableListener.php +++ b/src/Sluggable/SluggableListener.php @@ -278,7 +278,7 @@ public function prePersist(EventArgs $args) if ($config = $this->getConfiguration($om, $meta->getName())) { foreach ($config['slugs'] as $slugField => $options) { if ($meta->isIdentifier($slugField)) { - $meta->getReflectionProperty($slugField)->setValue($object, uniqid('__sluggable_placeholder__')); + $meta->setFieldValue($object, $slugField, uniqid('__sluggable_placeholder__')); } } } @@ -362,7 +362,7 @@ private function generateSlug(SluggableAdapter $ea, object $object): void $hasHandlers = [] !== $options['handlers']; $options['useObjectClass'] = $config['useObjectClass']; // collect the slug from fields - $slug = $meta->getReflectionProperty($slugField)->getValue($object); + $slug = $meta->getFieldValue($object, $slugField); // if slug should not be updated, skip it if (!$options['updatable'] && !$isInsert && (!isset($changeSet[$slugField]) || 0 === strpos($slug, '__sluggable_placeholder__'))) { @@ -380,7 +380,7 @@ private function generateSlug(SluggableAdapter $ea, object $object): void if (isset($changeSet[$sluggableField]) || isset($changeSet[$slugField])) { $needToChangeSlug = true; } - $value = $meta->getReflectionProperty($sluggableField)->getValue($object); + $value = $meta->getFieldValue($object, $sluggableField); $slug .= $value instanceof \DateTimeInterface ? $value->format($options['dateFormat']) : $value; $slug .= ' '; } @@ -490,7 +490,7 @@ private function generateSlug(SluggableAdapter $ea, object $object): void } // set the final slug - $meta->getReflectionProperty($slugField)->setValue($object, $slug); + $meta->setFieldValue($object, $slugField, $slug); // recompute changeset $ea->recomputeSingleObjectChangeSet($uow, $meta, $object); // overwrite changeset (to set old value) @@ -513,16 +513,16 @@ private function makeUniqueSlug(SluggableAdapter $ea, object $object, string $pr $base = false; if ($config['unique'] && isset($config['unique_base'])) { - $base = $meta->getReflectionProperty($config['unique_base'])->getValue($object); + $base = $meta->getFieldValue($object, $config['unique_base']); } // collect similar persisted slugs during this flush if (isset($this->persisted[$class = $ea->getRootObjectClass($meta)])) { foreach ($this->persisted[$class] as $obj) { - if (false !== $base && $meta->getReflectionProperty($config['unique_base'])->getValue($obj) !== $base) { + if (false !== $base && $meta->getFieldValue($obj, $config['unique_base']) !== $base) { continue; // if unique_base field is not the same, do not take slug as similar } - $slug = $meta->getReflectionProperty($config['slug'])->getValue($obj); + $slug = $meta->getFieldValue($obj, $config['slug']); $quotedPreferredSlug = preg_quote($preferredSlug); if (preg_match("@^{$quotedPreferredSlug}.*@smi", $slug)) { $similarPersisted[] = [$config['slug'] => $slug]; diff --git a/src/SoftDeleteable/SoftDeleteableListener.php b/src/SoftDeleteable/SoftDeleteableListener.php index 133aeb1927..86db3d3e22 100644 --- a/src/SoftDeleteable/SoftDeleteableListener.php +++ b/src/SoftDeleteable/SoftDeleteableListener.php @@ -94,8 +94,7 @@ public function onFlush(EventArgs $args) $config = $this->getConfiguration($om, $meta->getName()); if (isset($config['softDeleteable']) && $config['softDeleteable']) { - $reflProp = $meta->getReflectionProperty($config['fieldName']); - $oldValue = $reflProp->getValue($object); + $oldValue = $meta->getFieldValue($object, $config['fieldName']); $date = $ea->getDateValue($meta, $config['fieldName']); if (isset($config['hardDelete']) && $config['hardDelete'] && $oldValue instanceof \DateTimeInterface && $oldValue <= $date) { @@ -114,7 +113,7 @@ public function onFlush(EventArgs $args) ); } - $reflProp->setValue($object, $date); + $meta->setFieldValue($object, $config['fieldName'], $date); $om->persist($object); $uow->propertyChanged($object, $config['fieldName'], $oldValue, $date); diff --git a/src/Sortable/Mapping/Event/Adapter/ODM.php b/src/Sortable/Mapping/Event/Adapter/ODM.php index ec9f231e31..7484058c44 100644 --- a/src/Sortable/Mapping/Event/Adapter/ODM.php +++ b/src/Sortable/Mapping/Event/Adapter/ODM.php @@ -51,7 +51,7 @@ public function getMaxPosition(array $config, $meta, $groups) $document = $qb->getQuery()->getSingleResult(); if ($document) { - return $meta->getReflectionProperty($config['position'])->getValue($document); + return $meta->getFieldValue($document, $config['position']); } return -1; diff --git a/src/Sortable/SortableListener.php b/src/Sortable/SortableListener.php index e908a50797..d56e958c25 100644 --- a/src/Sortable/SortableListener.php +++ b/src/Sortable/SortableListener.php @@ -135,7 +135,7 @@ public function onFlush(EventArgs $args) foreach ($ea->getScheduledObjectUpdates($uow) as $object) { $meta = $om->getClassMetadata(get_class($object)); if ($config = $this->getConfiguration($om, $meta->getName())) { - $position = $meta->getReflectionProperty($config['position'])->getValue($object); + $position = $meta->getFieldValue($object, $config['position']); $updateValues[$position] = [$ea, $config, $meta, $object]; } } @@ -278,12 +278,12 @@ public function postFlush(EventArgs $args) } $oid = spl_object_id($object); - $pos = $meta->getReflectionProperty($config['position'])->getValue($object); + $pos = $meta->getFieldValue($object, $config['position']); $matches = $pos >= $delta['start']; $matches = $matches && ($delta['stop'] <= 0 || $pos < $delta['stop']); $value = reset($relocation['groups']); while ($matches && ($group = key($relocation['groups']))) { - $gr = $meta->getReflectionProperty($group)->getValue($object); + $gr = $meta->getFieldValue($object, $group); if (null === $value) { $matches = null === $gr; } elseif (is_object($gr) && is_object($value) && $gr !== $value) { @@ -326,7 +326,7 @@ public function postFlush(EventArgs $args) } $updatedObjects[$oid]['newValue'] = $pos + $delta['delta']; - $meta->getReflectionProperty($config['position'])->setValue($object, $updatedObjects[$oid]['newValue']); + $meta->setFieldValue($object, $config['position'], $updatedObjects[$oid]['newValue']); } } } @@ -355,8 +355,8 @@ public function postFlush(EventArgs $args) */ protected function processInsert(SortableAdapter $ea, array $config, $meta, $object) { - $old = $meta->getReflectionProperty($config['position'])->getValue($object); - $newPosition = $meta->getReflectionProperty($config['position'])->getValue($object); + $old = $meta->getFieldValue($object, $config['position']); + $newPosition = $meta->getFieldValue($object, $config['position']); if (null === $newPosition) { $newPosition = -1; @@ -451,7 +451,7 @@ protected function processUpdate(SortableAdapter $ea, array $config, $meta, $obj if (array_key_exists($config['position'], $changeSet)) { $oldPosition = $changeSet[$config['position']][0]; } else { - $oldPosition = $meta->getReflectionProperty($config['position'])->getValue($object); + $oldPosition = $meta->getFieldValue($object, $config['position']); } $this->addRelocation($oldHash, $config['useObjectClass'], $oldGroups, $oldPosition + 1, $this->maxPositions[$oldHash] + 1, -1); $groupHasChanged = true; @@ -557,7 +557,7 @@ protected function processUpdate(SortableAdapter $ea, array $config, $meta, $obj */ protected function processDeletion(SortableAdapter $ea, array $config, $meta, $object) { - $position = $meta->getReflectionProperty($config['position'])->getValue($object); + $position = $meta->getFieldValue($object, $config['position']); // Get groups $groups = $this->getGroups($meta, $config, $object); @@ -724,7 +724,7 @@ protected function getGroups($meta, $config, $object) $groups = []; if (isset($config['groups'])) { foreach ($config['groups'] as $group) { - $groups[$group] = $meta->getReflectionProperty($group)->getValue($object); + $groups[$group] = $meta->getFieldValue($object, $group); } } diff --git a/src/Tool/Wrapper/EntityWrapper.php b/src/Tool/Wrapper/EntityWrapper.php index 443c873459..9260f3c589 100644 --- a/src/Tool/Wrapper/EntityWrapper.php +++ b/src/Tool/Wrapper/EntityWrapper.php @@ -50,13 +50,13 @@ public function getPropertyValue($property) { $this->initialize(); - return $this->meta->getReflectionProperty($property)->getValue($this->object); + return $this->meta->getFieldValue($this->object, $property); } public function setPropertyValue($property, $value) { $this->initialize(); - $this->meta->getReflectionProperty($property)->setValue($this->object, $value); + $this->meta->setFieldValue($this->object, $property, $value); return $this; } diff --git a/src/Tool/Wrapper/MongoDocumentWrapper.php b/src/Tool/Wrapper/MongoDocumentWrapper.php index 94b81e554c..e7c94dd26d 100644 --- a/src/Tool/Wrapper/MongoDocumentWrapper.php +++ b/src/Tool/Wrapper/MongoDocumentWrapper.php @@ -48,7 +48,7 @@ public function getPropertyValue($property) { $this->initialize(); - return $this->meta->getReflectionProperty($property)->getValue($this->object); + return $this->meta->getFieldValue($this->object, $property); } public function getRootObjectName() @@ -59,7 +59,7 @@ public function getRootObjectName() public function setPropertyValue($property, $value) { $this->initialize(); - $this->meta->getReflectionProperty($property)->setValue($this->object, $value); + $this->meta->setFieldValue($this->object, $property, $value); return $this; } diff --git a/src/Translatable/Document/Repository/TranslationRepository.php b/src/Translatable/Document/Repository/TranslationRepository.php index 5dd18e1016..8c3b5acf2a 100644 --- a/src/Translatable/Document/Repository/TranslationRepository.php +++ b/src/Translatable/Document/Repository/TranslationRepository.php @@ -74,7 +74,7 @@ public function translate($document, $field, $locale, $value) || $listener->getTranslatableLocale($document, $meta, $this->getDocumentManager()) === $locale ; if ($modRecordValue) { - $meta->getReflectionProperty($field)->setValue($document, $value); + $meta->setFieldValue($document, $field, $value); $this->dm->persist($document); } else { if (isset($config['translationClass'])) { @@ -83,7 +83,7 @@ public function translate($document, $field, $locale, $value) $ea = new TranslatableAdapterODM(); $class = $listener->getTranslationClass($ea, $config['useObjectClass']); } - $foreignKey = $meta->getReflectionProperty($meta->getIdentifier()[0])->getValue($document); + $foreignKey = $meta->getFieldValue($document, $meta->getIdentifier()[0]); $objectClass = $config['useObjectClass']; $transMeta = $this->dm->getClassMetadata($class); $trans = $this->findOneBy([ @@ -94,15 +94,15 @@ public function translate($document, $field, $locale, $value) ]); if (!$trans) { $trans = $transMeta->newInstance(); - $transMeta->getReflectionProperty('foreignKey')->setValue($trans, $foreignKey); - $transMeta->getReflectionProperty('objectClass')->setValue($trans, $objectClass); - $transMeta->getReflectionProperty('field')->setValue($trans, $field); - $transMeta->getReflectionProperty('locale')->setValue($trans, $locale); + $transMeta->setFieldValue($trans, 'foreignKey', $foreignKey); + $transMeta->setFieldValue($trans, 'objectClass', $objectClass); + $transMeta->setFieldValue($trans, 'field', $field); + $transMeta->setFieldValue($trans, 'locale', $locale); } $mapping = $meta->getFieldMapping($field); $type = $this->getType($mapping['type']); $transformed = $type->convertToDatabaseValue($value); - $transMeta->getReflectionProperty('content')->setValue($trans, $transformed); + $transMeta->setFieldValue($trans, 'content', $transformed); if ($this->dm->getUnitOfWork()->isInIdentityMap($document)) { $this->dm->persist($trans); } else { diff --git a/src/Translatable/Entity/Repository/TranslationRepository.php b/src/Translatable/Entity/Repository/TranslationRepository.php index e623669aa4..54c309c95c 100644 --- a/src/Translatable/Entity/Repository/TranslationRepository.php +++ b/src/Translatable/Entity/Repository/TranslationRepository.php @@ -68,7 +68,7 @@ public function translate($entity, $field, $locale, $value) } $needsPersist = true; if ($locale === $listener->getTranslatableLocale($entity, $meta, $this->getEntityManager())) { - $meta->getReflectionProperty($field)->setValue($entity, $value); + $meta->setFieldValue($entity, $field, $value); $this->getEntityManager()->persist($entity); } else { if (isset($config['translationClass'])) { @@ -77,7 +77,7 @@ public function translate($entity, $field, $locale, $value) $ea = new TranslatableAdapterORM(); $class = $listener->getTranslationClass($ea, $config['useObjectClass']); } - $foreignKey = $meta->getReflectionProperty($meta->getSingleIdentifierFieldName())->getValue($entity); + $foreignKey = $meta->getFieldValue($entity, $meta->getSingleIdentifierFieldName()); $objectClass = $config['useObjectClass']; $transMeta = $this->getEntityManager()->getClassMetadata($class); $trans = $this->findOneBy([ @@ -88,10 +88,10 @@ public function translate($entity, $field, $locale, $value) ]); if (!$trans) { $trans = $transMeta->newInstance(); - $transMeta->getReflectionProperty('foreignKey')->setValue($trans, $foreignKey); - $transMeta->getReflectionProperty('objectClass')->setValue($trans, $objectClass); - $transMeta->getReflectionProperty('field')->setValue($trans, $field); - $transMeta->getReflectionProperty('locale')->setValue($trans, $locale); + $transMeta->setFieldValue($trans, 'foreignKey', $foreignKey); + $transMeta->setFieldValue($trans, 'objectClass', $objectClass); + $transMeta->setFieldValue($trans, 'field', $field); + $transMeta->setFieldValue($trans, 'locale', $locale); } if ($listener->getDefaultLocale() != $listener->getTranslatableLocale($entity, $meta, $this->getEntityManager()) && $locale === $listener->getDefaultLocale()) { @@ -99,7 +99,7 @@ public function translate($entity, $field, $locale, $value) $needsPersist = $listener->getPersistDefaultLocaleTranslation(); } $transformed = $this->getEntityManager()->getConnection()->convertToDatabaseValue($value, $meta->getTypeOfField($field)); - $transMeta->getReflectionProperty('content')->setValue($trans, $transformed); + $transMeta->setFieldValue($trans, 'content', $transformed); if ($needsPersist) { if ($this->getEntityManager()->getUnitOfWork()->isInIdentityMap($entity)) { $this->getEntityManager()->persist($trans); diff --git a/src/Translatable/TranslatableListener.php b/src/Translatable/TranslatableListener.php index 44a04ef979..7680f1c025 100644 --- a/src/Translatable/TranslatableListener.php +++ b/src/Translatable/TranslatableListener.php @@ -551,7 +551,7 @@ public function postLoad(EventArgs $args) $om->getUnitOfWork(), $object, $field, - $meta->getReflectionProperty($field)->getValue($object) + $meta->getFieldValue($object, $field) ); } } diff --git a/src/Tree/Entity/Repository/ClosureTreeRepository.php b/src/Tree/Entity/Repository/ClosureTreeRepository.php index 41933fdfa0..9da2c49fe4 100644 --- a/src/Tree/Entity/Repository/ClosureTreeRepository.php +++ b/src/Tree/Entity/Repository/ClosureTreeRepository.php @@ -278,8 +278,8 @@ public function removeFromTree($node) try { foreach ($nodesToReparent as $nodeToReparent) { - $id = $meta->getReflectionProperty($pk)->getValue($nodeToReparent); - $meta->getReflectionProperty($config['parent'])->setValue($nodeToReparent, $parent); + $id = $meta->getFieldValue($nodeToReparent, $pk); + $meta->setFieldValue($nodeToReparent, $config['parent'], $parent); $dql = "UPDATE {$config['useObjectClass']} node"; $dql .= " SET node.{$config['parent']} = :parent"; diff --git a/src/Tree/Entity/Repository/NestedTreeRepository.php b/src/Tree/Entity/Repository/NestedTreeRepository.php index f45f499137..375f42d6a6 100644 --- a/src/Tree/Entity/Repository/NestedTreeRepository.php +++ b/src/Tree/Entity/Repository/NestedTreeRepository.php @@ -1023,10 +1023,11 @@ public function recover(/* array $options = [] */) // @phpstan-ignore-line $doRecover($child, $count, $depth); } $right = $count++; - $meta->getReflectionProperty($config['left'])->setValue($root, $left); - $meta->getReflectionProperty($config['right'])->setValue($root, $right); + + $meta->setFieldValue($root, $config['left'], $left); + $meta->setFieldValue($root, $config['right'], $right); if (isset($config['level'])) { - $meta->getReflectionProperty($config['level'])->setValue($root, $lvl); + $meta->setFieldValue($root, $config['level'], $lvl); } $em->persist($root); }; @@ -1197,10 +1198,10 @@ private function verifyTree(array &$errors, ?object $root = null): void $config = $this->listener->getConfiguration($this->getEntityManager(), $meta->getName()); $identifier = $meta->getSingleIdentifierFieldName(); - if (isset($config['root'])) { - $rootId = $meta->getReflectionProperty($config['root'])->getValue($root); + if ($root && isset($config['root'])) { + $rootId = $meta->getFieldValue($root, $config['root']); if (is_object($rootId)) { - $rootId = $meta->getReflectionProperty($identifier)->getValue($rootId); + $rootId = $meta->getFieldValue($rootId, $identifier); } } else { $rootId = null; @@ -1294,10 +1295,10 @@ private function verifyTree(array &$errors, ?object $root = null): void } foreach ($qb->getQuery()->toIterable() as $node) { - $right = $meta->getReflectionProperty($config['right'])->getValue($node); - $left = $meta->getReflectionProperty($config['left'])->getValue($node); - $id = $meta->getReflectionProperty($identifier)->getValue($node); - $parent = $meta->getReflectionProperty($config['parent'])->getValue($node); + $right = $meta->getFieldValue($node, $config['right']); + $left = $meta->getFieldValue($node, $config['left']); + $id = $meta->getFieldValue($node, $identifier); + $parent = $meta->getFieldValue($node, $config['parent']); if (!$right || !$left) { $errors[] = "node [{$id}] has invalid left or right values"; } elseif ($right == $left) { @@ -1306,9 +1307,9 @@ private function verifyTree(array &$errors, ?object $root = null): void if ($parent instanceof Proxy && !$parent->__isInitialized()) { $this->getEntityManager()->refresh($parent); } - $parentRight = $meta->getReflectionProperty($config['right'])->getValue($parent); - $parentLeft = $meta->getReflectionProperty($config['left'])->getValue($parent); - $parentId = $meta->getReflectionProperty($identifier)->getValue($parent); + $parentRight = $meta->getFieldValue($parent, $config['right']); + $parentLeft = $meta->getFieldValue($parent, $config['left']); + $parentId = $meta->getFieldValue($parent, $identifier); if ($left < $parentLeft) { $errors[] = "node [{$id}] left is less than parent`s [{$parentId}] left value"; } elseif ($right > $parentRight) { @@ -1316,8 +1317,8 @@ private function verifyTree(array &$errors, ?object $root = null): void } // check that level of node is exactly after its parent's level if (isset($config['level'])) { - $parentLevel = $meta->getReflectionProperty($config['level'])->getValue($parent); - $level = $meta->getReflectionProperty($config['level'])->getValue($node); + $parentLevel = $meta->getFieldValue($parent, $config['level']); + $level = $meta->getFieldValue($node, $config['level']); if ($level !== $parentLevel + 1) { $errors[] = "node [{$id}] should be on the level right after its parent`s [{$parentId}] level"; } @@ -1326,7 +1327,7 @@ private function verifyTree(array &$errors, ?object $root = null): void // check that level of the root node is the base level defined if (isset($config['level'])) { $baseLevel = $config['level_base'] ?? 0; - $level = $meta->getReflectionProperty($config['level'])->getValue($node); + $level = $meta->getFieldValue($node, $config['level']); if ($level !== $baseLevel) { $errors[] = "node [{$id}] should be on level {$baseLevel}, not {$level}"; } diff --git a/src/Tree/Hydrator/ORM/TreeObjectHydrator.php b/src/Tree/Hydrator/ORM/TreeObjectHydrator.php index cb16778419..c22cfd99f4 100644 --- a/src/Tree/Hydrator/ORM/TreeObjectHydrator.php +++ b/src/Tree/Hydrator/ORM/TreeObjectHydrator.php @@ -60,7 +60,7 @@ class TreeObjectHydrator extends ObjectHydrator public function setPropertyValue($object, $property, $value) { $meta = $this->getEntityManager()->getClassMetadata(get_class($object)); - $meta->getReflectionProperty($property)->setValue($object, $value); + $meta->setFieldValue($object, $property, $value); } /** @@ -298,6 +298,6 @@ protected function getPropertyValue($object, $property) { $meta = $this->getEntityManager()->getClassMetadata(get_class($object)); - return $meta->getReflectionProperty($property)->getValue($object); + return $meta->getFieldValue($object, $property); } } diff --git a/src/Tree/Strategy/AbstractMaterializedPath.php b/src/Tree/Strategy/AbstractMaterializedPath.php index f8aeba2248..8a903b26e2 100644 --- a/src/Tree/Strategy/AbstractMaterializedPath.php +++ b/src/Tree/Strategy/AbstractMaterializedPath.php @@ -118,9 +118,7 @@ public function processScheduledUpdate($om, $node, AdapterInterface $ea) if (isset($changeSet[$config['path']])) { $originalPath = $changeSet[$config['path']][0]; } else { - $pathProp = $meta->getReflectionProperty($config['path']); - $pathProp->setAccessible(true); - $originalPath = $pathProp->getValue($node); + $originalPath = $meta->getFieldValue($node, $config['path']); } $this->updateNode($om, $node, $ea); @@ -204,14 +202,8 @@ public function updateNode(ObjectManager $om, $node, AdapterInterface $ea) $meta = $om->getClassMetadata(get_class($node)); $config = $this->listener->getConfiguration($om, $meta->getName()); $uow = $om->getUnitOfWork(); - $parentProp = $meta->getReflectionProperty($config['parent']); - $parentProp->setAccessible(true); - $parent = $parentProp->getValue($node); - $pathProp = $meta->getReflectionProperty($config['path']); - $pathProp->setAccessible(true); - $pathSourceProp = $meta->getReflectionProperty($config['path_source']); - $pathSourceProp->setAccessible(true); - $path = (string) $pathSourceProp->getValue($node); + $parent = $meta->getFieldValue($node, $config['parent']); + $path = (string) $meta->getFieldValue($node, $config['path_source']); // We need to avoid the presence of the path separator in the path source if (false !== strpos($path, $config['path_separator'])) { @@ -229,9 +221,7 @@ public function updateNode(ObjectManager $om, $node, AdapterInterface $ea) if (method_exists($meta, 'getIdentifierValue')) { $identifier = $meta->getIdentifierValue($node); } else { - $identifierProp = $meta->getReflectionProperty($meta->getSingleIdentifierFieldName()); - $identifierProp->setAccessible(true); - $identifier = $identifierProp->getValue($node); + $identifier = $meta->getFieldValue($node, $meta->getSingleIdentifierFieldName()); } $path .= '-'.$identifier; @@ -244,18 +234,18 @@ public function updateNode(ObjectManager $om, $node, AdapterInterface $ea) $changeSet = $uow->isScheduledForUpdate($parent) ? $ea->getObjectChangeSet($uow, $parent) : false; $pathOrPathSourceHasChanged = $changeSet && (isset($changeSet[$config['path_source']]) || isset($changeSet[$config['path']])); - if ($pathOrPathSourceHasChanged || !$pathProp->getValue($parent)) { + if ($pathOrPathSourceHasChanged || !$meta->getFieldValue($node, $config['path'])) { $this->updateNode($om, $parent, $ea); } - $parentPath = $pathProp->getValue($parent); + $parentPath = $meta->getFieldValue($parent, $config['path']); // if parent path not ends with separator if ($parentPath[strlen($parentPath) - 1] !== $config['path_separator']) { // add separator - $path = $pathProp->getValue($parent).$config['path_separator'].$path; + $path = $parentPath.$config['path_separator'].$path; } else { // don't add separator - $path = $pathProp->getValue($parent).$path; + $path = $parentPath.$path; } } @@ -267,7 +257,7 @@ public function updateNode(ObjectManager $om, $node, AdapterInterface $ea) $path .= $config['path_separator']; } - $pathProp->setValue($node, $path); + $meta->setFieldValue($node, $config['path'], $path); $changes = [ $config['path'] => [null, $path], ]; @@ -276,9 +266,7 @@ public function updateNode(ObjectManager $om, $node, AdapterInterface $ea) if (isset($config['path_hash'])) { $pathHash = md5($path); - $pathHashProp = $meta->getReflectionProperty($config['path_hash']); - $pathHashProp->setAccessible(true); - $pathHashProp->setValue($node, $pathHash); + $meta->setFieldValue($node, $config['path_hash'], $pathHash); $changes[$config['path_hash']] = [null, $pathHash]; } @@ -297,17 +285,13 @@ public function updateNode(ObjectManager $om, $node, AdapterInterface $ea) $root = $om->getReference($rootClass, $root); } - $rootProp = $meta->getReflectionProperty($config['root']); - $rootProp->setAccessible(true); - $rootProp->setValue($node, $root); + $meta->setFieldValue($node, $config['root'], $root); $changes[$config['root']] = [null, $root]; } if (isset($config['level'])) { $level = substr_count($path, $config['path_separator']); - $levelProp = $meta->getReflectionProperty($config['level']); - $levelProp->setAccessible(true); - $levelProp->setValue($node, $level); + $meta->setFieldValue($node, $config['level'], $level); $changes[$config['level']] = [null, $level]; } @@ -356,11 +340,9 @@ public function processPreLockingActions($om, $node, $action) $config = $this->listener->getConfiguration($om, $meta->getName()); if ($config['activate_locking']) { - $parentProp = $meta->getReflectionProperty($config['parent']); - $parentProp->setAccessible(true); $parentNode = $node; - while (($parent = $parentProp->getValue($parentNode)) !== null) { + while (($parent = $meta->getFieldValue($parentNode, $config['parent'])) !== null) { $parentNode = $parent; } @@ -372,9 +354,7 @@ public function processPreLockingActions($om, $node, $action) } // If tree is already locked, we throw an exception - $lockTimeProp = $meta->getReflectionProperty($config['lock_time']); - $lockTimeProp->setAccessible(true); - $lockTime = $lockTimeProp->getValue($parentNode); + $lockTime = $meta->getFieldValue($parentNode, $config['lock_time']); if (null !== $lockTime) { $lockTime = $lockTime instanceof UTCDateTime ? $lockTime->toDateTime()->getTimestamp() : $lockTime->getTimestamp(); diff --git a/src/Tree/Strategy/ODM/MongoDB/MaterializedPath.php b/src/Tree/Strategy/ODM/MongoDB/MaterializedPath.php index 1a5814c2e8..9e54b1fb37 100644 --- a/src/Tree/Strategy/ODM/MongoDB/MaterializedPath.php +++ b/src/Tree/Strategy/ODM/MongoDB/MaterializedPath.php @@ -71,10 +71,8 @@ protected function lockTrees(ObjectManager $om, AdapterInterface $ea) foreach ($this->rootsOfTreesWhichNeedsLocking as $root) { $meta = $om->getClassMetadata(get_class($root)); $config = $this->listener->getConfiguration($om, $meta->getName()); - $lockTimeProp = $meta->getReflectionProperty($config['lock_time']); - $lockTimeProp->setAccessible(true); $lockTimeValue = new UTCDateTime(); - $lockTimeProp->setValue($root, $lockTimeValue); + $meta->setFieldValue($root, $config['lock_time'], $lockTimeValue); $ea->recomputeSingleObjectChangeSet($uow, $meta, $root); } @@ -90,10 +88,8 @@ protected function releaseTreeLocks(ObjectManager $om, AdapterInterface $ea) foreach ($this->rootsOfTreesWhichNeedsLocking as $oid => $root) { $meta = $om->getClassMetadata(get_class($root)); $config = $this->listener->getConfiguration($om, $meta->getName()); - $lockTimeProp = $meta->getReflectionProperty($config['lock_time']); - $lockTimeProp->setAccessible(true); $lockTimeValue = null; - $lockTimeProp->setValue($root, $lockTimeValue); + $meta->setFieldValue($root, $config['lock_time'], $lockTimeValue); $ea->recomputeSingleObjectChangeSet($uow, $meta, $root); diff --git a/src/Tree/Strategy/ORM/Closure.php b/src/Tree/Strategy/ORM/Closure.php index ec2d98720a..c17c8202b1 100644 --- a/src/Tree/Strategy/ORM/Closure.php +++ b/src/Tree/Strategy/ORM/Closure.php @@ -312,8 +312,8 @@ public function processPostPersist($em, $entity, AdapterInterface $ea) $config = $this->listener->getConfiguration($em, $meta->getName()); $identifier = $meta->getSingleIdentifierFieldName(); - $nodeId = $meta->getReflectionProperty($identifier)->getValue($node); - $parent = $meta->getReflectionProperty($config['parent'])->getValue($node); + $nodeId = $meta->getFieldValue($node, $identifier); + $parent = $meta->getFieldValue($node, $config['parent']); $closureClass = $config['closure']; $closureMeta = $em->getClassMetadata($closureClass); @@ -366,8 +366,7 @@ public function processPostPersist($em, $entity, AdapterInterface $ea) } elseif (isset($config['level'])) { $uow->scheduleExtraUpdate($node, [$config['level'] => [null, 1]]); $ea->setOriginalObjectProperty($uow, $node, $config['level'], 1); - $levelProp = $meta->getReflectionProperty($config['level']); - $levelProp->setValue($node, 1); + $meta->setFieldValue($node, $config['level'], 1); } foreach ($entries as $closure) { @@ -569,14 +568,13 @@ protected function setLevelFieldOnPendingNodes(ObjectManager $em) foreach ($this->pendingNodesLevelProcess as $nodeId => $node) { // Update new level $level = $levels[$nodeId]; - $levelProp = $meta->getReflectionProperty($config['level']); $uow->scheduleExtraUpdate( $node, [$config['level'] => [ - $levelProp->getValue($node), $level, + $meta->getFieldValue($node, $config['level']), $level, ]] ); - $levelProp->setValue($node, $level); + $meta->setFieldValue($node, $config['level'], $level); $uow->setOriginalEntityProperty(spl_object_id($node), $config['level'], $level); } diff --git a/src/Tree/Strategy/ORM/Nested.php b/src/Tree/Strategy/ORM/Nested.php index b43e3261fa..bb491886d6 100644 --- a/src/Tree/Strategy/ORM/Nested.php +++ b/src/Tree/Strategy/ORM/Nested.php @@ -128,15 +128,15 @@ public function processScheduledInsertion($em, $node, AdapterInterface $ea) $meta = $em->getClassMetadata(get_class($node)); $config = $this->listener->getConfiguration($em, $meta->getName()); - $meta->getReflectionProperty($config['left'])->setValue($node, 0); - $meta->getReflectionProperty($config['right'])->setValue($node, 0); + $meta->setFieldValue($node, $config['left'], 0); + $meta->setFieldValue($node, $config['right'], 0); if (isset($config['level'])) { - $meta->getReflectionProperty($config['level'])->setValue($node, 0); + $meta->setFieldValue($node, $config['level'], 0); } if (isset($config['root']) && !$meta->hasAssociation($config['root']) && !isset($config['rootIdentifierMethod'])) { - $meta->getReflectionProperty($config['root'])->setValue($node, 0); - } elseif (isset($config['rootIdentifierMethod']) && null === $meta->getReflectionProperty($config['root'])->getValue($node)) { - $meta->getReflectionProperty($config['root'])->setValue($node, 0); + $meta->setFieldValue($node, $config['root'], 0); + } elseif (isset($config['rootIdentifierMethod']) && null === $meta->getFieldValue($node, $config['root'])) { + $meta->setFieldValue($node, $config['root'], 0); } } @@ -189,7 +189,7 @@ public function processPostPersist($em, $node, AdapterInterface $ea) $meta = $em->getClassMetadata(get_class($node)); $config = $this->listener->getConfiguration($em, $meta->getName()); - $parent = $meta->getReflectionProperty($config['parent'])->getValue($node); + $parent = $meta->getFieldValue($node, $config['parent']); $this->updateNode($em, $node, $parent, self::LAST_CHILD); } @@ -640,15 +640,15 @@ public function shiftRL(EntityManagerInterface $em, $class, $first, $delta, $roo } $oid = spl_object_id($node); - $left = $meta->getReflectionProperty($config['left'])->getValue($node); - $currentRoot = isset($config['root']) ? $meta->getReflectionProperty($config['root'])->getValue($node) : null; + $left = $meta->getFieldValue($node, $config['left']); + $currentRoot = isset($config['root']) ? $meta->getFieldValue($node, $config['root']) : null; if ($currentRoot === $root && $left >= $first) { - $meta->getReflectionProperty($config['left'])->setValue($node, $left + $delta); + $meta->setFieldValue($node, $config['left'], $left + $delta); $em->getUnitOfWork()->setOriginalEntityProperty($oid, $config['left'], $left + $delta); } - $right = $meta->getReflectionProperty($config['right'])->getValue($node); + $right = $meta->getFieldValue($node, $config['right']); if ($currentRoot === $root && $right >= $first) { - $meta->getReflectionProperty($config['right'])->setValue($node, $right + $delta); + $meta->setFieldValue($node, $config['right'], $right + $delta); $em->getUnitOfWork()->setOriginalEntityProperty($oid, $config['right'], $right + $delta); } } @@ -739,24 +739,24 @@ public function shiftRangeRL(EntityManagerInterface $em, $class, $first, $last, } } - $left = $meta->getReflectionProperty($config['left'])->getValue($node); - $right = $meta->getReflectionProperty($config['right'])->getValue($node); - $currentRoot = isset($config['root']) ? $meta->getReflectionProperty($config['root'])->getValue($node) : null; + $left = $meta->getFieldValue($node, $config['left']); + $right = $meta->getFieldValue($node, $config['right']); + $currentRoot = isset($config['root']) ? $meta->getFieldValue($node, $config['root']) : null; if ($currentRoot === $root && $left >= $first && $right <= $last) { $oid = spl_object_id($node); $uow = $em->getUnitOfWork(); - $meta->getReflectionProperty($config['left'])->setValue($node, $left + $delta); + $meta->setFieldValue($node, $config['left'], $left + $delta); $uow->setOriginalEntityProperty($oid, $config['left'], $left + $delta); - $meta->getReflectionProperty($config['right'])->setValue($node, $right + $delta); + $meta->setFieldValue($node, $config['right'], $right + $delta); $uow->setOriginalEntityProperty($oid, $config['right'], $right + $delta); if (isset($config['root'])) { - $meta->getReflectionProperty($config['root'])->setValue($node, $destRoot); + $meta->setFieldValue($node, $config['root'], $destRoot); $uow->setOriginalEntityProperty($oid, $config['root'], $destRoot); } if (isset($config['level'])) { - $level = $meta->getReflectionProperty($config['level'])->getValue($node); - $meta->getReflectionProperty($config['level'])->setValue($node, $level + $levelDelta); + $level = $meta->getFieldValue($node, $config['level']); + $meta->setFieldValue($node, $config['level'], $level + $levelDelta); $uow->setOriginalEntityProperty($oid, $config['level'], $level + $levelDelta); } } diff --git a/src/Uploadable/UploadableListener.php b/src/Uploadable/UploadableListener.php index 7dfa8cacea..765fd2dae9 100644 --- a/src/Uploadable/UploadableListener.php +++ b/src/Uploadable/UploadableListener.php @@ -791,9 +791,8 @@ protected function getNamespace() */ protected function updateField($object, $uow, AdapterInterface $ea, ClassMetadata $meta, $field, $value, $notifyPropertyChanged = true) { - $property = $meta->getReflectionProperty($field); - $oldValue = $property->getValue($object); - $property->setValue($object, $value); + $oldValue = $meta->getFieldValue($object, $field); + $meta->setFieldValue($object, $field, $value); if ($notifyPropertyChanged && $object instanceof NotifyPropertyChanged) { $uow = $ea->getObjectManager()->getUnitOfWork(); diff --git a/tests/Gedmo/Sluggable/Fixture/Embeddable/Address.php b/tests/Gedmo/Sluggable/Fixture/Embeddable/Address.php new file mode 100644 index 0000000000..2c6a9593af --- /dev/null +++ b/tests/Gedmo/Sluggable/Fixture/Embeddable/Address.php @@ -0,0 +1,86 @@ + http://www.gediminasm.org + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Gedmo\Tests\Sluggable\Fixture\Embeddable; + +use Doctrine\DBAL\Types\Types; +use Doctrine\ORM\Mapping as ORM; + +/** + * @ORM\Embeddable + */ +#[ORM\Embeddable] +class Address +{ + /** + * @ORM\Column(name="street", type="string", length=64) + */ + #[ORM\Column(name: 'street', type: Types::STRING, length: 64)] + private ?string $street = null; + + /** + * @ORM\Column(name="postalCode", type="string", length=64) + */ + #[ORM\Column(name: 'postalCode', type: Types::STRING, length: 64)] + private ?string $postalCode = null; + + /** + * @ORM\Column(name="city", type="string", length=64) + */ + #[ORM\Column(name: 'city', type: Types::STRING, length: 64)] + private ?string $city = null; + + /** + * @ORM\Column(name="country", type="string", length=64) + */ + #[ORM\Column(name: 'country', type: Types::STRING, length: 64)] + private ?string $country = null; + + public function getStreet(): ?string + { + return $this->street; + } + + public function setStreet(?string $street): void + { + $this->street = $street; + } + + public function getPostalCode(): ?string + { + return $this->postalCode; + } + + public function setPostalCode(?string $postalCode): void + { + $this->postalCode = $postalCode; + } + + public function getCity(): ?string + { + return $this->city; + } + + public function setCity(?string $city): void + { + $this->city = $city; + } + + public function getCountry(): ?string + { + return $this->country; + } + + public function setCountry(?string $country): void + { + $this->country = $country; + } +} diff --git a/tests/Gedmo/Sluggable/Fixture/Embeddable/User.php b/tests/Gedmo/Sluggable/Fixture/Embeddable/User.php new file mode 100644 index 0000000000..69740363ec --- /dev/null +++ b/tests/Gedmo/Sluggable/Fixture/Embeddable/User.php @@ -0,0 +1,96 @@ + http://www.gediminasm.org + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Gedmo\Tests\Sluggable\Fixture\Embeddable; + +use Doctrine\DBAL\Types\Types; +use Doctrine\ORM\Mapping as ORM; +use Doctrine\ORM\Mapping\Embedded; +use Gedmo\Mapping\Annotation as Gedmo; +use Gedmo\Sluggable\Sluggable; + +/** + * @ORM\Entity + */ +#[ORM\Entity] +class User implements Sluggable +{ + /** + * @ORM\Id + * @ORM\GeneratedValue + * @ORM\Column(type="integer") + */ + #[ORM\Id] + #[ORM\GeneratedValue] + #[ORM\Column(type: Types::INTEGER)] + private ?int $id = null; + + /** + * @ORM\Column(name="username", type="string", length=64) + */ + #[ORM\Column(name: 'username', type: Types::STRING, length: 64)] + private ?string $username = null; + + /** + * @Gedmo\Slug(separator="-", updatable=true, fields={"username", "address.city", "address.country"}) + * + * @ORM\Column(name="slug", type="string", length=64, unique=true) + */ + #[Gedmo\Slug(separator: '-', updatable: true, fields: ['username', 'address.city', 'address.country'])] + #[ORM\Column(name: 'slug', type: Types::STRING, length: 64, unique: true)] + private ?string $slug = null; + + /** + * @ORM\Embeddable(class=Address::class) + */ + #[Embedded(class: Address::class)] + private Address $address; + + public function __construct() + { + $this->address = new Address(); + } + + public function getId(): ?int + { + return $this->id; + } + + public function getUsername(): ?string + { + return $this->username; + } + + public function setUsername(?string $username): void + { + $this->username = $username; + } + + public function setSlug(?string $slug): void + { + $this->slug = $slug; + } + + public function getSlug(): ?string + { + return $this->slug; + } + + public function getAddress(): Address + { + return $this->address; + } + + public function setAddress(Address $address): void + { + $this->address = $address; + } +} diff --git a/tests/Gedmo/Sluggable/SluggableEmbeddableTest.php b/tests/Gedmo/Sluggable/SluggableEmbeddableTest.php new file mode 100644 index 0000000000..5605fb5b6f --- /dev/null +++ b/tests/Gedmo/Sluggable/SluggableEmbeddableTest.php @@ -0,0 +1,55 @@ + http://www.gediminasm.org + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Doctrine\Common\EventManager; +use Gedmo\Sluggable\SluggableListener; +use Gedmo\Tests\Sluggable\Fixture\Embeddable\Address; +use Gedmo\Tests\Sluggable\Fixture\Embeddable\User; +use Gedmo\Tests\Tool\BaseTestCaseORM; + +final class SluggableEmbeddableTest extends BaseTestCaseORM +{ + protected function setUp(): void + { + parent::setUp(); + + $evm = new EventManager(); + $evm->addEventSubscriber(new SluggableListener()); + + $this->getDefaultMockSqliteEntityManager($evm); + } + + public function testShouldHandleSlugWithEmbeddable(): void + { + $address = new Address(); + $address->setStreet('street'); + $address->setCity('city'); + $address->setPostalCode('postal code'); + $address->setCountry('country'); + + $user = new User(); + $user->setUsername('username'); + $user->setAddress($address); + + $this->em->persist($user); + $this->em->flush(); + $this->em->clear(); + + static::assertSame('username-city-country', $user->getSlug()); + } + + protected function getUsedEntityFixtures(): array + { + return [ + User::class, + ]; + } +} From 58b3989f0fa8869bfe70c6723a6ce3df3292a789 Mon Sep 17 00:00:00 2001 From: Romain Monteil Date: Sat, 20 Sep 2025 15:43:14 +0200 Subject: [PATCH 2/3] fixup! Use getFieldValue and setFieldValue methods --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6fbc55774c..9216afdfe2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,7 +21,10 @@ a release. ### Changed - Sluggable: Replaced abandoned `behat/transliterator` with `symfony/string` for default transliteration and urlization steps (#2985) -- Use `getFieldValue` and `setFieldValue` methods to support `doctrine/orm` >= 3.4 (#2966) +- Use `ClassMetadata::getFieldValue()` and `ClassMetadata::setFieldValue(` methods to support `doctrine/orm` >= 3.4 (#2966) + +### Fixed +- Sluggable: Fix type error when generating slug using embedded properties (#2965) ## [3.20.1] - 2025-09-14 ### Fixed From 51dce33a158b2341d38ff385decfe6c05d0cb48a Mon Sep 17 00:00:00 2001 From: Romain Monteil Date: Sat, 20 Sep 2025 15:46:40 +0200 Subject: [PATCH 3/3] fixup! Use getFieldValue and setFieldValue methods --- tests/Gedmo/Sluggable/Fixture/Embeddable/User.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Gedmo/Sluggable/Fixture/Embeddable/User.php b/tests/Gedmo/Sluggable/Fixture/Embeddable/User.php index 69740363ec..aa90445525 100644 --- a/tests/Gedmo/Sluggable/Fixture/Embeddable/User.php +++ b/tests/Gedmo/Sluggable/Fixture/Embeddable/User.php @@ -49,7 +49,7 @@ class User implements Sluggable private ?string $slug = null; /** - * @ORM\Embeddable(class=Address::class) + * @ORM\Embedded(class=Address::class) */ #[Embedded(class: Address::class)] private Address $address;