diff --git a/phpstan.neon.dist b/phpstan.neon.dist index f9a6985f..b7263d0a 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -8,4 +8,4 @@ parameters: checkMissingOverrideMethodAttribute: true ignoreErrors: - '#Instantiated class Seld\\PharUtils\\Timestamps not found.#' - - '#on an unknown class Seld\\PharUtils\\Timestamps.#' \ No newline at end of file + - '#on an unknown class Seld\\PharUtils\\Timestamps.#' diff --git a/src/Anonymization/Anonymizator.php b/src/Anonymization/Anonymizator.php index 39b61d24..2adcc576 100644 --- a/src/Anonymization/Anonymizator.php +++ b/src/Anonymization/Anonymizator.php @@ -86,14 +86,11 @@ protected function getSalt(): string */ protected function createAnonymizer(AnonymizerConfig $config): AbstractAnonymizer { - $className = $this->anonymizerRegistry->get($config->anonymizer); - \assert(\is_subclass_of($className, AbstractAnonymizer::class)); - - return new $className( - $config->table, - $config->targetName, - $this->databaseSession, + return $this->anonymizerRegistry->createAnonymizer( + $config->anonymizer, + $config, $config->options->with(['salt' => $this->getSalt()]), + $this->databaseSession ); } diff --git a/src/Anonymization/Anonymizer/AbstractAnonymizer.php b/src/Anonymization/Anonymizer/AbstractAnonymizer.php index 5a6285c4..a8c3c49c 100644 --- a/src/Anonymization/Anonymizer/AbstractAnonymizer.php +++ b/src/Anonymization/Anonymizer/AbstractAnonymizer.php @@ -5,7 +5,6 @@ namespace MakinaCorpus\DbToolsBundle\Anonymization\Anonymizer; use MakinaCorpus\DbToolsBundle\Anonymization\Anonymizator; -use MakinaCorpus\DbToolsBundle\Attribute\AsAnonymizer; use MakinaCorpus\QueryBuilder\DatabaseSession; use MakinaCorpus\QueryBuilder\Expression; use MakinaCorpus\QueryBuilder\ExpressionFactory; @@ -28,20 +27,6 @@ final public function __construct( $this->validateOptions(); } - final public static function id(): string - { - return self::getMetadata()->id(); - } - - final public static function getMetadata(): AsAnonymizer - { - if ($attributes = (new \ReflectionClass(static::class))->getAttributes(AsAnonymizer::class)) { - return $attributes[0]->newInstance(); - } - - throw new \LogicException(\sprintf("Class '%s' should have an '%s' attribute.", static::class, AsAnonymizer::class)); - } - /** * Get table name. * diff --git a/src/Anonymization/Anonymizer/AnonymizerRegistry.php b/src/Anonymization/Anonymizer/AnonymizerRegistry.php index 6109b5a5..f8dce218 100644 --- a/src/Anonymization/Anonymizer/AnonymizerRegistry.php +++ b/src/Anonymization/Anonymizer/AnonymizerRegistry.php @@ -5,6 +5,9 @@ namespace MakinaCorpus\DbToolsBundle\Anonymization\Anonymizer; use Composer\InstalledVersions; +use MakinaCorpus\DbToolsBundle\Anonymization\Config\AnonymizerConfig; +use MakinaCorpus\DbToolsBundle\Attribute\AsAnonymizer; +use MakinaCorpus\QueryBuilder\DatabaseSession; class AnonymizerRegistry { @@ -26,7 +29,10 @@ class AnonymizerRegistry Core\StringAnonymizer::class, ]; - private ?array $anonymizers = null; + /** @var array */ + private ?array $classes = null; + /** @var array */ + private ?array $metadata = null; private array $paths = []; public function __construct(?array $paths = null) @@ -45,30 +51,57 @@ public function addPath(array $paths): void /** * Get all registered anonymizers classe names. * - * @return array - * Keys are names, values are class names. + * @return array */ - public function getAnonymizers(): array + public function getAllAnonymizerMetadata(): array { $this->initialize(); - return $this->anonymizers; + return $this->metadata; } /** - * Get anonymizer class name. - * - * @param string $name - * Anonymizer name. - * - * @return string - * Anonymizer class name. + * Create anonymizer instance. + */ + public function createAnonymizer( + string $name, + AnonymizerConfig $config, + Options $options, + DatabaseSession $databaseSession, + ): AbstractAnonymizer { + $className = $this->getAnonymizerClass($name); + + return new $className($config->table, $config->targetName, $databaseSession, $options); + } + + /** + * Get anonymizer metadata. + */ + public function getAnonymizerMetadata(string $name): AsAnonymizer + { + $this->initialize(); + + return $this->metadata[$name] ?? $this->throwAnonymizerDoesNotExist($name); + } + + /** + * @internal + * For unit tests only, please do not use. */ - public function get(string $name): string + public function getAnonymizerClass(string $name): string { $this->initialize(); - return $this->anonymizers[$name] ?? throw new \InvalidArgumentException(\sprintf("Can't find Anonymizer with name : %s, check your configuration.", $name)); + return $this->classes[$name] ?? $this->throwAnonymizerDoesNotExist($name); + } + + private function getAnonymizatorClassMetadata(string $className): AsAnonymizer + { + if ($attributes = (new \ReflectionClass($className))->getAttributes(AsAnonymizer::class)) { + return $attributes[0]->newInstance(); + } + + throw new \LogicException(\sprintf("Class '%s' should have an '%s' attribute.", $className, AsAnonymizer::class)); } /** @@ -76,11 +109,12 @@ public function get(string $name): string */ private function initialize(): void { - if (null !== $this->anonymizers) { + if (null !== $this->classes) { return; } - $this->anonymizers = []; + $this->classes = []; + $this->metadata = []; foreach (self::$coreAnonymizers as $className) { $this->addAnonymizer($className, true); @@ -152,7 +186,11 @@ private function addAnonymizer(string $className, bool $failOnError = false): vo return; } - $this->anonymizers[$className::id()] = $className; + $metadata = $this->getAnonymizatorClassMetadata($className); + $id = $metadata->id(); + + $this->classes[$id] = $className; + $this->metadata[$id] = $metadata; } /** @@ -172,4 +210,9 @@ private function locatePacks(): void } } } + + private function throwAnonymizerDoesNotExist(string $name): never + { + throw new \InvalidArgumentException(\sprintf("Can't find Anonymizer with name : %s, check your configuration.", $name)); + } } diff --git a/src/Command/Anonymization/AnonymizerListCommand.php b/src/Command/Anonymization/AnonymizerListCommand.php index ca1184c8..85dc4949 100644 --- a/src/Command/Anonymization/AnonymizerListCommand.php +++ b/src/Command/Anonymization/AnonymizerListCommand.php @@ -32,11 +32,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int $io = new SymfonyStyle($input, $output); - $rawList = $this->anonymizerRegistry->getAnonymizers(); + $rawList = $this->anonymizerRegistry->getAllAnonymizerMetadata(); $list = []; - foreach ($rawList as $anonymizer) { - $metadata = $anonymizer::getMetadata(); + foreach ($rawList as $metadata) { \assert($metadata instanceof AsAnonymizer); if (!\array_key_exists($metadata->pack, $list)) { diff --git a/tests/Unit/Anonymization/Anonymizer/AnonymizerRegistryTest.php b/tests/Unit/Anonymization/Anonymizer/AnonymizerRegistryTest.php index d972e646..fa0e5626 100644 --- a/tests/Unit/Anonymization/Anonymizer/AnonymizerRegistryTest.php +++ b/tests/Unit/Anonymization/Anonymizer/AnonymizerRegistryTest.php @@ -17,14 +17,17 @@ public function testAnonymizerRegistryWithTestPack(): void $anonymizerRegistry = new AnonymizerRegistry(); - $anonymizers = $anonymizerRegistry->getAnonymizers(); + $anonymizers = $anonymizerRegistry->getAllAnonymizerMetadata(); self::assertNotEmpty($anonymizers); self::assertArrayHasKey('string', $anonymizers); self::assertArrayHasKey('test.my-anonymizer', $anonymizers); - self::assertEquals('MakinaCorpus\DbToolsBundle\Anonymization\Anonymizer\Core\FloatAnonymizer', $anonymizerRegistry->get('float')); - self::assertEquals('DbToolsBundle\PackTest\Anonymizer\MyAnonymizer', $anonymizerRegistry->get('test.my-anonymizer')); + self::assertEquals('MakinaCorpus\DbToolsBundle\Anonymization\Anonymizer\Core\FloatAnonymizer', $anonymizerRegistry->getAnonymizerClass('float')); + self::assertEquals('float', $anonymizerRegistry->getAnonymizerMetadata('float')->id()); + + self::assertEquals('DbToolsBundle\PackTest\Anonymizer\MyAnonymizer', $anonymizerRegistry->getAnonymizerClass('test.my-anonymizer')); + self::assertEquals('test.my-anonymizer', $anonymizerRegistry->getAnonymizerMetadata('test.my-anonymizer')->id()); } finally { $this->composerProjectRemove(); } @@ -34,10 +37,10 @@ public function testAnonymizerRegistryWithoutTestPack(): void { $anonymizerRegistry = new AnonymizerRegistry(); - self::assertEquals('MakinaCorpus\DbToolsBundle\Anonymization\Anonymizer\Core\FloatAnonymizer', $anonymizerRegistry->get('float')); + self::assertEquals('MakinaCorpus\DbToolsBundle\Anonymization\Anonymizer\Core\FloatAnonymizer', $anonymizerRegistry->getAnonymizerClass('float')); self::expectExceptionMessageMatches("@Can't find Anonymizer@"); - $anonymizerRegistry->get('test.my_anonymizer'); + $anonymizerRegistry->getAnonymizerClass('test.my_anonymizer'); } private function composerProjectRemove(): void