Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add config options to allow fields to be updated using a setter method. #2645

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
31 changes: 24 additions & 7 deletions src/AbstractTrackingListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -89,7 +90,7 @@
$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);
}
}
}
Expand All @@ -101,7 +102,7 @@
&& 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);
}
}
}
Expand Down Expand Up @@ -152,7 +153,7 @@

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);
}
}
}
Expand Down Expand Up @@ -184,14 +185,14 @@
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);
}
}
}
Expand Down Expand Up @@ -219,7 +220,7 @@
*
* @return void
*/
protected function updateField($object, $eventAdapter, $meta, $field)
protected function updateField($object, $eventAdapter, $meta, $field, array $config = [])

Check failure on line 223 in src/AbstractTrackingListener.php

View workflow job for this annotation

GitHub Actions / PHPStan

Method Gedmo\AbstractTrackingListener::updateField() has parameter $config with no value type specified in iterable type array.
fwolfsjaeger marked this conversation as resolved.
Show resolved Hide resolved
{
$property = $meta->getReflectionProperty($field);
$oldValue = $property->getValue($object);
Expand All @@ -235,7 +236,23 @@
}
}

$property->setValue($object, $newValue);
if (!empty($config['setterMethod'][$field])) {
$setterName = $config['setterMethod'][$field];

if (!method_exists($object, $setterName)) {
throw new InvalidMappingException(
sprintf(
"Setter method [%s] does not exist in class %s",
$setterName,
$meta->getName(),
),
);
}

$object->{$setterName}($newValue);
} else {
$property->setValue($object, $newValue);
}

if ($object instanceof NotifyPropertyChanged) {
$uow = $eventAdapter->getObjectManager()->getUnitOfWork();
Expand Down
2 changes: 2 additions & 0 deletions src/Blameable/Mapping/Driver/Annotation.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ public function readExtendedMetadata($meta, array &$config)
'value' => $blameable->value,
];
}
// add the setter method for the field
$this->setSetterMethod($property->getName(), $blameable->setterMethod, $config);
// properties are unique and mapper checks that, no risk here
$config[$blameable->on][] = $field;
}
Expand Down
5 changes: 4 additions & 1 deletion src/Blameable/Mapping/Driver/Xml.php
Original file line number Diff line number Diff line change
Expand Up @@ -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()}");
Expand Down
4 changes: 4 additions & 0 deletions src/Blameable/Mapping/Driver/Yaml.php
Original file line number Diff line number Diff line change
Expand Up @@ -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()}");
Expand Down
2 changes: 2 additions & 0 deletions src/IpTraceable/Mapping/Driver/Annotation.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ public function readExtendedMetadata($meta, array &$config)
'value' => $ipTraceable->value,
];
}
// add the setter method for the field
$this->setSetterMethod($property->getName(), $ipTraceable->setterMethod, $config);
// properties are unique and mapper checks that, no risk here
$config[$ipTraceable->on][] = $field;
}
Expand Down
5 changes: 4 additions & 1 deletion src/IpTraceable/Mapping/Driver/Xml.php
Original file line number Diff line number Diff line change
Expand Up @@ -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()}");
Expand Down
3 changes: 3 additions & 0 deletions src/IpTraceable/Mapping/Driver/Yaml.php
Original file line number Diff line number Diff line change
Expand Up @@ -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'])) {
Expand Down
13 changes: 11 additions & 2 deletions src/Mapping/Annotation/Blameable.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,21 @@ final class Blameable implements GedmoAnnotation
public $field;
/** @var mixed */
public $value;
/** @var string */
public $setterMethod;

/**
* @param array<string, mixed> $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 = ''
) {
if ([] !== $data) {
Deprecation::trigger(
'gedmo/doctrine-extensions',
Expand All @@ -55,12 +62,14 @@ 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;
}

$this->on = $on;
$this->field = $field;
$this->value = $value;
$this->setterMethod = $setterMethod;
}
}
13 changes: 11 additions & 2 deletions src/Mapping/Annotation/IpTraceable.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,21 @@ final class IpTraceable implements GedmoAnnotation
public $field;
/** @var mixed */
public $value;
/** @var string */
public $setterMethod;

