diff --git a/doc/annotations.md b/doc/annotations.md index 602702aefc..588dbe5331 100644 --- a/doc/annotations.md +++ b/doc/annotations.md @@ -664,6 +664,8 @@ Optional Attributes: - **hardDelete** - Flag indicating the object supports hard deletes, defaults to `true` +- **nonDeletedColumnValue** - The value that is seen as not deleted, default: null + Examples: ```php diff --git a/doc/soft-deleteable.md b/doc/soft-deleteable.md index e5e3bf9609..f33ca171b5 100644 --- a/doc/soft-deleteable.md +++ b/doc/soft-deleteable.md @@ -283,3 +283,26 @@ assert($found !== null); // Found because deletion time is in the future By default, the soft deleteable extension allows soft deleted records to be "hard deleted" (fully removed from the database) by deleting them a second time. However, by setting the `hardDelete` parameter in the configuration to `false`, you can prevent soft deleted records from being deleted at all. + +## Setting the non-deleted value + +By default a record set to null will be seen as not (yet) soft-deleted. +This can be overwritten by setting `nonDeletedColumnValue` on the specified entity + +```php +#[ORM\Entity] +#[Gedmo\SoftDeleteable(fieldName: 'deletedAt', hardDelete: false, nonDeletedColumnValue: '1970-01-01 00:00:00')] +class Article +{ + #[ORM\Id] + #[ORM\GeneratedValue] + #[ORM\Column(type: Types::INTEGER)] + public ?int $id = null; + + #[ORM\Column(type: Types::STRING)] + public ?string $title = null; + + #[ORM\Column(type: Types::DATETIME_IMMUTABLE, nullable: true)] + public ?\DateTimeImmutable $deletedAt = null; +} +``` \ No newline at end of file diff --git a/src/Mapping/Annotation/SoftDeleteable.php b/src/Mapping/Annotation/SoftDeleteable.php index 709d9c4e7f..ff48c2d4cb 100644 --- a/src/Mapping/Annotation/SoftDeleteable.php +++ b/src/Mapping/Annotation/SoftDeleteable.php @@ -35,10 +35,12 @@ final class SoftDeleteable implements GedmoAnnotation public bool $hardDelete = true; + public ?string $nonDeletedColumnValue = null; + /** * @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 $nonDeletedColumnValue = null) { if ([] !== $data) { Deprecation::trigger( @@ -53,6 +55,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->nonDeletedColumnValue = $this->getAttributeValue($data, 'nonDeletedColumnValue', $args, 4, $nonDeletedColumnValue); return; } @@ -60,5 +63,6 @@ public function __construct(array $data = [], string $fieldName = 'deletedAt', b $this->fieldName = $fieldName; $this->timeAware = $timeAware; $this->hardDelete = $hardDelete; + $this->nonDeletedColumnValue = $nonDeletedColumnValue; } } diff --git a/src/SoftDeleteable/Filter/ODM/SoftDeleteableFilter.php b/src/SoftDeleteable/Filter/ODM/SoftDeleteableFilter.php index 12d80c0b4b..5e09fc83a6 100644 --- a/src/SoftDeleteable/Filter/ODM/SoftDeleteableFilter.php +++ b/src/SoftDeleteable/Filter/ODM/SoftDeleteableFilter.php @@ -60,18 +60,19 @@ public function addFilterCriteria(ClassMetadata $targetEntity): array } $column = $targetEntity->getFieldMapping($config['fieldName']); + $nonDeletedValue = $config['nonDeletedColumnValue'] ?? null; if (isset($config['timeAware']) && $config['timeAware']) { return [ '$or' => [ - [$column['fieldName'] => null], + [$column['fieldName'] => $nonDeletedValue], [$column['fieldName'] => ['$gt' => new \DateTime()]], ], ]; } return [ - $column['fieldName'] => null, + $column['fieldName'] => $nonDeletedValue, ]; } diff --git a/src/SoftDeleteable/Filter/SoftDeleteableFilter.php b/src/SoftDeleteable/Filter/SoftDeleteableFilter.php index 12ed75f48d..7537caf6d9 100644 --- a/src/SoftDeleteable/Filter/SoftDeleteableFilter.php +++ b/src/SoftDeleteable/Filter/SoftDeleteableFilter.php @@ -70,7 +70,8 @@ public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAli $column = $quoteStrategy->getColumnName($config['fieldName'], $targetEntity, $platform); - $addCondSql = $targetTableAlias.'.'.$column.' IS NULL'; + $nonDeletedSql = isset($config['nonDeletedColumnValue']) ? '= "'.$config['nonDeletedColumnValue'].'"': 'IS NULL'; + $addCondSql = $targetTableAlias.'.'.$column.' '.$nonDeletedSql; if (isset($config['timeAware']) && $config['timeAware']) { $addCondSql = "({$addCondSql} OR {$targetTableAlias}.{$column} > {$platform->getCurrentTimestampSQL()})"; } diff --git a/src/SoftDeleteable/Mapping/Driver/Attribute.php b/src/SoftDeleteable/Mapping/Driver/Attribute.php index 8358f1b35b..e64c4674f5 100644 --- a/src/SoftDeleteable/Mapping/Driver/Attribute.php +++ b/src/SoftDeleteable/Mapping/Driver/Attribute.php @@ -62,6 +62,14 @@ public function readExtendedMetadata($meta, array &$config) $config['hardDelete'] = $annot->hardDelete; } + + if (isset($annot->nonDeletedColumnValue)) { + if (!is_string($annot->nonDeletedColumnValue)) { + throw new InvalidMappingException('nonDeletedColumnValue must be string. '.gettype($annot->nonDeletedColumnValue).' provided.'); + } + + $config['nonDeletedColumnValue'] = $annot->nonDeletedColumnValue; + } } $this->validateFullMetadata($meta, $config); diff --git a/src/SoftDeleteable/Mapping/Driver/Xml.php b/src/SoftDeleteable/Mapping/Driver/Xml.php index 451733fd4c..d8ceefc284 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'); } + + $config['nonDeletedColumnValue'] = null; + if ($this->_isAttributeSet($xml->{'soft-deleteable'}, 'non-deleted-column-value')) { + $config['nonDeletedColumnValue'] = $this->_getAttribute($xml->{'soft-deleteable'}, 'non-deleted-column-value'); + } } } diff --git a/src/SoftDeleteable/Mapping/Driver/Yaml.php b/src/SoftDeleteable/Mapping/Driver/Yaml.php index e2790b1b66..41b142b53f 100644 --- a/src/SoftDeleteable/Mapping/Driver/Yaml.php +++ b/src/SoftDeleteable/Mapping/Driver/Yaml.php @@ -70,6 +70,14 @@ public function readExtendedMetadata($meta, array &$config) } $config['hardDelete'] = $classMapping['soft_deleteable']['hard_delete']; } + + $config['nonDeletedColumnValue'] = null; + if (isset($classMapping['soft_deleteable']['non_deleted_column_value'])) { + if (!is_string($classMapping['soft_deleteable']['non_deleted_column_value'])) { + throw new InvalidMappingException('nonDeletedColumnValue must be string. '.gettype($classMapping['soft_deleteable']['non_deleted_column_value']).' provided.'); + } + $config['nonDeletedColumnValue'] = $classMapping['soft_deleteable']['non_deleted_column_value']; + } } } diff --git a/tests/Gedmo/Mapping/Driver/Xml/Gedmo.Tests.Mapping.Fixture.Xml.SoftDeleteableNonDeletedColumnValue.dcm.xml b/tests/Gedmo/Mapping/Driver/Xml/Gedmo.Tests.Mapping.Fixture.Xml.SoftDeleteableNonDeletedColumnValue.dcm.xml new file mode 100644 index 0000000000..73b5a7ab45 --- /dev/null +++ b/tests/Gedmo/Mapping/Driver/Xml/Gedmo.Tests.Mapping.Fixture.Xml.SoftDeleteableNonDeletedColumnValue.dcm.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/tests/Gedmo/Mapping/Driver/Yaml/Gedmo.Tests.Mapping.Fixture.Yaml.SoftDeleteableNonDeletedColumnValue.dcm.yml b/tests/Gedmo/Mapping/Driver/Yaml/Gedmo.Tests.Mapping.Fixture.Yaml.SoftDeleteableNonDeletedColumnValue.dcm.yml new file mode 100644 index 0000000000..c6089e958b --- /dev/null +++ b/tests/Gedmo/Mapping/Driver/Yaml/Gedmo.Tests.Mapping.Fixture.Yaml.SoftDeleteableNonDeletedColumnValue.dcm.yml @@ -0,0 +1,18 @@ +--- +Gedmo\Tests\Mapping\Fixture\Yaml\SoftDeleteableNonDeletedColumnValue: + type: entity + table: soft_deleteables + gedmo: + soft_deleteable: + field_name: deletedAt + hard_delete: false + non_deleted_column_value: '1970-01-01 00:00:00' + id: + id: + type: integer + generator: + strategy: AUTO + fields: + deletedAt: + type: datetime + nullable: true diff --git a/tests/Gedmo/Mapping/Fixture/SoftDeleteableNonDeletedColumnValue.php b/tests/Gedmo/Mapping/Fixture/SoftDeleteableNonDeletedColumnValue.php new file mode 100644 index 0000000000..e5102322e2 --- /dev/null +++ b/tests/Gedmo/Mapping/Fixture/SoftDeleteableNonDeletedColumnValue.php @@ -0,0 +1,85 @@ + 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\Mapping\Fixture; + +use Doctrine\DBAL\Types\Types; +use Doctrine\ORM\Mapping as ORM; +use Gedmo\Mapping\Annotation as Gedmo; + +/** + * @ORM\Entity + * + * @Gedmo\SoftDeleteable(fieldName="deletedAt", hardDelete: false, nonDeletedColumnValue: '1970-01-01 00:00:00') + */ +#[ORM\Entity] +#[Gedmo\SoftDeleteable(fieldName: 'deletedAt', hardDelete: false, nonDeletedColumnValue: '1970-01-01 00:00:00')] +class SoftDeleteableNonDeletedColumnValue +{ + /** + * @var int|null + * + * @ORM\Id + * @ORM\GeneratedValue + * @ORM\Column(type="integer") + */ + #[ORM\Id] + #[ORM\GeneratedValue] + #[ORM\Column(type: Types::INTEGER)] + private $id; + + private ?string $title = null; + + private ?string $code = null; + + /** + * @var string|null + */ + private $slug; + + /** + * @var \DateTime|null + * + * @ORM\Column(name="deleted_at", type="datetime", nullable=true) + */ + #[ORM\Column(name: 'deleted_at', type: Types::DATETIME_MUTABLE, nullable: true)] + private $deletedAt; + + public function getId(): ?int + { + return $this->id; + } + + public function setTitle(?string $title): void + { + $this->title = $title; + } + + public function getTitle(): ?string + { + return $this->title; + } + + public function setCode(?string $code): void + { + $this->code = $code; + } + + public function getCode(): ?string + { + return $this->code; + } + + public function getSlug(): ?string + { + return $this->slug; + } +} diff --git a/tests/Gedmo/Mapping/Fixture/Xml/SoftDeleteableNonDeletedColumnValue.php b/tests/Gedmo/Mapping/Fixture/Xml/SoftDeleteableNonDeletedColumnValue.php new file mode 100644 index 0000000000..86fbc6c8fb --- /dev/null +++ b/tests/Gedmo/Mapping/Fixture/Xml/SoftDeleteableNonDeletedColumnValue.php @@ -0,0 +1,25 @@ + 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\Mapping\Fixture\Xml; + +class SoftDeleteableNonDeletedColumnValue +{ + /** + * @var int + */ + private $id; + + /** + * @var \DateTime|null + */ + private $deletedAt; +} diff --git a/tests/Gedmo/Mapping/Fixture/Yaml/SoftDeleteableNonDeletedColumnValue.php b/tests/Gedmo/Mapping/Fixture/Yaml/SoftDeleteableNonDeletedColumnValue.php new file mode 100644 index 0000000000..cae52c2381 --- /dev/null +++ b/tests/Gedmo/Mapping/Fixture/Yaml/SoftDeleteableNonDeletedColumnValue.php @@ -0,0 +1,25 @@ + 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\Mapping\Fixture\Yaml; + +class SoftDeleteableNonDeletedColumnValue +{ + /** + * @var int + */ + private $id; + + /** + * @var \DateTime|null + */ + private $deletedAt; +} diff --git a/tests/Gedmo/Mapping/SoftDeleteableMappingNonDeletedValueTest.php b/tests/Gedmo/Mapping/SoftDeleteableMappingNonDeletedValueTest.php new file mode 100644 index 0000000000..61e8e551db --- /dev/null +++ b/tests/Gedmo/Mapping/SoftDeleteableMappingNonDeletedValueTest.php @@ -0,0 +1,77 @@ + 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\Mapping; + +use Doctrine\ORM\EntityManager; +use Doctrine\ORM\Mapping\Driver\AnnotationDriver; +use Doctrine\ORM\Mapping\Driver\YamlDriver; +use Gedmo\Mapping\ExtensionMetadataFactory; +use Gedmo\SoftDeleteable\SoftDeleteableListener; +use Gedmo\Tests\Mapping\Fixture\SoftDeleteableNonDeletedColumnValue as AnnotatedSoftDeleteable; +use Gedmo\Tests\Mapping\Fixture\Xml\SoftDeleteableNonDeletedColumnValue as XmlSoftDeleteable; +use Gedmo\Tests\Mapping\Fixture\Yaml\SoftDeleteableNonDeletedColumnValue as YamlSoftDeleteable; + +/** + * These are mapping tests for SoftDeleteable extension + * + * @author Gustavo Falco + * @author Gediminas Morkevicius + */ +final class SoftDeleteableMappingNonDeletedValueTest extends ORMMappingTestCase +{ + private EntityManager $em; + + protected function setUp(): void + { + ORMMappingTestCase::setUp(); + + $listener = new SoftDeleteableListener(); + $listener->setCacheItemPool($this->cache); + + $this->em = $this->getBasicEntityManager(); + $this->em->getEventManager()->addEventSubscriber($listener); + } + + /** + * @return \Generator + */ + public static function dataSoftDeleteableObject(): \Generator + { + yield 'Model with XML mapping' => [XmlSoftDeleteable::class]; + + if (PHP_VERSION_ID >= 80000) { + yield 'Model with attributes' => [AnnotatedSoftDeleteable::class]; + } elseif (class_exists(AnnotationDriver::class)) { + yield 'Model with annotations' => [AnnotatedSoftDeleteable::class]; + } + + if (class_exists(YamlDriver::class)) { + yield 'Model with YAML mapping' => [YamlSoftDeleteable::class]; + } + } + + /** + * @param class-string $className + * + * @dataProvider dataSoftDeleteableObject + */ + public function testSoftDeleteableMapping(string $className): void + { + // Force metadata class loading. + $this->em->getClassMetadata($className); + $cacheId = ExtensionMetadataFactory::getCacheId($className, 'Gedmo\SoftDeleteable'); + $config = $this->cache->getItem($cacheId)->get(); + + static::assertArrayHasKey('nonDeletedColumnValue', $config); + static::assertSame('1970-01-01 00:00:00', $config['nonDeletedColumnValue']); + } +} diff --git a/tests/Gedmo/SoftDeleteable/Fixture/Document/UserNonDeletedValue.php b/tests/Gedmo/SoftDeleteable/Fixture/Document/UserNonDeletedValue.php new file mode 100644 index 0000000000..ae3a544755 --- /dev/null +++ b/tests/Gedmo/SoftDeleteable/Fixture/Document/UserNonDeletedValue.php @@ -0,0 +1,74 @@ + 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\SoftDeleteable\Fixture\Document; + +use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM; +use Doctrine\ODM\MongoDB\Types\Type; +use Gedmo\Mapping\Annotation as Gedmo; + +/** + * @ODM\Document(collection="users") + * + * @Gedmo\SoftDeleteable(fieldName="deletedAt" hardDelete: false, nonDeletedColumnValue: '1970-01-01 00:00:00') + */ +#[ODM\Document(collection: 'users')] +#[Gedmo\SoftDeleteable(fieldName: 'deletedAt', hardDelete: false, nonDeletedColumnValue: '1970-01-01 00:00:00')] +class UserNonDeletedValue +{ + /** + * @var \DateTime|null + * + * @ODM\Field(type="date") + */ + #[ODM\Field(type: Type::DATE)] + protected $deletedAt; + /** + * @var string|null + * + * @ODM\Id + */ + #[ODM\Id] + private $id; + + /** + * @ODM\Field(type="string") + */ + #[ODM\Field(type: Type::STRING)] + private ?string $username = null; + + public function setDeletedAt(\DateTime $deletedAt): self + { + $this->deletedAt = $deletedAt; + + return $this; + } + + public function getDeletedAt(): ?\DateTime + { + return $this->deletedAt; + } + + public function getId(): ?string + { + return $this->id; + } + + public function setUsername(?string $username): void + { + $this->username = $username; + } + + public function getUsername(): ?string + { + return $this->username; + } +} diff --git a/tests/Gedmo/SoftDeleteable/Fixture/Entity/UserNonDeletedValue.php b/tests/Gedmo/SoftDeleteable/Fixture/Entity/UserNonDeletedValue.php new file mode 100644 index 0000000000..cd1b9b14bf --- /dev/null +++ b/tests/Gedmo/SoftDeleteable/Fixture/Entity/UserNonDeletedValue.php @@ -0,0 +1,75 @@ + 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\SoftDeleteable\Fixture\Entity; + +use Doctrine\DBAL\Types\Types; +use Doctrine\ORM\Mapping as ORM; +use Gedmo\Mapping\Annotation as Gedmo; + +/** + * @ORM\Entity + * + * @Gedmo\SoftDeleteable(fieldName="deletedAt", hardDelete: false, nonDeletedColumnValue: '1970-01-01 00:00:00') + */ +#[ORM\Entity] +#[Gedmo\SoftDeleteable(fieldName: 'deletedAt', hardDelete: false, nonDeletedColumnValue: '1970-01-01 00:00:00')] +class UserNonDeletedValue +{ + /** + * @var int|null + * + * @ORM\Id + * @ORM\GeneratedValue(strategy="IDENTITY") + * @ORM\Column(type="integer") + */ + #[ORM\Id] + #[ORM\GeneratedValue(strategy: 'IDENTITY')] + #[ORM\Column(type: Types::INTEGER)] + private $id; + + /** + * @ORM\Column(name="title", type="string") + */ + #[ORM\Column(name: 'title', type: Types::STRING)] + private ?string $username = null; + + /** + * @ORM\Column(name="deleted_time", type="datetime", nullable=true) + */ + #[ORM\Column(name: 'deleted_time', type: Types::DATETIME_MUTABLE, nullable: true)] + private ?\DateTime $deletedAt = null; + + public function getId(): ?int + { + return $this->id; + } + + public function setUsername(?string $username): void + { + $this->username = $username; + } + + public function getUsername(): ?string + { + return $this->username; + } + + public function setDeletedAt(?\DateTime $deletedAt): void + { + $this->deletedAt = $deletedAt; + } + + public function getDeletedAt(): ?\DateTime + { + return $this->deletedAt; + } +} diff --git a/tests/Gedmo/SoftDeleteable/SoftDeleteableDocumentTest.php b/tests/Gedmo/SoftDeleteable/SoftDeleteableDocumentTest.php index b2c1fe4da6..9f8c553e64 100644 --- a/tests/Gedmo/SoftDeleteable/SoftDeleteableDocumentTest.php +++ b/tests/Gedmo/SoftDeleteable/SoftDeleteableDocumentTest.php @@ -16,6 +16,7 @@ use Gedmo\SoftDeleteable\SoftDeleteableListener; use Gedmo\Tests\SoftDeleteable\Fixture\Document\User; use Gedmo\Tests\SoftDeleteable\Fixture\Document\UserTimeAware; +use Gedmo\Tests\SoftDeleteable\Fixture\Document\UserNonDeletedValue; use Gedmo\Tests\SoftDeleteable\Fixture\Listener\WithLifecycleEventArgsFromODMTypeListener; use Gedmo\Tests\SoftDeleteable\Fixture\Listener\WithoutTypeListener; use Gedmo\Tests\SoftDeleteable\Fixture\Listener\WithPreAndPostSoftDeleteEventArgsTypeListener; @@ -72,6 +73,38 @@ public function testShouldSoftlyDeleteIfColumnNameDifferFromPropertyName(): void static::assertNull($user); } + public function testShouldBeMarkedAsSoftDeletedWithDifferentNonDeletedValueSet(): void + { + $repo = $this->dm->getRepository(UserNonDeletedValue::class); + $newUser = new UserNonDeletedValue(); + $username = 'test_user'; + $newUser->setUsername($username); + // '1970-01-01 00:00:00' + $date = (new \DateTime())->setTimestamp(0); + $newUser->setDeletedAt($date); + + $this->dm->persist($newUser); + $this->dm->flush(); + + $user = $repo->findOneBy(['username' => $username]); + static::assertSame($date, $user->getDeletedAt()); + + $this->dm->remove($user); + $this->dm->flush(); + + $user = $repo->findOneBy(['username' => $username]); + static::assertNull($user, 'User should be filtered out'); + + // deactivate filter to fetch softdeleted entity + $filter = $this->dm->getFilterCollection()->getFilter(self::SOFT_DELETEABLE_FILTER_NAME); + static::assertInstanceOf(SoftDeleteableFilter::class, $filter); + $filter->disableForDocument(UserNonDeletedValue::class); + + $user = $repo->findOneBy(['username' => $username]); + static::assertNotNull($user, 'User should be fetched when filter is disabled'); + static::assertGreaterThan(0, $user->getDeletedAt()->getTimestamp()); + } + /** * Tests the filter by enabling and disabling it between * some user persists actions. diff --git a/tests/Gedmo/SoftDeleteable/SoftDeleteableEntityTest.php b/tests/Gedmo/SoftDeleteable/SoftDeleteableEntityTest.php index 129351b3b9..a669dab112 100644 --- a/tests/Gedmo/SoftDeleteable/SoftDeleteableEntityTest.php +++ b/tests/Gedmo/SoftDeleteable/SoftDeleteableEntityTest.php @@ -29,6 +29,7 @@ use Gedmo\Tests\SoftDeleteable\Fixture\Entity\Page; use Gedmo\Tests\SoftDeleteable\Fixture\Entity\User; use Gedmo\Tests\SoftDeleteable\Fixture\Entity\UserNoHardDelete; +use Gedmo\Tests\SoftDeleteable\Fixture\Entity\UserNonDeletedValue; use Gedmo\Tests\SoftDeleteable\Fixture\Listener\WithLifecycleEventArgsFromORMTypeListener; use Gedmo\Tests\SoftDeleteable\Fixture\Listener\WithoutTypeListener; use Gedmo\Tests\SoftDeleteable\Fixture\Listener\WithPreAndPostSoftDeleteEventArgsTypeListener; @@ -651,6 +652,35 @@ public function testShouldNotDeleteIfColumnNameDifferFromPropertyName(): void static::assertNotNull($user, 'User is still available, hard delete done'); } + public function testShouldBeMarkedAsSoftDeletedWithDifferentNonDeletedValueSet(): void + { + $repo = $this->em->getRepository(UserNonDeletedValue::class); + $newUser = new UserNonDeletedValue(); + $username = 'test_user'; + $newUser->setUsername($username); + // '1970-01-01 00:00:00' + $date = (new \DateTime())->setTimestamp(0); + $newUser->setDeletedAt($date); + + $this->em->persist($newUser); + $this->em->flush(); + + $user = $repo->findOneBy(['username' => $username]); + static::assertSame($date, $user->getDeletedAt()); + + $this->em->remove($user); + $this->em->flush(); + + $user = $repo->findOneBy(['username' => $username]); + static::assertNull($user, 'User should be filtered out'); + + // deactivate filter to fetch softdeleted entity + $this->em->getFilters()->disable(self::SOFT_DELETEABLE_FILTER_NAME); + $user = $repo->findOneBy(['username' => $username]); + static::assertNotNull($user, 'User should be fetched when filter is disabled'); + static::assertGreaterThan(0, $user->getDeletedAt()->getTimestamp()); + } + protected function getUsedEntityFixtures(): array { return [ @@ -665,6 +695,7 @@ protected function getUsedEntityFixtures(): array OtherComment::class, Child::class, UserNoHardDelete::class, + UserNonDeletedValue::class, ]; }