From 534802904ed7c8a8c57902913ef5ef72eb197bb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=B3zsa=20Norbert?= Date: Thu, 19 Dec 2024 14:51:05 +0100 Subject: [PATCH 1/6] Add extends version fields exclude or include Add more index to AuditLog/Association --- README.md | 54 ++++++++++ config/doctrine/Association.orm.xml | 2 + config/doctrine/AuditLog.orm.xml | 2 + src/DependencyInjection/Configuration.php | 11 +++ .../DataDogAuditExtension.php | 8 +- src/EventListener/AuditListener.php | 99 +++++++++++++++---- 6 files changed, 153 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 132289e..a8fa1df 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,60 @@ data_dog_audit: You can specify either audited or unaudited entities. If both are specified, only audited entities would be taken into account. +### Specify Audited Entities with specific fields (extends version) + +The new configuration has been expanded with fields that can be set as excluded or highlighted. + +```php +class Test { + private string $name; + private bool $noImportant; + private \DateTime $createdAt; + private \DateTime $modifiedAt; +} +``` + +When we only want to audit a few fields: +```yaml +data_dog_audit: + entities: + App\Entity\Test: + mode: include + fields: + - name + - createdAt + - modifiedAt +``` +OR +```yaml +data_dog_audit: + entities: + App\Entity\Test: + mode: exclude + fields: + - noImportant +``` + +The old logic was also included in the new configuration: + +If we want to audit everything on an entity +```yaml +data_dog_audit: + entities: + App\Entity\Test: + mode: include + fields: ~ +``` + +If we want to exclude an entity +```yaml +data_dog_audit: + entities: + App\Entity\Test: + mode: exclude + fields: ~ +``` + ### Impersonation Sometimes, you might also want to blame the `impersonator` user instead of the `impersonated` one. diff --git a/config/doctrine/Association.orm.xml b/config/doctrine/Association.orm.xml index 82f1388..014ed6e 100644 --- a/config/doctrine/Association.orm.xml +++ b/config/doctrine/Association.orm.xml @@ -23,6 +23,8 @@ + + diff --git a/config/doctrine/AuditLog.orm.xml b/config/doctrine/AuditLog.orm.xml index 9bda568..ba4d8be 100644 --- a/config/doctrine/AuditLog.orm.xml +++ b/config/doctrine/AuditLog.orm.xml @@ -24,6 +24,8 @@ + + diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index e49255d..f22af7c 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -12,6 +12,17 @@ public function getConfigTreeBuilder(): TreeBuilder // @formatter:off $treeBuilder = new TreeBuilder('data_dog_audit'); $treeBuilder->getRootNode() + ->children() + ->arrayNode('entities')->canBeUnset()->useAttributeAsKey('key') + ->arrayPrototype() + ->children() + ->enumNode('mode')->values(['include', 'exclude'])->isRequired()->cannotBeEmpty()->end() + ->arrayNode('fields') + ->prototype('scalar')->end() + ->end() + ->end() + ->end() + ->end() ->children() ->arrayNode('audited_entities') ->canBeUnset() diff --git a/src/DependencyInjection/DataDogAuditExtension.php b/src/DependencyInjection/DataDogAuditExtension.php index 911b64b..10db907 100644 --- a/src/DependencyInjection/DataDogAuditExtension.php +++ b/src/DependencyInjection/DataDogAuditExtension.php @@ -11,7 +11,7 @@ class DataDogAuditExtension extends Extension { public function load(array $configs, ContainerBuilder $container): void { - $loader = new PhpFileLoader($container, new FileLocator(__DIR__ . '/../../config')); + $loader = new PhpFileLoader($container, new FileLocator(__DIR__.'/../../config')); $loader->load('services.php'); $configuration = new Configuration(); @@ -19,9 +19,11 @@ public function load(array $configs, ContainerBuilder $container): void $auditListener = $container->getDefinition('data_dog_audit.listener.audit'); - if (isset($config['audited_entities']) && !empty($config['audited_entities'])) { + if (isset($config['entities'])) { + $auditListener->addMethodCall('addEntities', array($config['entities'])); + } elseif (isset($config['audited_entities']) && !empty($config['audited_entities'])) { $auditListener->addMethodCall('addAuditedEntities', array($config['audited_entities'])); - } else if (isset($config['unaudited_entities'])) { + } elseif (isset($config['unaudited_entities'])) { $auditListener->addMethodCall('addUnauditedEntities', array($config['unaudited_entities'])); } diff --git a/src/EventListener/AuditListener.php b/src/EventListener/AuditListener.php index ef372d9..78ab3b1 100644 --- a/src/EventListener/AuditListener.php +++ b/src/EventListener/AuditListener.php @@ -2,6 +2,7 @@ namespace DataDog\AuditBundle\EventListener; +use DataDog\AuditBundle\DBAL\Middleware\AuditFlushMiddleware; use DataDog\AuditBundle\Entity\Association; use DataDog\AuditBundle\Entity\AuditLog; use Doctrine\DBAL\Types\Type; @@ -26,6 +27,8 @@ class AuditListener protected $unauditedEntities = []; + protected $entities = []; + protected $blameImpersonator = false; protected $inserted = []; // [$source, $changeset] @@ -49,7 +52,8 @@ class AuditListener public function __construct( private readonly TokenStorageInterface $securityTokenStorage, private readonly EntityManagerInterface $entityManager - ) {} + ) { + } public function setLabeler(?callable $labeler = null): self { @@ -79,6 +83,27 @@ public function addUnauditedEntities(array $unauditedEntities) } } + public function addEntities(array $entities): void + { + $this->entities = $entities; + + $auditedEntities = []; + $unauditedEntities = []; + + foreach ($entities as $fqcn => $data) { + if ( + $data['mode'] === 'include' || + ($data['mode'] === 'exclude' && !empty($data['fields'])) + ) { + $auditedEntities[] = $fqcn; + } elseif ($data['mode'] === 'exclude' && empty($data['fields'])) { + $unauditedEntities[] = $fqcn; + } + } + $this->addAuditedEntities($auditedEntities); + $this->addUnauditedEntities($unauditedEntities); + } + public function setBlameImpersonator($blameImpersonator) { // blame impersonator user instead of logged user (where applicable) @@ -94,18 +119,18 @@ protected function isEntityUnaudited($entity) { if (!empty($this->auditedEntities)) { // only selected entities are audited - $isEntityUnaudited = TRUE; + $isEntityUnaudited = true; foreach (array_keys($this->auditedEntities) as $auditedEntity) { if ($entity instanceof $auditedEntity) { - $isEntityUnaudited = FALSE; + $isEntityUnaudited = false; break; } } } else { - $isEntityUnaudited = FALSE; + $isEntityUnaudited = false; foreach (array_keys($this->unauditedEntities) as $unauditedEntity) { if ($entity instanceof $unauditedEntity) { - $isEntityUnaudited = TRUE; + $isEntityUnaudited = true; break; } } @@ -121,7 +146,7 @@ public function onFlush(OnFlushEventArgs $args): void $middlewares = $this->entityManager->getConnection()->getConfiguration()->getMiddlewares(); foreach ($middlewares as $middleware) { - if($middleware::class === 'DataDog\AuditBundle\DBAL\Middleware\AuditFlushMiddleware'){ + if ($middleware::class === AuditFlushMiddleware::class) { $middleware->flushHandler = [$this, 'flush']; } } @@ -365,9 +390,33 @@ protected function id(EntityManager $em, $entity) Type::getType($meta->fieldMappings[$pk]['type']), $meta->getReflectionProperty($pk)->getValue($entity) ); + return $pk; } + protected function isDiff(object $entity, string $fieldName): bool + { + if (array_key_exists($entity::class, $this->entities)) { // New logic + $entityConfig = $this->entities[$entity::class]; + + return ( + ( + $entityConfig['mode'] === 'include' && + ( + !empty($entityConfig['fields']) && in_array($fieldName, $entityConfig['fields']) || + empty($entityConfig['fields']) + ) + ) || + ( + $entityConfig['mode'] === 'exclude' && + !empty($entityConfig['fields']) && !in_array($fieldName, $entityConfig['fields']) + ) + ); + } else { // Old logic + return true; + } + } + protected function diff(EntityManager $em, $entity, array $ch): array { $uow = $em->getUnitOfWork(); @@ -375,23 +424,30 @@ protected function diff(EntityManager $em, $entity, array $ch): array $diff = []; foreach ($ch as $fieldName => list($old, $new)) { if ($meta->hasField($fieldName) && !array_key_exists($fieldName, $meta->embeddedClasses)) { - $mapping = $meta->fieldMappings[$fieldName]; - $diff[$fieldName] = [ - 'old' => $this->value($em, Type::getType($mapping['type']), $old), - 'new' => $this->value($em, Type::getType($mapping['type']), $new), - 'col' => $mapping['columnName'], - ]; + if ($this->isDiff($entity, $fieldName)) { + $mapping = $meta->fieldMappings[$fieldName]; + + $diff[$fieldName] = [ + 'old' => $this->value($em, Type::getType($mapping['type']), $old), + 'new' => $this->value($em, Type::getType($mapping['type']), $new), + 'col' => $mapping['columnName'], + ]; + } } elseif ($meta->hasAssociation($fieldName) && $meta->isSingleValuedAssociation($fieldName)) { - $mapping = $meta->associationMappings[$fieldName]; - $colName = $meta->getSingleAssociationJoinColumnName($fieldName); - $assocMeta = $em->getClassMetadata($mapping['targetEntity']); - $diff[$fieldName] = [ - 'old' => $this->assoc($em, $old), - 'new' => $this->assoc($em, $new), - 'col' => $colName, - ]; + if ($this->isDiff($entity, $fieldName)) { + $mapping = $meta->associationMappings[$fieldName]; + $colName = $meta->getSingleAssociationJoinColumnName($fieldName); + $assocMeta = $em->getClassMetadata($mapping['targetEntity']); + + $diff[$fieldName] = [ + 'old' => $this->assoc($em, $old), + 'new' => $this->assoc($em, $new), + 'col' => $colName, + ]; + } } } + return $diff; } @@ -421,6 +477,7 @@ protected function typ($className): string { // strip prefixes and repeating garbage from name $className = preg_replace("/^(.+\\\)?(.+)(Bundle\\\Entity)/", "$2", $className); + // underscore and lowercase each subdirectory return implode('.', array_map(function ($name) { return strtolower(preg_replace('/(?<=\\w)(?=[A-Z])/', '_$1', $name)); @@ -481,6 +538,7 @@ protected function blame(EntityManager $em): ?array if ($token && $token->getUser() instanceof UserInterface && \method_exists($token->getUser(), 'getId')) { return $this->assoc($em, $token->getUser()); } + return null; } @@ -498,6 +556,7 @@ private function getImpersonatorUserFromSecurityToken($token) return $role->getSource()->getUser(); } } + return null; } From 314e3ee8b8ad9aa93f12b7d70125e6c82f11db76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=B3zsa=20Norbert?= Date: Thu, 19 Dec 2024 15:23:02 +0100 Subject: [PATCH 2/6] Configuration.php fixes --- src/DependencyInjection/Configuration.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index f22af7c..58e53a1 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -14,11 +14,12 @@ public function getConfigTreeBuilder(): TreeBuilder $treeBuilder->getRootNode() ->children() ->arrayNode('entities')->canBeUnset()->useAttributeAsKey('key') - ->arrayPrototype() - ->children() - ->enumNode('mode')->values(['include', 'exclude'])->isRequired()->cannotBeEmpty()->end() - ->arrayNode('fields') - ->prototype('scalar')->end() + ->arrayPrototype() + ->children() + ->enumNode('mode')->values(['include', 'exclude'])->isRequired()->cannotBeEmpty()->end() + ->arrayNode('fields') + ->prototype('scalar')->end() + ->end() ->end() ->end() ->end() From 5d0a702e547827db09723ad144ab92387dbc4c70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=B3zsa=20Norbert?= Date: Thu, 19 Dec 2024 16:00:55 +0100 Subject: [PATCH 3/6] remove indexes --- config/doctrine/Association.orm.xml | 2 -- config/doctrine/AuditLog.orm.xml | 2 -- 2 files changed, 4 deletions(-) diff --git a/config/doctrine/Association.orm.xml b/config/doctrine/Association.orm.xml index 014ed6e..82f1388 100644 --- a/config/doctrine/Association.orm.xml +++ b/config/doctrine/Association.orm.xml @@ -23,8 +23,6 @@ - - diff --git a/config/doctrine/AuditLog.orm.xml b/config/doctrine/AuditLog.orm.xml index ba4d8be..9bda568 100644 --- a/config/doctrine/AuditLog.orm.xml +++ b/config/doctrine/AuditLog.orm.xml @@ -24,8 +24,6 @@ - - From 6084ba2d39ad6d39021b5a33937860d0d580c71f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=B3zsa=20Norbert?= Date: Thu, 19 Dec 2024 18:49:06 +0100 Subject: [PATCH 4/6] Add extends version unit test --- tests/Entity/Account.php | 69 +++++++++++ .../AuditListenerExtendsVersionTest.php | 111 ++++++++++++++++++ tests/EventListener/AuditListenerTest.php | 19 +++ tests/TestKernel.php | 4 +- 4 files changed, 201 insertions(+), 2 deletions(-) create mode 100644 tests/Entity/Account.php create mode 100644 tests/EventListener/AuditListenerExtendsVersionTest.php diff --git a/tests/Entity/Account.php b/tests/Entity/Account.php new file mode 100644 index 0000000..27ad00d --- /dev/null +++ b/tests/Entity/Account.php @@ -0,0 +1,69 @@ +id; + } + + public function setId(int $id): void + { + $this->id = $id; + } + + public function getUsername(): string + { + return $this->username; + } + + public function setUsername(string $username): void + { + $this->username = $username; + } + + public function getPassword(): string + { + return $this->password; + } + + public function setPassword(string $password): void + { + $this->password = $password; + } +} diff --git a/tests/EventListener/AuditListenerExtendsVersionTest.php b/tests/EventListener/AuditListenerExtendsVersionTest.php new file mode 100644 index 0000000..7bad536 --- /dev/null +++ b/tests/EventListener/AuditListenerExtendsVersionTest.php @@ -0,0 +1,111 @@ +kernel = new TestKernel([ + 'entities' => [ + Account::class => $dataDogAuditConfig, + ], + ]); + $this->kernel->boot(); + + $this->loadFixtures(); + + $em = $this->getDoctrine()->getManager(); + + $account = new Account(); + $callable($account); + + $em->persist($account); + $em->flush(); + + $auditLogs = $em->createQuery('SELECT l FROM '.AuditLog::class.' l')->getResult(); + $this->assertCount(1, $auditLogs); + + foreach ($expectedFields as $field) { + $this->assertArrayHasKey($field, $auditLogs[0]->getDiff()); + } + } + + public static function dataProvider(): array + { + return [ + 'exclude-password-field' => [ + [ + 'mode' => 'exclude', + 'fields' => [ + 'password', + ], + ], + function (Account $account): void { + $account->setUsername('username'); + $account->setPassword('password'); + }, + [ + 'username', + ], + ], + 'exclude-all' => [ + [ + 'mode' => 'exclude', + 'fields' => null, + ], + function (Account $account): void { + $account->setUsername('username'); + $account->setPassword('password'); + }, + [], + ], + 'include-password-field' => [ + [ + 'mode' => 'include', + 'fields' => [ + 'password', + ], + ], + function (Account $account): void { + $account->setUsername('username'); + $account->setPassword('password'); + }, + [ + 'password', + ], + ], + 'include-all' => [ + [ + 'mode' => 'include', + 'fields' => null, + ], + function (Account $account): void { + $account->setUsername('username'); + $account->setPassword('password'); + }, + [ + 'username', + 'password', + ], + ] + ]; + } +} diff --git a/tests/EventListener/AuditListenerTest.php b/tests/EventListener/AuditListenerTest.php index b084e20..4c5b62e 100644 --- a/tests/EventListener/AuditListenerTest.php +++ b/tests/EventListener/AuditListenerTest.php @@ -120,4 +120,23 @@ public function testEntityRelationUpdate(): void $this->assertCount(6, $em->createQuery('SELECT l FROM '.AuditLog::class.' l')->getResult()); } + + public function testExcludeField(): void + { + $this->resetDatabase(); + + $em = $this->getDoctrine()->getManager(); + + $tag = new Tag(); + $tag->setName('Books'); + + $em->persist($tag); + $em->flush(); + + $tag->setName('Movies'); + + $em->flush(); + + $this->assertCount(2, $em->createQuery('SELECT l FROM '.AuditLog::class.' l')->getResult()); + } } diff --git a/tests/TestKernel.php b/tests/TestKernel.php index 518affe..7b36887 100644 --- a/tests/TestKernel.php +++ b/tests/TestKernel.php @@ -17,7 +17,7 @@ class TestKernel extends Kernel { private ?string $projectDir = null; - public function __construct() + public function __construct(private readonly array $dataDogAuditConfig = []) { parent::__construct('test', true); } @@ -55,7 +55,7 @@ public function registerContainerConfiguration(LoaderInterface $loader): void ], ], ]); - $container->loadFromExtension('data_dog_audit'); + $container->loadFromExtension('data_dog_audit', $this->dataDogAuditConfig); $container->register('logger', NullLogger::class); }); From a717e403c42dd45f2eb50ed60bdf3368f6c15ab2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=B3zsa=20Norbert?= Date: Tue, 4 Feb 2025 19:43:38 +0100 Subject: [PATCH 5/6] add php typed add deprecation and validate to Configuration.php phpunit fixes --- src/DependencyInjection/Configuration.php | 6 +++ .../DataDogAuditExtension.php | 8 +-- src/EventListener/AuditListener.php | 54 +++++++++---------- .../AuditListenerExtendsVersionTest.php | 3 +- tests/EventListener/AuditListenerTest.php | 37 ++++++++++--- tests/OrmTestCase.php | 4 +- 6 files changed, 68 insertions(+), 44 deletions(-) diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 58e53a1..4809c94 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -12,6 +12,10 @@ public function getConfigTreeBuilder(): TreeBuilder // @formatter:off $treeBuilder = new TreeBuilder('data_dog_audit'); $treeBuilder->getRootNode() + ->validate() + ->ifTrue(fn ($v) => !empty($v['entities']) && (!empty($v['audited_entities']) || !empty($v['unaudited_entities']))) + ->thenInvalid('If you use the "entities" config you cannot use "audited_entities" and/or "unaudited_entities"') + ->end() ->children() ->arrayNode('entities')->canBeUnset()->useAttributeAsKey('key') ->arrayPrototype() @@ -26,6 +30,7 @@ public function getConfigTreeBuilder(): TreeBuilder ->end() ->children() ->arrayNode('audited_entities') + ->setDeprecated('data-dog/audit-bundle', 'v1.2', 'Not setting the "%node%" config option is deprecated. Use the "entities" option instead.') ->canBeUnset() ->performNoDeepMerging() ->scalarPrototype()->end() @@ -33,6 +38,7 @@ public function getConfigTreeBuilder(): TreeBuilder ->end() ->children() ->arrayNode('unaudited_entities') + ->setDeprecated('data-dog/audit-bundle', 'v1.2', 'Not setting the "%node%" config option is deprecated. Use the "entities" option instead.') ->canBeUnset() ->performNoDeepMerging() ->scalarPrototype()->end() diff --git a/src/DependencyInjection/DataDogAuditExtension.php b/src/DependencyInjection/DataDogAuditExtension.php index 10db907..af1daf8 100644 --- a/src/DependencyInjection/DataDogAuditExtension.php +++ b/src/DependencyInjection/DataDogAuditExtension.php @@ -20,15 +20,15 @@ public function load(array $configs, ContainerBuilder $container): void $auditListener = $container->getDefinition('data_dog_audit.listener.audit'); if (isset($config['entities'])) { - $auditListener->addMethodCall('addEntities', array($config['entities'])); + $auditListener->addMethodCall('addEntities', [$config['entities']]); } elseif (isset($config['audited_entities']) && !empty($config['audited_entities'])) { - $auditListener->addMethodCall('addAuditedEntities', array($config['audited_entities'])); + $auditListener->addMethodCall('addAuditedEntities', [$config['audited_entities']]); } elseif (isset($config['unaudited_entities'])) { - $auditListener->addMethodCall('addUnauditedEntities', array($config['unaudited_entities'])); + $auditListener->addMethodCall('addUnauditedEntities', [$config['unaudited_entities']]); } if (isset($config['blame_impersonator'])) { - $auditListener->addMethodCall('setBlameImpersonator', array($config['blame_impersonator'])); + $auditListener->addMethodCall('setBlameImpersonator', [$config['blame_impersonator']]); } } } diff --git a/src/EventListener/AuditListener.php b/src/EventListener/AuditListener.php index 78ab3b1..066b97a 100644 --- a/src/EventListener/AuditListener.php +++ b/src/EventListener/AuditListener.php @@ -23,23 +23,23 @@ class AuditListener */ protected $labeler; - protected $auditedEntities = []; + protected array $auditedEntities = []; - protected $unauditedEntities = []; + protected array $unauditedEntities = []; - protected $entities = []; + protected array $entities = []; - protected $blameImpersonator = false; + protected bool $blameImpersonator = false; - protected $inserted = []; // [$source, $changeset] + protected array $inserted = []; // [$source, $changeset] - protected $updated = []; // [$source, $changeset] + protected array $updated = []; // [$source, $changeset] - protected $removed = []; // [$source, $id] + protected array $removed = []; // [$source, $id] - protected $associated = []; // [$source, $target, $mapping] + protected array $associated = []; // [$source, $target, $mapping] - protected $dissociated = []; // [$source, $target, $id, $mapping] + protected array $dissociated = []; // [$source, $target, $id, $mapping] protected $assocInsertStmt; @@ -67,7 +67,7 @@ public function getLabeler(): ?callable return $this->labeler; } - public function addAuditedEntities(array $auditedEntities) + public function addAuditedEntities(array $auditedEntities): void { // use entity names as array keys for easier lookup foreach ($auditedEntities as $auditedEntity) { @@ -75,7 +75,7 @@ public function addAuditedEntities(array $auditedEntities) } } - public function addUnauditedEntities(array $unauditedEntities) + public function addUnauditedEntities(array $unauditedEntities): void { // use entity names as array keys for easier lookup foreach ($unauditedEntities as $unauditedEntity) { @@ -104,18 +104,18 @@ public function addEntities(array $entities): void $this->addUnauditedEntities($unauditedEntities); } - public function setBlameImpersonator($blameImpersonator) + public function setBlameImpersonator(bool $blameImpersonator): void { // blame impersonator user instead of logged user (where applicable) $this->blameImpersonator = $blameImpersonator; } - public function getUnauditedEntities() + public function getUnauditedEntities(): array { return array_keys($this->unauditedEntities); } - protected function isEntityUnaudited($entity) + protected function isEntityUnaudited(object $entity): bool { if (!empty($this->auditedEntities)) { // only selected entities are audited @@ -213,7 +213,7 @@ public function onFlush(OnFlushEventArgs $args): void } } - public function flush() + public function flush(): void { $uow = $this->entityManager->getUnitOfWork(); @@ -262,7 +262,7 @@ public function flush() $this->dissociated = []; } - protected function associate(EntityManager $em, $source, $target, array $mapping): void + protected function associate(EntityManager $em, ?object $source, ?object $target, array $mapping): void { $this->audit($em, [ 'source' => $this->assoc($em, $source), @@ -274,7 +274,7 @@ protected function associate(EntityManager $em, $source, $target, array $mapping ]); } - protected function dissociate(EntityManager $em, $source, $target, $id, array $mapping): void + protected function dissociate(EntityManager $em, ?object $source, ?object $target, string|int $id, array $mapping): void { $this->audit($em, [ 'source' => $this->assoc($em, $source), @@ -286,7 +286,7 @@ protected function dissociate(EntityManager $em, $source, $target, $id, array $m ]); } - protected function insert(EntityManager $em, $entity, array $ch): void + protected function insert(EntityManager $em, object $entity, array $ch): void { $diff = $this->diff($em, $entity, $ch); if (empty($diff)) { @@ -303,7 +303,7 @@ protected function insert(EntityManager $em, $entity, array $ch): void ]); } - protected function update(EntityManager $em, $entity, array $ch): void + protected function update(EntityManager $em, object $entity, array $ch): void { $diff = $this->diff($em, $entity, $ch); if (empty($diff)) { @@ -320,7 +320,7 @@ protected function update(EntityManager $em, $entity, array $ch): void ]); } - protected function remove(EntityManager $em, $entity, $id): void + protected function remove(EntityManager $em, object $entity, string|int $id): void { $meta = $em->getClassMetadata(get_class($entity)); $source = array_merge($this->assoc($em, $entity), ['fk' => $id]); @@ -381,7 +381,7 @@ protected function audit(EntityManager $em, array $data): void $this->auditInsertStmt->executeQuery(); } - protected function id(EntityManager $em, $entity) + protected function id(EntityManager $em, object $entity) { $meta = $em->getClassMetadata(get_class($entity)); $pk = $meta->getSingleIdentifierFieldName(); @@ -417,7 +417,7 @@ protected function isDiff(object $entity, string $fieldName): bool } } - protected function diff(EntityManager $em, $entity, array $ch): array + protected function diff(EntityManager $em, object $entity, array $ch): array { $uow = $em->getUnitOfWork(); $meta = $em->getClassMetadata(get_class($entity)); @@ -451,7 +451,7 @@ protected function diff(EntityManager $em, $entity, array $ch): array return $diff; } - protected function assoc(EntityManager $em, $association = null): ?array + protected function assoc(EntityManager $em, ?object $association = null): ?array { if (null === $association) { return null; @@ -484,7 +484,7 @@ protected function typ($className): string }, explode('\\', $className))); } - protected function label(EntityManager $em, $entity) + protected function label(EntityManager $em, object $entity) { if (is_callable($this->labeler)) { return call_user_func($this->labeler, $entity); @@ -542,7 +542,7 @@ protected function blame(EntityManager $em): ?array return null; } - private function getImpersonatorUserFromSecurityToken($token) + private function getImpersonatorUserFromSecurityToken(?TokenInterface $token) { if (false === $this->blameImpersonator) { return null; @@ -560,10 +560,6 @@ private function getImpersonatorUserFromSecurityToken($token) return null; } - /** - * @param TokenInterface $token - * @return array - */ private function getRoles(TokenInterface $token): array { if (method_exists($token, 'getRoleNames')) { diff --git a/tests/EventListener/AuditListenerExtendsVersionTest.php b/tests/EventListener/AuditListenerExtendsVersionTest.php index 7bad536..8bdf58a 100644 --- a/tests/EventListener/AuditListenerExtendsVersionTest.php +++ b/tests/EventListener/AuditListenerExtendsVersionTest.php @@ -23,12 +23,11 @@ public function testExtendsVersion( callable $callable, array $expectedFields ): void { - $this->kernel = new TestKernel([ + $this->bootKernel([ 'entities' => [ Account::class => $dataDogAuditConfig, ], ]); - $this->kernel->boot(); $this->loadFixtures(); diff --git a/tests/EventListener/AuditListenerTest.php b/tests/EventListener/AuditListenerTest.php index 4c5b62e..b55c68d 100644 --- a/tests/EventListener/AuditListenerTest.php +++ b/tests/EventListener/AuditListenerTest.php @@ -8,18 +8,13 @@ use DataDog\AuditBundle\Tests\Entity\Post; use DataDog\AuditBundle\Tests\Entity\Tag; use DataDog\AuditBundle\Tests\OrmTestCase; +use DataDog\AuditBundle\Tests\TestKernel; final class AuditListenerTest extends OrmTestCase { - protected function setUp(): void - { - parent::setUp(); - - $this->loadFixtures(); - } - public function testSingleEntityCreation(): void { + $this->includeKernelBoot(); $this->resetDatabase(); $em = $this->getDoctrine()->getManager(); @@ -35,6 +30,7 @@ public function testSingleEntityCreation(): void public function testSingleEntityUpdate(): void { + $this->includeKernelBoot(); $this->resetDatabase(); $em = $this->getDoctrine()->getManager(); @@ -54,6 +50,7 @@ public function testSingleEntityUpdate(): void public function testSingleEntityDelete(): void { + $this->includeKernelBoot(); $this->resetDatabase(); $em = $this->getDoctrine()->getManager(); @@ -73,6 +70,7 @@ public function testSingleEntityDelete(): void public function testEntityRelationCreate(): void { + $this->includeKernelBoot(); $this->resetDatabase(); $em = $this->getDoctrine()->getManager(); @@ -94,6 +92,7 @@ public function testEntityRelationCreate(): void public function testEntityRelationUpdate(): void { + $this->includeKernelBoot(); $this->resetDatabase(); $em = $this->getDoctrine()->getManager(); @@ -123,6 +122,7 @@ public function testEntityRelationUpdate(): void public function testExcludeField(): void { + $this->excludeKernelBoot(); $this->resetDatabase(); $em = $this->getDoctrine()->getManager(); @@ -139,4 +139,27 @@ public function testExcludeField(): void $this->assertCount(2, $em->createQuery('SELECT l FROM '.AuditLog::class.' l')->getResult()); } + + private function includeKernelBoot(): void + { + $this->bootKernel([ + 'audited_entities' => [ + Tag::class, + Post::class, + ], + ]); + + $this->loadFixtures(); + } + + private function excludeKernelBoot(): void + { + $this->bootKernel([ + 'unaudited_entities' => [ + Tag::class, + ], + ]); + + $this->loadFixtures(); + } } diff --git a/tests/OrmTestCase.php b/tests/OrmTestCase.php index e5c8d58..91e7eba 100644 --- a/tests/OrmTestCase.php +++ b/tests/OrmTestCase.php @@ -14,9 +14,9 @@ abstract class OrmTestCase extends TestCase { protected KernelInterface $kernel; - protected function setUp(): void + protected function bootKernel(array $dataDogAuditConfig): void { - $this->kernel = new TestKernel(); + $this->kernel = new TestKernel($dataDogAuditConfig); $this->kernel->boot(); } From 6d3c4abed24a7bcb207349bc6d14bd92d18f1213 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=B3zsa=20Norbert?= Date: Tue, 4 Feb 2025 19:47:07 +0100 Subject: [PATCH 6/6] add php 8.4 to phpunit.yml --- .github/workflows/phpunit.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index a866253..c1746a5 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -15,7 +15,7 @@ jobs: strategy: fail-fast: false matrix: - php: ['8.1', '8.2', '8.3'] + php: ['8.1', '8.2', '8.3', '8.4'] steps: - name: Checkout