From fede62d5afd4066d8564801a8daa2c13538b6e43 Mon Sep 17 00:00:00 2001 From: Florian Wolfsjaeger Date: Mon, 3 Jul 2023 16:46:04 +0200 Subject: [PATCH 1/7] Add config options to allow fields to be updated using a setter method. This change is applied in Blameable, IpTraceable, SoftDeleteable & Timestampable annotations. The new attribute "setterMethod" can be passed to specify the setter method to be used for a field. If no setter method is specified, the property value would be set directly as before. --- CHANGELOG.md | 3 +++ src/AbstractTrackingListener.php | 27 ++++++++++++++----- src/Blameable/Mapping/Driver/Annotation.php | 9 +++++-- src/Blameable/Mapping/Driver/Xml.php | 5 +++- src/Blameable/Mapping/Driver/Yaml.php | 4 +++ src/IpTraceable/Mapping/Driver/Annotation.php | 11 +++++--- src/IpTraceable/Mapping/Driver/Xml.php | 5 +++- src/IpTraceable/Mapping/Driver/Yaml.php | 3 +++ src/Mapping/Annotation/Blameable.php | 13 +++++++-- src/Mapping/Annotation/IpTraceable.php | 13 +++++++-- src/Mapping/Annotation/SoftDeleteable.php | 7 ++++- src/Mapping/Annotation/Timestampable.php | 13 +++++++-- .../Driver/AbstractAnnotationDriver.php | 16 +++++++++++ src/Mapping/Driver/File.php | 16 +++++++++++ .../Mapping/Driver/Annotation.php | 7 +++++ src/SoftDeleteable/Mapping/Driver/Xml.php | 5 ++++ src/SoftDeleteable/Mapping/Driver/Yaml.php | 4 +++ .../Mapping/Driver/Annotation.php | 10 ++++--- src/Timestampable/Mapping/Driver/Xml.php | 5 +++- src/Timestampable/Mapping/Driver/Yaml.php | 3 +++ 20 files changed, 154 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b4d6bd81c..7e3aee82c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -66,6 +66,9 @@ a release. - Fix bug collecting metadata for inherited mapped classes ## [3.12.0] - 2023-07-08 +### Added +- Blameable/IpTraceable/SoftDeletable/Timestampable: Added functionality to use setter method instead of setting property values directly (#2644) + ### Added - Tree: `setSibling()` and `getSibling()` methods in the `Node` interface through the BC `@method` annotation - Tree: Support array of fields and directions in the `$sortByField` and `$direction` parameters at `AbstractTreeRepository::recover()` diff --git a/src/AbstractTrackingListener.php b/src/AbstractTrackingListener.php index 481bc521cb..76a382f435 100644 --- a/src/AbstractTrackingListener.php +++ b/src/AbstractTrackingListener.php @@ -20,6 +20,7 @@ use Doctrine\Persistence\Mapping\ClassMetadata; use Doctrine\Persistence\NotifyPropertyChanged; use Doctrine\Persistence\ObjectManager; +use Gedmo\Exception\InvalidMappingException; use Gedmo\Exception\UnexpectedValueException; use Gedmo\Mapping\Event\AdapterInterface; use Gedmo\Mapping\MappedEventSubscriber; @@ -89,7 +90,7 @@ public function onFlush(EventArgs $args) $new = array_key_exists($field, $changeSet) ? $changeSet[$field][1] : false; if (null === $new) { // let manual values $needChanges = true; - $this->updateField($object, $ea, $meta, $field); + $this->updateField($object, $ea, $meta, $field, $config); } } } @@ -101,7 +102,7 @@ public function onFlush(EventArgs $args) && null === $changeSet[$field][1]; if (!isset($changeSet[$field]) || $isInsertAndNull) { // let manual values $needChanges = true; - $this->updateField($object, $ea, $meta, $field); + $this->updateField($object, $ea, $meta, $field, $config); } } } @@ -152,7 +153,7 @@ public function onFlush(EventArgs $args) if (null === $configuredValues || ($singleField && in_array($value, $configuredValues, true))) { $needChanges = true; - $this->updateField($object, $ea, $meta, $options['field']); + $this->updateField($object, $ea, $meta, $options['field'], $config); } } } @@ -184,14 +185,14 @@ public function prePersist(EventArgs $args) if (isset($config['update'])) { foreach ($config['update'] as $field) { if (null === $meta->getReflectionProperty($field)->getValue($object)) { // let manual values - $this->updateField($object, $ea, $meta, $field); + $this->updateField($object, $ea, $meta, $field, $config); } } } if (isset($config['create'])) { foreach ($config['create'] as $field) { if (null === $meta->getReflectionProperty($field)->getValue($object)) { // let manual values - $this->updateField($object, $ea, $meta, $field); + $this->updateField($object, $ea, $meta, $field, $config); } } } @@ -216,10 +217,11 @@ abstract protected function getFieldValue($meta, $field, $eventAdapter); * @param AdapterInterface $eventAdapter * @param ClassMetadata $meta * @param string $field + * @param array $config * * @return void */ - protected function updateField($object, $eventAdapter, $meta, $field) + protected function updateField($object, $eventAdapter, $meta, $field, array $config = []) { $property = $meta->getReflectionProperty($field); $oldValue = $property->getValue($object); @@ -235,7 +237,18 @@ protected function updateField($object, $eventAdapter, $meta, $field) } } - $property->setValue($object, $newValue); + if (!empty($config['setterMethod'][$field])) { + $reflectionClass = $meta->getReflectionClass(); + $setterName = $config['setterMethod'][$field]; + + if (!$reflectionClass->hasMethod($setterName)) { + throw new InvalidMappingException("Setter method - [{$setterName}] does not exist in class - {$meta->getName()}"); + } + + $reflectionClass->getMethod($setterName)->invoke($object, $newValue); + } else { + $property->setValue($object, $newValue); + } if ($object instanceof NotifyPropertyChanged) { $uow = $eventAdapter->getObjectManager()->getUnitOfWork(); diff --git a/src/Blameable/Mapping/Driver/Annotation.php b/src/Blameable/Mapping/Driver/Annotation.php index b01a086d28..34e383b784 100644 --- a/src/Blameable/Mapping/Driver/Annotation.php +++ b/src/Blameable/Mapping/Driver/Annotation.php @@ -49,13 +49,16 @@ public function readExtendedMetadata($meta, array &$config) $class = $this->getMetaReflectionClass($meta); // property annotations foreach ($class->getProperties() as $property) { - if ($meta->isMappedSuperclass && !$property->isPrivate() + if ( + isset($meta->associationMappings[$property->name]['inherited']) + || ($meta->isMappedSuperclass && !$property->isPrivate()) || $meta->isInheritedField($property->name) - || isset($meta->associationMappings[$property->name]['inherited']) ) { continue; } if ($blameable = $this->reader->getPropertyAnnotation($property, self::BLAMEABLE)) { + assert($blameable instanceof Blameable); + $field = $property->getName(); if (!$meta->hasField($field) && !$meta->hasAssociation($field)) { @@ -87,6 +90,8 @@ public function readExtendedMetadata($meta, array &$config) 'value' => $blameable->value, ]; } + // add the setter method for the field + $this->setSetterMethod($field, $blameable->setterMethod, $config); // properties are unique and mapper checks that, no risk here $config[$blameable->on][] = $field; } diff --git a/src/Blameable/Mapping/Driver/Xml.php b/src/Blameable/Mapping/Driver/Xml.php index 42861f8e17..7e730a4427 100644 --- a/src/Blameable/Mapping/Driver/Xml.php +++ b/src/Blameable/Mapping/Driver/Xml.php @@ -65,7 +65,10 @@ public function readExtendedMetadata($meta, array &$config) if (!$this->_isAttributeSet($data, 'on') || !in_array($this->_getAttribute($data, 'on'), ['update', 'create', 'change'], true)) { throw new InvalidMappingException("Field - [{$field}] trigger 'on' is not one of [update, create, change] in class - {$meta->getName()}"); } - + if ($this->_isAttributeSet($data, 'setterMethod')) { + $setterMethod = $this->_getAttribute($data, 'setterMethod'); + $this->setSetterMethod($field, $setterMethod, $config); + } if ('change' === $this->_getAttribute($data, 'on')) { if (!$this->_isAttributeSet($data, 'field')) { throw new InvalidMappingException("Missing parameters on property - {$field}, field must be set on [change] trigger in class - {$meta->getName()}"); diff --git a/src/Blameable/Mapping/Driver/Yaml.php b/src/Blameable/Mapping/Driver/Yaml.php index e72b334890..2bfc0e1f3d 100644 --- a/src/Blameable/Mapping/Driver/Yaml.php +++ b/src/Blameable/Mapping/Driver/Yaml.php @@ -63,6 +63,10 @@ public function readExtendedMetadata($meta, array &$config) throw new InvalidMappingException("Field - [{$field}] trigger 'on' is not one of [update, create, change] in class - {$meta->getName()}"); } + if (isset($mappingProperty['setterMethod'])) { + $this->setSetterMethod($field, $mappingProperty['setterMethod'], $config); + } + if ('change' === $mappingProperty['on']) { if (!isset($mappingProperty['field'])) { throw new InvalidMappingException("Missing parameters on property - {$field}, field must be set on [change] trigger in class - {$meta->getName()}"); diff --git a/src/IpTraceable/Mapping/Driver/Annotation.php b/src/IpTraceable/Mapping/Driver/Annotation.php index 8eb3efb795..1dc295438e 100644 --- a/src/IpTraceable/Mapping/Driver/Annotation.php +++ b/src/IpTraceable/Mapping/Driver/Annotation.php @@ -45,13 +45,16 @@ public function readExtendedMetadata($meta, array &$config) $class = $this->getMetaReflectionClass($meta); // property annotations foreach ($class->getProperties() as $property) { - if ($meta->isMappedSuperclass && !$property->isPrivate() - || $meta->isInheritedField($property->name) - || isset($meta->associationMappings[$property->name]['inherited']) + if ( + isset($meta->associationMappings[$property->name]['inherited']) || + ($meta->isMappedSuperclass && !$property->isPrivate()) || + $meta->isInheritedField($property->name) ) { continue; } if ($ipTraceable = $this->reader->getPropertyAnnotation($property, self::IP_TRACEABLE)) { + assert($ipTraceable instanceof IpTraceable); + $field = $property->getName(); if (!$meta->hasField($field)) { @@ -76,6 +79,8 @@ public function readExtendedMetadata($meta, array &$config) 'value' => $ipTraceable->value, ]; } + // add the setter method for the field + $this->setSetterMethod($field, $ipTraceable->setterMethod, $config); // properties are unique and mapper checks that, no risk here $config[$ipTraceable->on][] = $field; } diff --git a/src/IpTraceable/Mapping/Driver/Xml.php b/src/IpTraceable/Mapping/Driver/Xml.php index 9e64a9efd2..3cc5589e78 100644 --- a/src/IpTraceable/Mapping/Driver/Xml.php +++ b/src/IpTraceable/Mapping/Driver/Xml.php @@ -63,7 +63,10 @@ public function readExtendedMetadata($meta, array &$config) if (!$this->_isAttributeSet($data, 'on') || !in_array($this->_getAttribute($data, 'on'), ['update', 'create', 'change'], true)) { throw new InvalidMappingException("Field - [{$field}] trigger 'on' is not one of [update, create, change] in class - {$meta->getName()}"); } - + if ($this->_isAttributeSet($data, 'setterMethod')) { + $setterMethod = $this->_getAttribute($data, 'setterMethod'); + $this->setSetterMethod($field, $setterMethod, $config); + } if ('change' === $this->_getAttribute($data, 'on')) { if (!$this->_isAttributeSet($data, 'field')) { throw new InvalidMappingException("Missing parameters on property - {$field}, field must be set on [change] trigger in class - {$meta->getName()}"); diff --git a/src/IpTraceable/Mapping/Driver/Yaml.php b/src/IpTraceable/Mapping/Driver/Yaml.php index 590969ea8d..ecb6bc723b 100644 --- a/src/IpTraceable/Mapping/Driver/Yaml.php +++ b/src/IpTraceable/Mapping/Driver/Yaml.php @@ -58,6 +58,9 @@ public function readExtendedMetadata($meta, array &$config) if (!isset($mappingProperty['on']) || !in_array($mappingProperty['on'], ['update', 'create', 'change'], true)) { throw new InvalidMappingException("Field - [{$field}] trigger 'on' is not one of [update, create, change] in class - {$meta->getName()}"); } + if (isset($mappingProperty['setterMethod'])) { + $this->setSetterMethod($field, $mappingProperty['setterMethod'], $config); + } if ('change' === $mappingProperty['on']) { if (!isset($mappingProperty['field'])) { diff --git a/src/Mapping/Annotation/Blameable.php b/src/Mapping/Annotation/Blameable.php index 804adb819e..e348d3939a 100644 --- a/src/Mapping/Annotation/Blameable.php +++ b/src/Mapping/Annotation/Blameable.php @@ -34,14 +34,21 @@ final class Blameable implements GedmoAnnotation public $field; /** @var mixed */ public $value; + /** @var string|null */ + public $setterMethod; /** * @param array $data * @param string|string[]|null $field * @param mixed $value */ - public function __construct(array $data = [], string $on = 'update', $field = null, $value = null) - { + public function __construct( + array $data = [], + string $on = 'update', + $field = null, + $value = null, + string $setterMethod = null + ) { if ([] !== $data) { Deprecation::trigger( 'gedmo/doctrine-extensions', @@ -55,6 +62,7 @@ public function __construct(array $data = [], string $on = 'update', $field = nu $this->on = $this->getAttributeValue($data, 'on', $args, 1, $on); $this->field = $this->getAttributeValue($data, 'field', $args, 2, $field); $this->value = $this->getAttributeValue($data, 'value', $args, 3, $value); + $this->setterMethod = $this->getAttributeValue($data, 'setterMethod', $args, 4, $setterMethod); return; } @@ -62,5 +70,6 @@ public function __construct(array $data = [], string $on = 'update', $field = nu $this->on = $on; $this->field = $field; $this->value = $value; + $this->setterMethod = $setterMethod; } } diff --git a/src/Mapping/Annotation/IpTraceable.php b/src/Mapping/Annotation/IpTraceable.php index a438f46b21..7b4b52c7b5 100644 --- a/src/Mapping/Annotation/IpTraceable.php +++ b/src/Mapping/Annotation/IpTraceable.php @@ -35,14 +35,21 @@ final class IpTraceable implements GedmoAnnotation public $field; /** @var mixed */ public $value; + /** @var string|null */ + public $setterMethod; /** * @param array $data * @param string|string[]|null $field * @param mixed $value */ - public function __construct(array $data = [], string $on = 'update', $field = null, $value = null) - { + public function __construct( + array $data = [], + string $on = 'update', + $field = null, + $value = null, + string $setterMethod = null + ) { if ([] !== $data) { Deprecation::trigger( 'gedmo/doctrine-extensions', @@ -56,6 +63,7 @@ public function __construct(array $data = [], string $on = 'update', $field = nu $this->on = $this->getAttributeValue($data, 'on', $args, 1, $on); $this->field = $this->getAttributeValue($data, 'field', $args, 2, $field); $this->value = $this->getAttributeValue($data, 'value', $args, 3, $value); + $this->setterMethod = $this->getAttributeValue($data, 'setterMethod', $args, 4, $setterMethod); return; } @@ -63,5 +71,6 @@ public function __construct(array $data = [], string $on = 'update', $field = nu $this->on = $on; $this->field = $field; $this->value = $value; + $this->setterMethod = $setterMethod; } } diff --git a/src/Mapping/Annotation/SoftDeleteable.php b/src/Mapping/Annotation/SoftDeleteable.php index 709d9c4e7f..faef9dfdee 100644 --- a/src/Mapping/Annotation/SoftDeleteable.php +++ b/src/Mapping/Annotation/SoftDeleteable.php @@ -35,10 +35,13 @@ final class SoftDeleteable implements GedmoAnnotation public bool $hardDelete = true; + /** @var string|null */ + public $setterMethod; + /** * @param array $data */ - public function __construct(array $data = [], string $fieldName = 'deletedAt', bool $timeAware = false, bool $hardDelete = true) + public function __construct(array $data = [], string $fieldName = 'deletedAt', bool $timeAware = false, bool $hardDelete = true, string $setterMethod = null) { if ([] !== $data) { Deprecation::trigger( @@ -53,6 +56,7 @@ public function __construct(array $data = [], string $fieldName = 'deletedAt', b $this->fieldName = $this->getAttributeValue($data, 'fieldName', $args, 1, $fieldName); $this->timeAware = $this->getAttributeValue($data, 'timeAware', $args, 2, $timeAware); $this->hardDelete = $this->getAttributeValue($data, 'hardDelete', $args, 3, $hardDelete); + $this->setterMethod = $this->getAttributeValue($data, 'setterMethod', $args, 4, $setterMethod); return; } @@ -60,5 +64,6 @@ public function __construct(array $data = [], string $fieldName = 'deletedAt', b $this->fieldName = $fieldName; $this->timeAware = $timeAware; $this->hardDelete = $hardDelete; + $this->setterMethod = $setterMethod; } } diff --git a/src/Mapping/Annotation/Timestampable.php b/src/Mapping/Annotation/Timestampable.php index eceff32be7..6d468bede3 100644 --- a/src/Mapping/Annotation/Timestampable.php +++ b/src/Mapping/Annotation/Timestampable.php @@ -34,14 +34,21 @@ final class Timestampable implements GedmoAnnotation public $field; /** @var mixed */ public $value; + /** @var string|null */ + public $setterMethod; /** * @param array $data * @param string|string[] $field * @param mixed $value */ - public function __construct(array $data = [], string $on = 'update', $field = null, $value = null) - { + public function __construct( + array $data = [], + string $on = 'update', + $field = null, + $value = null, + string $setterMethod = null + ) { if ([] !== $data) { Deprecation::trigger( 'gedmo/doctrine-extensions', @@ -55,6 +62,7 @@ public function __construct(array $data = [], string $on = 'update', $field = nu $this->on = $this->getAttributeValue($data, 'on', $args, 1, $on); $this->field = $this->getAttributeValue($data, 'field', $args, 2, $field); $this->value = $this->getAttributeValue($data, 'value', $args, 3, $value); + $this->setterMethod = $this->getAttributeValue($data, 'setterMethod', $args, 4, $setterMethod); return; } @@ -62,5 +70,6 @@ public function __construct(array $data = [], string $on = 'update', $field = nu $this->on = $on; $this->field = $field; $this->value = $value; + $this->setterMethod = $setterMethod; } } diff --git a/src/Mapping/Driver/AbstractAnnotationDriver.php b/src/Mapping/Driver/AbstractAnnotationDriver.php index efd4a15e05..7de7400629 100644 --- a/src/Mapping/Driver/AbstractAnnotationDriver.php +++ b/src/Mapping/Driver/AbstractAnnotationDriver.php @@ -135,4 +135,20 @@ protected function getRelatedClassName($metadata, $name) return class_exists($className) ? $className : ''; } + + /** + * Set the setter method for the given field. + */ + protected function setSetterMethod(string $field, ?string $method, array &$config): void + { + if (empty($method)) { + return; + } + + if (!isset($config['setterMethod'])) { + $config['setterMethod'] = []; + } + + $config['setterMethod'][$field] = $method; + } } diff --git a/src/Mapping/Driver/File.php b/src/Mapping/Driver/File.php index 116bd1a8d0..12df23847e 100644 --- a/src/Mapping/Driver/File.php +++ b/src/Mapping/Driver/File.php @@ -160,4 +160,20 @@ protected function getRelatedClassName($metadata, $name) return class_exists($className) ? $className : ''; } + + /** + * Set the setter method for the given field. + */ + protected function setSetterMethod(string $field, ?string $method, array &$config): void + { + if (empty($method)) { + return; + } + + if (!isset($config['setterMethod'])) { + $config['setterMethod'] = []; + } + + $config['setterMethod'][$field] = $method; + } } diff --git a/src/SoftDeleteable/Mapping/Driver/Annotation.php b/src/SoftDeleteable/Mapping/Driver/Annotation.php index d15bd90f21..ab3333bf2f 100644 --- a/src/SoftDeleteable/Mapping/Driver/Annotation.php +++ b/src/SoftDeleteable/Mapping/Driver/Annotation.php @@ -37,6 +37,8 @@ public function readExtendedMetadata($meta, array &$config) $class = $this->getMetaReflectionClass($meta); // class annotations if (null !== $class && $annot = $this->reader->getClassAnnotation($class, self::SOFT_DELETEABLE)) { + assert($annot instanceof SoftDeleteable); + $config['softDeleteable'] = true; Validator::validateField($meta, $annot->fieldName); @@ -58,6 +60,11 @@ public function readExtendedMetadata($meta, array &$config) } $config['hardDelete'] = $annot->hardDelete; } + + // add the setter method for the field? + if (isset($annot->setterMethod)) { + $this->setSetterMethod($annot->fieldName, $annot->setterMethod, $config); + } } $this->validateFullMetadata($meta, $config); diff --git a/src/SoftDeleteable/Mapping/Driver/Xml.php b/src/SoftDeleteable/Mapping/Driver/Xml.php index 451733fd4c..9317641ad0 100644 --- a/src/SoftDeleteable/Mapping/Driver/Xml.php +++ b/src/SoftDeleteable/Mapping/Driver/Xml.php @@ -58,6 +58,11 @@ public function readExtendedMetadata($meta, array &$config) if ($this->_isAttributeSet($xml->{'soft-deleteable'}, 'hard-delete')) { $config['hardDelete'] = $this->_getBooleanAttribute($xml->{'soft-deleteable'}, 'hard-delete'); } + + if ($this->_isAttributeSet($xml, 'setterMethod')) { + $setterMethod = $this->_getAttribute($xml, 'setterMethod'); + $this->setSetterMethod($field, $setterMethod, $config); + } } } diff --git a/src/SoftDeleteable/Mapping/Driver/Yaml.php b/src/SoftDeleteable/Mapping/Driver/Yaml.php index e2790b1b66..4f2b68f38f 100644 --- a/src/SoftDeleteable/Mapping/Driver/Yaml.php +++ b/src/SoftDeleteable/Mapping/Driver/Yaml.php @@ -53,6 +53,10 @@ public function readExtendedMetadata($meta, array &$config) Validator::validateField($meta, $fieldName); + if (isset($classMapping['soft_deleteable']['setterMethod'])) { + $this->setSetterMethod($fieldName, $classMapping['soft_deleteable']['setterMethod'], $config); + } + $config['fieldName'] = $fieldName; $config['timeAware'] = false; diff --git a/src/Timestampable/Mapping/Driver/Annotation.php b/src/Timestampable/Mapping/Driver/Annotation.php index 5c68f34713..5c16054678 100644 --- a/src/Timestampable/Mapping/Driver/Annotation.php +++ b/src/Timestampable/Mapping/Driver/Annotation.php @@ -54,13 +54,15 @@ public function readExtendedMetadata($meta, array &$config) $class = $this->getMetaReflectionClass($meta); // property annotations foreach ($class->getProperties() as $property) { - if ($meta->isMappedSuperclass && !$property->isPrivate() - || $meta->isInheritedField($property->name) - || isset($meta->associationMappings[$property->name]['inherited']) + if ( + isset($meta->associationMappings[$property->name]['inherited']) || + ($meta->isMappedSuperclass && !$property->isPrivate()) || + $meta->isInheritedField($property->name) ) { continue; } if ($timestampable = $this->reader->getPropertyAnnotation($property, self::TIMESTAMPABLE)) { + assert($timestampable instanceof Timestampable); $field = $property->getName(); if (!$meta->hasField($field)) { throw new InvalidMappingException("Unable to find timestampable [{$field}] as mapped property in entity - {$meta->getName()}"); @@ -84,6 +86,8 @@ public function readExtendedMetadata($meta, array &$config) 'value' => $timestampable->value, ]; } + // add the setter method for the field + $this->setSetterMethod($field, $timestampable->setterMethod, $config); // properties are unique and mapper checks that, no risk here $config[$timestampable->on][] = $field; } diff --git a/src/Timestampable/Mapping/Driver/Xml.php b/src/Timestampable/Mapping/Driver/Xml.php index e94415ab42..40219c9aa5 100644 --- a/src/Timestampable/Mapping/Driver/Xml.php +++ b/src/Timestampable/Mapping/Driver/Xml.php @@ -72,7 +72,10 @@ public function readExtendedMetadata($meta, array &$config) if (!$this->_isAttributeSet($data, 'on') || !in_array($this->_getAttribute($data, 'on'), ['update', 'create', 'change'], true)) { throw new InvalidMappingException("Field - [{$field}] trigger 'on' is not one of [update, create, change] in class - {$meta->getName()}"); } - + if ($this->_isAttributeSet($data, 'setterMethod')) { + $setterMethod = $this->_getAttribute($data, 'setterMethod'); + $this->setSetterMethod($field, $setterMethod, $config); + } if ('change' === $this->_getAttribute($data, 'on')) { if (!$this->_isAttributeSet($data, 'field')) { throw new InvalidMappingException("Missing parameters on property - {$field}, field must be set on [change] trigger in class - {$meta->getName()}"); diff --git a/src/Timestampable/Mapping/Driver/Yaml.php b/src/Timestampable/Mapping/Driver/Yaml.php index 3c1600f734..a340456d9d 100644 --- a/src/Timestampable/Mapping/Driver/Yaml.php +++ b/src/Timestampable/Mapping/Driver/Yaml.php @@ -68,6 +68,9 @@ public function readExtendedMetadata($meta, array &$config) if (!isset($mappingProperty['on']) || !in_array($mappingProperty['on'], ['update', 'create', 'change'], true)) { throw new InvalidMappingException("Field - [{$field}] trigger 'on' is not one of [update, create, change] in class - {$meta->getName()}"); } + if (isset($mappingProperty['setterMethod'])) { + $this->setSetterMethod($field, $mappingProperty['setterMethod'], $config); + } if ('change' === $mappingProperty['on']) { if (!isset($mappingProperty['field'])) { From 53f5abdd1fae32a6ceb261c4f04598406b21d281 Mon Sep 17 00:00:00 2001 From: Florian Wolfsjaeger Date: Wed, 23 Aug 2023 08:38:05 +0200 Subject: [PATCH 2/7] Amended Coding Style --- src/AbstractTrackingListener.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/AbstractTrackingListener.php b/src/AbstractTrackingListener.php index 76a382f435..131ee02293 100644 --- a/src/AbstractTrackingListener.php +++ b/src/AbstractTrackingListener.php @@ -217,7 +217,6 @@ abstract protected function getFieldValue($meta, $field, $eventAdapter); * @param AdapterInterface $eventAdapter * @param ClassMetadata $meta * @param string $field - * @param array $config * * @return void */ From 01378aed41d4a8caee2d9601d0d6ead5ab3ac17d Mon Sep 17 00:00:00 2001 From: Florian Wolfsjaeger Date: Tue, 29 Aug 2023 10:42:25 +0200 Subject: [PATCH 3/7] Amended Coding Style --- src/Mapping/Annotation/Blameable.php | 2 +- src/Mapping/Annotation/IpTraceable.php | 2 +- src/Mapping/Annotation/SoftDeleteable.php | 2 +- src/Mapping/Annotation/Timestampable.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Mapping/Annotation/Blameable.php b/src/Mapping/Annotation/Blameable.php index e348d3939a..d02b6d1009 100644 --- a/src/Mapping/Annotation/Blameable.php +++ b/src/Mapping/Annotation/Blameable.php @@ -47,7 +47,7 @@ public function __construct( string $on = 'update', $field = null, $value = null, - string $setterMethod = null + ?string $setterMethod = null ) { if ([] !== $data) { Deprecation::trigger( diff --git a/src/Mapping/Annotation/IpTraceable.php b/src/Mapping/Annotation/IpTraceable.php index 7b4b52c7b5..aff58c69ea 100644 --- a/src/Mapping/Annotation/IpTraceable.php +++ b/src/Mapping/Annotation/IpTraceable.php @@ -48,7 +48,7 @@ public function __construct( string $on = 'update', $field = null, $value = null, - string $setterMethod = null + ?string $setterMethod = null ) { if ([] !== $data) { Deprecation::trigger( diff --git a/src/Mapping/Annotation/SoftDeleteable.php b/src/Mapping/Annotation/SoftDeleteable.php index faef9dfdee..4f1904cf4f 100644 --- a/src/Mapping/Annotation/SoftDeleteable.php +++ b/src/Mapping/Annotation/SoftDeleteable.php @@ -41,7 +41,7 @@ final class SoftDeleteable implements GedmoAnnotation /** * @param array $data */ - public function __construct(array $data = [], string $fieldName = 'deletedAt', bool $timeAware = false, bool $hardDelete = true, string $setterMethod = null) + public function __construct(array $data = [], string $fieldName = 'deletedAt', bool $timeAware = false, bool $hardDelete = true, ?string $setterMethod = null) { if ([] !== $data) { Deprecation::trigger( diff --git a/src/Mapping/Annotation/Timestampable.php b/src/Mapping/Annotation/Timestampable.php index 6d468bede3..292a9c7de3 100644 --- a/src/Mapping/Annotation/Timestampable.php +++ b/src/Mapping/Annotation/Timestampable.php @@ -47,7 +47,7 @@ public function __construct( string $on = 'update', $field = null, $value = null, - string $setterMethod = null + ?string $setterMethod = null ) { if ([] !== $data) { Deprecation::trigger( From 4f6b4e6bdc87bf3c4836f53dd377c8c9611089e6 Mon Sep 17 00:00:00 2001 From: Florian Wolfsjaeger Date: Wed, 18 Oct 2023 09:46:52 +0200 Subject: [PATCH 4/7] Ensure setterMethod is always a string --- src/Mapping/Annotation/Blameable.php | 4 ++-- src/Mapping/Annotation/IpTraceable.php | 4 ++-- src/Mapping/Annotation/SoftDeleteable.php | 11 ++++++++--- src/Mapping/Annotation/Timestampable.php | 4 ++-- src/Mapping/Driver/AbstractAnnotationDriver.php | 4 ++-- 5 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/Mapping/Annotation/Blameable.php b/src/Mapping/Annotation/Blameable.php index d02b6d1009..7ac7a31eb3 100644 --- a/src/Mapping/Annotation/Blameable.php +++ b/src/Mapping/Annotation/Blameable.php @@ -34,7 +34,7 @@ final class Blameable implements GedmoAnnotation public $field; /** @var mixed */ public $value; - /** @var string|null */ + /** @var string */ public $setterMethod; /** @@ -47,7 +47,7 @@ public function __construct( string $on = 'update', $field = null, $value = null, - ?string $setterMethod = null + string $setterMethod = '' ) { if ([] !== $data) { Deprecation::trigger( diff --git a/src/Mapping/Annotation/IpTraceable.php b/src/Mapping/Annotation/IpTraceable.php index aff58c69ea..8bea876580 100644 --- a/src/Mapping/Annotation/IpTraceable.php +++ b/src/Mapping/Annotation/IpTraceable.php @@ -35,7 +35,7 @@ final class IpTraceable implements GedmoAnnotation public $field; /** @var mixed */ public $value; - /** @var string|null */ + /** @var string */ public $setterMethod; /** @@ -48,7 +48,7 @@ public function __construct( string $on = 'update', $field = null, $value = null, - ?string $setterMethod = null + string $setterMethod = '' ) { if ([] !== $data) { Deprecation::trigger( diff --git a/src/Mapping/Annotation/SoftDeleteable.php b/src/Mapping/Annotation/SoftDeleteable.php index 4f1904cf4f..84fa8efa70 100644 --- a/src/Mapping/Annotation/SoftDeleteable.php +++ b/src/Mapping/Annotation/SoftDeleteable.php @@ -35,14 +35,19 @@ final class SoftDeleteable implements GedmoAnnotation public bool $hardDelete = true; - /** @var string|null */ + /** @var string */ public $setterMethod; /** * @param array $data */ - public function __construct(array $data = [], string $fieldName = 'deletedAt', bool $timeAware = false, bool $hardDelete = true, ?string $setterMethod = null) - { + public function __construct( + array $data = [], + string $fieldName = 'deletedAt', + bool $timeAware = false, + bool $hardDelete = true, + string $setterMethod = '' + ) { if ([] !== $data) { Deprecation::trigger( 'gedmo/doctrine-extensions', diff --git a/src/Mapping/Annotation/Timestampable.php b/src/Mapping/Annotation/Timestampable.php index 292a9c7de3..c180e4a0f5 100644 --- a/src/Mapping/Annotation/Timestampable.php +++ b/src/Mapping/Annotation/Timestampable.php @@ -34,7 +34,7 @@ final class Timestampable implements GedmoAnnotation public $field; /** @var mixed */ public $value; - /** @var string|null */ + /** @var string */ public $setterMethod; /** @@ -47,7 +47,7 @@ public function __construct( string $on = 'update', $field = null, $value = null, - ?string $setterMethod = null + string $setterMethod = '' ) { if ([] !== $data) { Deprecation::trigger( diff --git a/src/Mapping/Driver/AbstractAnnotationDriver.php b/src/Mapping/Driver/AbstractAnnotationDriver.php index 7de7400629..11e70f8070 100644 --- a/src/Mapping/Driver/AbstractAnnotationDriver.php +++ b/src/Mapping/Driver/AbstractAnnotationDriver.php @@ -139,9 +139,9 @@ protected function getRelatedClassName($metadata, $name) /** * Set the setter method for the given field. */ - protected function setSetterMethod(string $field, ?string $method, array &$config): void + protected function setSetterMethod(string $field, string $method, array &$config): void { - if (empty($method)) { + if ('' === $method) { return; } From 94b275aa111344b31121c6d552dcdb8d20414bfc Mon Sep 17 00:00:00 2001 From: Florian Wolfsjaeger Date: Fri, 1 Dec 2023 15:45:25 +0100 Subject: [PATCH 5/7] Fixed getting property name in annotation drivers Fixed using setterMethod for SoftDeleteable annotations Added Unit tests for the setter methods Amended Code Style --- src/Blameable/Mapping/Driver/Annotation.php | 2 +- src/IpTraceable/Mapping/Driver/Annotation.php | 8 +++---- src/SoftDeleteable/SoftDeleteableListener.php | 14 ++++++++++++- .../Mapping/Driver/Annotation.php | 8 +++---- tests/Gedmo/Blameable/BlameableTest.php | 1 + .../Blameable/Fixture/Entity/Comment.php | 19 +++++++++++++++++ tests/Gedmo/IpTraceable/Fixture/Comment.php | 7 ++++++- .../SoftDeleteable/Fixture/Entity/Comment.php | 2 +- .../SoftDeleteableEntityTest.php | 11 ++++++++++ tests/Gedmo/Timestampable/Fixture/Comment.php | 21 +++++++++++++++++++ .../Gedmo/Timestampable/TimestampableTest.php | 1 + 11 files changed, 82 insertions(+), 12 deletions(-) diff --git a/src/Blameable/Mapping/Driver/Annotation.php b/src/Blameable/Mapping/Driver/Annotation.php index 34e383b784..a90a226883 100644 --- a/src/Blameable/Mapping/Driver/Annotation.php +++ b/src/Blameable/Mapping/Driver/Annotation.php @@ -91,7 +91,7 @@ public function readExtendedMetadata($meta, array &$config) ]; } // add the setter method for the field - $this->setSetterMethod($field, $blameable->setterMethod, $config); + $this->setSetterMethod($property->getName(), $blameable->setterMethod, $config); // properties are unique and mapper checks that, no risk here $config[$blameable->on][] = $field; } diff --git a/src/IpTraceable/Mapping/Driver/Annotation.php b/src/IpTraceable/Mapping/Driver/Annotation.php index 1dc295438e..8c0380ccbc 100644 --- a/src/IpTraceable/Mapping/Driver/Annotation.php +++ b/src/IpTraceable/Mapping/Driver/Annotation.php @@ -46,9 +46,9 @@ public function readExtendedMetadata($meta, array &$config) // property annotations foreach ($class->getProperties() as $property) { if ( - isset($meta->associationMappings[$property->name]['inherited']) || - ($meta->isMappedSuperclass && !$property->isPrivate()) || - $meta->isInheritedField($property->name) + isset($meta->associationMappings[$property->name]['inherited']) + || ($meta->isMappedSuperclass && !$property->isPrivate()) + || $meta->isInheritedField($property->name) ) { continue; } @@ -80,7 +80,7 @@ public function readExtendedMetadata($meta, array &$config) ]; } // add the setter method for the field - $this->setSetterMethod($field, $ipTraceable->setterMethod, $config); + $this->setSetterMethod($property->getName(), $ipTraceable->setterMethod, $config); // properties are unique and mapper checks that, no risk here $config[$ipTraceable->on][] = $field; } diff --git a/src/SoftDeleteable/SoftDeleteableListener.php b/src/SoftDeleteable/SoftDeleteableListener.php index 81284c1d9e..40d2602883 100644 --- a/src/SoftDeleteable/SoftDeleteableListener.php +++ b/src/SoftDeleteable/SoftDeleteableListener.php @@ -19,6 +19,7 @@ use Doctrine\Persistence\Event\ManagerEventArgs; use Doctrine\Persistence\Mapping\ClassMetadata; use Doctrine\Persistence\ObjectManager; +use Gedmo\Exception\InvalidMappingException; use Gedmo\Mapping\MappedEventSubscriber; use Gedmo\SoftDeleteable\Event\PostSoftDeleteEventArgs; use Gedmo\SoftDeleteable\Event\PreSoftDeleteEventArgs; @@ -102,7 +103,18 @@ public function onFlush(EventArgs $args) ); } - $reflProp->setValue($object, $date); + if (!empty($config['setterMethod'][$config['fieldName']])) { + $reflectionClass = $meta->getReflectionClass(); + $setterName = $config['setterMethod'][$config['fieldName']]; + + if (!$reflectionClass->hasMethod($setterName)) { + throw new InvalidMappingException("Setter method - [{$setterName}] does not exist in class - {$meta->getName()}"); + } + + $reflectionClass->getMethod($setterName)->invoke($object, $date); + } else { + $reflProp->setValue($object, $date); + } $om->persist($object); $uow->propertyChanged($object, $config['fieldName'], $oldValue, $date); diff --git a/src/Timestampable/Mapping/Driver/Annotation.php b/src/Timestampable/Mapping/Driver/Annotation.php index 5c16054678..7f3bf0a550 100644 --- a/src/Timestampable/Mapping/Driver/Annotation.php +++ b/src/Timestampable/Mapping/Driver/Annotation.php @@ -55,9 +55,9 @@ public function readExtendedMetadata($meta, array &$config) // property annotations foreach ($class->getProperties() as $property) { if ( - isset($meta->associationMappings[$property->name]['inherited']) || - ($meta->isMappedSuperclass && !$property->isPrivate()) || - $meta->isInheritedField($property->name) + isset($meta->associationMappings[$property->name]['inherited']) + || ($meta->isMappedSuperclass && !$property->isPrivate()) + || $meta->isInheritedField($property->name) ) { continue; } @@ -87,7 +87,7 @@ public function readExtendedMetadata($meta, array &$config) ]; } // add the setter method for the field - $this->setSetterMethod($field, $timestampable->setterMethod, $config); + $this->setSetterMethod($property->getName(), $timestampable->setterMethod, $config); // properties are unique and mapper checks that, no risk here $config[$timestampable->on][] = $field; } diff --git a/tests/Gedmo/Blameable/BlameableTest.php b/tests/Gedmo/Blameable/BlameableTest.php index 4919944152..d7aee86681 100644 --- a/tests/Gedmo/Blameable/BlameableTest.php +++ b/tests/Gedmo/Blameable/BlameableTest.php @@ -68,6 +68,7 @@ public function testBlameable(): void static::assertNull($sport->getPublished()); $sportComment = $this->em->getRepository(self::COMMENT)->findOneBy(['message' => 'hello']); + static::assertSame('testuser', $sportComment->getCreated()); static::assertSame('testuser', $sportComment->getModified()); static::assertNull($sportComment->getClosed()); diff --git a/tests/Gedmo/Blameable/Fixture/Entity/Comment.php b/tests/Gedmo/Blameable/Fixture/Entity/Comment.php index 6d93430f3b..d646e77dfc 100644 --- a/tests/Gedmo/Blameable/Fixture/Entity/Comment.php +++ b/tests/Gedmo/Blameable/Fixture/Entity/Comment.php @@ -52,6 +52,15 @@ class Comment implements Blameable #[ORM\Column(type: Types::INTEGER)] private ?int $status = null; + /** + * @Gedmo\Blameable(on="create") + * + * @ORM\Column(name="created", type="string") + */ + #[ORM\Column(name: 'created', type: Types::STRING)] + #[Gedmo\Blameable(on: 'create', setterMethod: 'setCreated')] + private ?string $created = null; + /** * @var string|null * @@ -104,6 +113,16 @@ public function getMessage(): ?string return $this->message; } + public function getCreated(): ?string + { + return $this->created; + } + + public function setCreated(?string $created): void + { + $this->created = $created; + } + public function getModified(): ?string { return $this->modified; diff --git a/tests/Gedmo/IpTraceable/Fixture/Comment.php b/tests/Gedmo/IpTraceable/Fixture/Comment.php index 50c032f3ba..4a6b950b5d 100644 --- a/tests/Gedmo/IpTraceable/Fixture/Comment.php +++ b/tests/Gedmo/IpTraceable/Fixture/Comment.php @@ -71,7 +71,7 @@ class Comment implements IpTraceable * @Gedmo\IpTraceable(on="update") */ #[ORM\Column(name: 'modified', type: Types::STRING, length: 45)] - #[Gedmo\IpTraceable(on: 'update')] + #[Gedmo\IpTraceable(on: 'update', setterMethod: 'setModified')] private $modified; public function setArticle(?Article $article): void @@ -109,6 +109,11 @@ public function getModified(): ?string return $this->modified; } + public function setModified(?string $modified): void + { + $this->modified = $modified; + } + public function getClosed(): ?string { return $this->closed; diff --git a/tests/Gedmo/SoftDeleteable/Fixture/Entity/Comment.php b/tests/Gedmo/SoftDeleteable/Fixture/Entity/Comment.php index e58dcda565..ed8631ad74 100644 --- a/tests/Gedmo/SoftDeleteable/Fixture/Entity/Comment.php +++ b/tests/Gedmo/SoftDeleteable/Fixture/Entity/Comment.php @@ -21,7 +21,7 @@ * @Gedmo\SoftDeleteable(fieldName="deletedAt") */ #[ORM\Entity] -#[Gedmo\SoftDeleteable(fieldName: 'deletedAt')] +#[Gedmo\SoftDeleteable(fieldName: 'deletedAt', setterMethod: 'setDeletedAt')] class Comment { /** diff --git a/tests/Gedmo/SoftDeleteable/SoftDeleteableEntityTest.php b/tests/Gedmo/SoftDeleteable/SoftDeleteableEntityTest.php index a6aba5d40f..f926a6519c 100644 --- a/tests/Gedmo/SoftDeleteable/SoftDeleteableEntityTest.php +++ b/tests/Gedmo/SoftDeleteable/SoftDeleteableEntityTest.php @@ -434,6 +434,17 @@ public function testSoftDeleteableWithDateTimeInterface(): void static::assertInstanceOf('DateTimeInterface', $foundArt->getDeletedAt()); static::assertIsObject($foundComment); static::assertInstanceOf(self::OTHER_COMMENT_CLASS, $foundComment); + + $commentField = 'comment'; + $commentValue = 'Comment 1'; + $commentRepo = $this->em->getRepository(self::COMMENT_CLASS); + $comment = $commentRepo->findOneBy([$commentField => $commentValue]); + + $this->em->remove($comment); + $this->em->flush(); + + static::assertIsObject($comment->getDeletedAt()); + static::assertInstanceOf('DateTimeInterface', $comment->getDeletedAt()); } /** diff --git a/tests/Gedmo/Timestampable/Fixture/Comment.php b/tests/Gedmo/Timestampable/Fixture/Comment.php index 2631fd345d..efb60b8d3d 100644 --- a/tests/Gedmo/Timestampable/Fixture/Comment.php +++ b/tests/Gedmo/Timestampable/Fixture/Comment.php @@ -65,6 +65,17 @@ class Comment implements Timestampable #[Gedmo\Timestampable(on: 'change', field: 'status', value: 1)] private $closed; + /** + * @var \DateTime|null + * + * @ORM\Column(name="modified", type="time") + * + * @Gedmo\Timestampable(on="update") + */ + #[ORM\Column(name: 'created', type: Types::TIME_MUTABLE)] + #[Gedmo\Timestampable(on: 'create', setterMethod: 'setCreated')] + private $created; + /** * @var \DateTime|null * @@ -109,6 +120,16 @@ public function getMessage(): ?string return $this->message; } + public function getCreated(): ?\DateTime + { + return $this->created; + } + + public function setCreated(?\DateTime $created): void + { + $this->created = $created; + } + public function getModified(): ?\DateTime { return $this->modified; diff --git a/tests/Gedmo/Timestampable/TimestampableTest.php b/tests/Gedmo/Timestampable/TimestampableTest.php index 1307e9bea7..e165c5e5c7 100644 --- a/tests/Gedmo/Timestampable/TimestampableTest.php +++ b/tests/Gedmo/Timestampable/TimestampableTest.php @@ -124,6 +124,7 @@ public function testShouldHandleStandardBehavior(): void $sport->setAuthor($author); $sportComment = $this->em->getRepository(self::COMMENT)->findOneBy(['message' => 'hello']); + static::assertInstanceOf(\DateTime::class, $sportComment->getCreated()); static::assertNotNull($sportComment->getModified()); static::assertNull($sportComment->getClosed()); From 2a71dacad64f63970f5c301b1aebead7bf06a114 Mon Sep 17 00:00:00 2001 From: Florian Wolfsjaeger Date: Tue, 9 Jan 2024 12:08:39 +0100 Subject: [PATCH 6/7] Reverted not necessary changes --- CHANGELOG.md | 4 +--- src/Blameable/Mapping/Driver/Annotation.php | 7 ++----- src/IpTraceable/Mapping/Driver/Annotation.php | 7 ++----- src/SoftDeleteable/Mapping/Driver/Annotation.php | 2 -- src/Timestampable/Mapping/Driver/Annotation.php | 6 ++---- 5 files changed, 7 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e3aee82c3..c23b42b9cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ a release. - Sluggable: Allow ascii_string to validTypes - IpTraceable: Allow ascii_string to validTypes - Sluggable: Use `TranslationWalker` hint when looking for similar slugs (`getSimilarSlugs` method) for entities which implement `Translatable` interface and have `uniqueOverTranslations: true` Slug option (#100, #2530) +- Blameable/IpTraceable/SoftDeletable/Timestampable: Added functionality to use setter method instead of setting property values directly (#2644) ## [3.15.0] ### Added @@ -66,9 +67,6 @@ a release. - Fix bug collecting metadata for inherited mapped classes ## [3.12.0] - 2023-07-08 -### Added -- Blameable/IpTraceable/SoftDeletable/Timestampable: Added functionality to use setter method instead of setting property values directly (#2644) - ### Added - Tree: `setSibling()` and `getSibling()` methods in the `Node` interface through the BC `@method` annotation - Tree: Support array of fields and directions in the `$sortByField` and `$direction` parameters at `AbstractTreeRepository::recover()` diff --git a/src/Blameable/Mapping/Driver/Annotation.php b/src/Blameable/Mapping/Driver/Annotation.php index a90a226883..5e08a39c4e 100644 --- a/src/Blameable/Mapping/Driver/Annotation.php +++ b/src/Blameable/Mapping/Driver/Annotation.php @@ -49,16 +49,13 @@ public function readExtendedMetadata($meta, array &$config) $class = $this->getMetaReflectionClass($meta); // property annotations foreach ($class->getProperties() as $property) { - if ( - isset($meta->associationMappings[$property->name]['inherited']) - || ($meta->isMappedSuperclass && !$property->isPrivate()) + if ($meta->isMappedSuperclass && !$property->isPrivate() || $meta->isInheritedField($property->name) + || isset($meta->associationMappings[$property->name]['inherited']) ) { continue; } if ($blameable = $this->reader->getPropertyAnnotation($property, self::BLAMEABLE)) { - assert($blameable instanceof Blameable); - $field = $property->getName(); if (!$meta->hasField($field) && !$meta->hasAssociation($field)) { diff --git a/src/IpTraceable/Mapping/Driver/Annotation.php b/src/IpTraceable/Mapping/Driver/Annotation.php index 8c0380ccbc..ce5b36efd0 100644 --- a/src/IpTraceable/Mapping/Driver/Annotation.php +++ b/src/IpTraceable/Mapping/Driver/Annotation.php @@ -45,16 +45,13 @@ public function readExtendedMetadata($meta, array &$config) $class = $this->getMetaReflectionClass($meta); // property annotations foreach ($class->getProperties() as $property) { - if ( - isset($meta->associationMappings[$property->name]['inherited']) - || ($meta->isMappedSuperclass && !$property->isPrivate()) + if ($meta->isMappedSuperclass && !$property->isPrivate() || $meta->isInheritedField($property->name) + || isset($meta->associationMappings[$property->name]['inherited']) ) { continue; } if ($ipTraceable = $this->reader->getPropertyAnnotation($property, self::IP_TRACEABLE)) { - assert($ipTraceable instanceof IpTraceable); - $field = $property->getName(); if (!$meta->hasField($field)) { diff --git a/src/SoftDeleteable/Mapping/Driver/Annotation.php b/src/SoftDeleteable/Mapping/Driver/Annotation.php index ab3333bf2f..7a8fec4448 100644 --- a/src/SoftDeleteable/Mapping/Driver/Annotation.php +++ b/src/SoftDeleteable/Mapping/Driver/Annotation.php @@ -37,8 +37,6 @@ public function readExtendedMetadata($meta, array &$config) $class = $this->getMetaReflectionClass($meta); // class annotations if (null !== $class && $annot = $this->reader->getClassAnnotation($class, self::SOFT_DELETEABLE)) { - assert($annot instanceof SoftDeleteable); - $config['softDeleteable'] = true; Validator::validateField($meta, $annot->fieldName); diff --git a/src/Timestampable/Mapping/Driver/Annotation.php b/src/Timestampable/Mapping/Driver/Annotation.php index 7f3bf0a550..427fcf6940 100644 --- a/src/Timestampable/Mapping/Driver/Annotation.php +++ b/src/Timestampable/Mapping/Driver/Annotation.php @@ -54,15 +54,13 @@ public function readExtendedMetadata($meta, array &$config) $class = $this->getMetaReflectionClass($meta); // property annotations foreach ($class->getProperties() as $property) { - if ( - isset($meta->associationMappings[$property->name]['inherited']) - || ($meta->isMappedSuperclass && !$property->isPrivate()) + if ($meta->isMappedSuperclass && !$property->isPrivate() || $meta->isInheritedField($property->name) + || isset($meta->associationMappings[$property->name]['inherited']) ) { continue; } if ($timestampable = $this->reader->getPropertyAnnotation($property, self::TIMESTAMPABLE)) { - assert($timestampable instanceof Timestampable); $field = $property->getName(); if (!$meta->hasField($field)) { throw new InvalidMappingException("Unable to find timestampable [{$field}] as mapped property in entity - {$meta->getName()}"); From 4f2c498ebfe84d3a477d612c8e076e36f82d8147 Mon Sep 17 00:00:00 2001 From: Florian Wolfsjaeger Date: Fri, 1 Mar 2024 16:26:46 +0100 Subject: [PATCH 7/7] Replaced ReflectionClass usages with procedural function calls --- src/AbstractTrackingListener.php | 13 +++++++++---- src/SoftDeleteable/SoftDeleteableListener.php | 13 +++++++++---- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/AbstractTrackingListener.php b/src/AbstractTrackingListener.php index 131ee02293..cc402d0ac9 100644 --- a/src/AbstractTrackingListener.php +++ b/src/AbstractTrackingListener.php @@ -237,14 +237,19 @@ protected function updateField($object, $eventAdapter, $meta, $field, array $con } if (!empty($config['setterMethod'][$field])) { - $reflectionClass = $meta->getReflectionClass(); $setterName = $config['setterMethod'][$field]; - if (!$reflectionClass->hasMethod($setterName)) { - throw new InvalidMappingException("Setter method - [{$setterName}] does not exist in class - {$meta->getName()}"); + if (!method_exists($object, $setterName)) { + throw new InvalidMappingException( + sprintf( + "Setter method [%s] does not exist in class %s", + $setterName, + $meta->getName(), + ), + ); } - $reflectionClass->getMethod($setterName)->invoke($object, $newValue); + $object->{$setterName}($newValue); } else { $property->setValue($object, $newValue); } diff --git a/src/SoftDeleteable/SoftDeleteableListener.php b/src/SoftDeleteable/SoftDeleteableListener.php index 40d2602883..6cf1fafa54 100644 --- a/src/SoftDeleteable/SoftDeleteableListener.php +++ b/src/SoftDeleteable/SoftDeleteableListener.php @@ -104,14 +104,19 @@ public function onFlush(EventArgs $args) } if (!empty($config['setterMethod'][$config['fieldName']])) { - $reflectionClass = $meta->getReflectionClass(); $setterName = $config['setterMethod'][$config['fieldName']]; - if (!$reflectionClass->hasMethod($setterName)) { - throw new InvalidMappingException("Setter method - [{$setterName}] does not exist in class - {$meta->getName()}"); + if (!method_exists($object, $setterName)) { + throw new InvalidMappingException( + sprintf( + "Setter method [%s] does not exist in class %s", + $setterName, + $meta->getName(), + ), + ); } - $reflectionClass->getMethod($setterName)->invoke($object, $date); + $object->{$setterName}($date); } else { $reflProp->setValue($object, $date); }