/**
* @param array<string, mixed> $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 = ''
) {
if ([] !== $data) {
Deprecation::trigger(
'gedmo/doctrine-extensions',
Expand All @@ -56,12 +63,14 @@ 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;
}

$this->on = $on;
$this->field = $field;
$this->value = $value;
$this->setterMethod = $setterMethod;
}
}
14 changes: 12 additions & 2 deletions src/Mapping/Annotation/SoftDeleteable.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,19 @@ final class SoftDeleteable implements GedmoAnnotation

public bool $hardDelete = true;

/** @var string */
public $setterMethod;

/**
* @param array<string, mixed> $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 = ''
) {
if ([] !== $data) {
Deprecation::trigger(
'gedmo/doctrine-extensions',
Expand All @@ -53,12 +61,14 @@ 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;
}

$this->fieldName = $fieldName;
$this->timeAware = $timeAware;
$this->hardDelete = $hardDelete;
$this->setterMethod = $setterMethod;
}
}
13 changes: 11 additions & 2 deletions src/Mapping/Annotation/Timestampable.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,21 @@ final class Timestampable implements GedmoAnnotation
public $field;
/** @var mixed */
public $value;
/** @var string */
public $setterMethod;

/**
* @param array<string, mixed> $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 = ''
) {
if ([] !== $data) {
Deprecation::trigger(
'gedmo/doctrine-extensions',
Expand All @@ -55,12 +62,14 @@ 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;
}

$this->on = $on;
$this->field = $field;
$this->value = $value;
$this->setterMethod = $setterMethod;
}
}
16 changes: 16 additions & 0 deletions src/Mapping/Driver/AbstractAnnotationDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -135,4 +135,20 @@

return class_exists($className) ? $className : '';
}

/**
* Set the setter method for the given field.
*/
protected function setSetterMethod(string $field, string $method, array &$config): void

Check failure on line 142 in src/Mapping/Driver/AbstractAnnotationDriver.php

View workflow job for this annotation

GitHub Actions / PHPStan

Method Gedmo\Mapping\Driver\AbstractAnnotationDriver::setSetterMethod() has parameter $config with no value type specified in iterable type array.
{
if ('' === $method) {
return;
}

if (!isset($config['setterMethod'])) {
$config['setterMethod'] = [];
}

$config['setterMethod'][$field] = $method;
}
}
16 changes: 16 additions & 0 deletions src/Mapping/Driver/File.php
Original file line number Diff line number Diff line change
Expand Up @@ -160,4 +160,20 @@

return class_exists($className) ? $className : '';
}

/**
* Set the setter method for the given field.
*/
protected function setSetterMethod(string $field, ?string $method, array &$config): void

Check failure on line 167 in src/Mapping/Driver/File.php

View workflow job for this annotation

GitHub Actions / PHPStan

Method Gedmo\Mapping\Driver\File::setSetterMethod() has parameter $config with no value type specified in iterable type array.
{
if (empty($method)) {
return;
}

if (!isset($config['setterMethod'])) {
$config['setterMethod'] = [];
}

$config['setterMethod'][$field] = $method;
}
Comment on lines +163 to +178
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code doesn't seem to belong to File, if we don't use it in Yaml drivers, I'd move it to Xml

}
5 changes: 5 additions & 0 deletions src/SoftDeleteable/Mapping/Driver/Annotation.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@
}
$config['hardDelete'] = $annot->hardDelete;
}

// add the setter method for the field?
if (isset($annot->setterMethod)) {
$this->setSetterMethod($annot->fieldName, $annot->setterMethod, $config);

Check failure on line 64 in src/SoftDeleteable/Mapping/Driver/Annotation.php

View workflow job for this annotation

GitHub Actions / PHPStan

Access to an undefined property object::$fieldName.
}
}

$this->validateFullMetadata($meta, $config);
Expand Down
5 changes: 5 additions & 0 deletions src/SoftDeleteable/Mapping/Driver/Xml.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/SoftDeleteable/Mapping/Driver/Yaml.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading
Loading