Skip to content
Closed
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 docs/content/anonymization/core-anonymizers.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ This page list all *Anonymizers* provided by *DbToolsBundle*.
<!--@include: ./core-anonymizers/lorem-ipsum.md-->
<!--@include: ./core-anonymizers/address.md-->
<!--@include: ./core-anonymizers/iban-bic.md-->
<!--@include: ./core-anonymizers/file-resolution.md-->
39 changes: 39 additions & 0 deletions docs/content/anonymization/core-anonymizers/file-resolution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
## File name resolution

In various places you can configure relative file names in order to load data,
here is how relative file names are resolved.
**All relative file names will be considered relative to a given _base path_.**

The default base path is always stable but depends upon your selected flavor.

@todo examples

@@@ symfony

When parsing Symfony configuration, base path will always be the project
directory, known as `%kernel.project_dir%` variable in Symfony configuration.
This is the directory where your `composer.json` file.

@todo examples

@@@
@@@ laravel

When parsing Laravel configuration, base path will always be the project
directory, as returned by the `base_path()` Laravel function.

@todo examples

@@@
@@@ standalone docker

When parsing configuration in the standalone CLI version or in docker context,
base path will be currently being parsed Yaml file.

:::tip
If you set the `workdir` option in your configuration file, then it will
override the file directory and use it as the base path.

@todo link to `workdir` documentation
:::
@@@
10 changes: 8 additions & 2 deletions src/Anonymization/Anonymizer/Core/StringPatternAnonymizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -192,15 +192,21 @@ private function getAnonymizer(string $anonymizer, ?Options $options = null, int
return $ret;
}

$config = new AnonymizerConfig($this->tableName, $this->columnName, $anonymizer, new Options());
$config = new AnonymizerConfig(
$this->tableName,
$this->columnName,
$anonymizer,
new Options(),
__DIR__, // @todo FIXME
);

return $this->childAnonymizers[$key] = $this
->getAnonymizerRegistry()
->createAnonymizer(
$anonymizer,
$config,
$options ?? new Options(),
$this->databaseSession
$this->databaseSession,
)
;
}
Expand Down
6 changes: 6 additions & 0 deletions src/Anonymization/Config/AnonymizerConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,11 @@ public function __construct(
public readonly string $targetName,
public readonly string $anonymizer,
public readonly Options $options,
/**
* Root directory in which this anonymizer configuration was in the
* first place. This allows implementations to use it in order, for
* example, to load files using a relative path.
*/
public readonly string $basePath,
) {}
}
8 changes: 7 additions & 1 deletion src/Anonymization/Config/Loader/ArrayLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@ class ArrayLoader implements LoaderInterface
{
public function __construct(
private array $data,
private string $connectionName = 'default',
private string $connectionName,
/**
* Root directory from which the configuration was loaded. It allows
* later file loading (for example, when sources are CSV or TXT files).
*/
private readonly string $basePath,
) {}

#[\Override]
Expand Down Expand Up @@ -51,6 +56,7 @@ public function load(AnonymizationConfig $config): void
$target,
$targetConfig['anonymizer'],
new Options($targetConfig['options']),
$this->basePath,
));
}
}
Expand Down
8 changes: 8 additions & 0 deletions src/Anonymization/Config/Loader/AttributesLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ class AttributesLoader implements LoaderInterface
{
public function __construct(
private EntityManagerProvider $entityManagerProvider,
/**
* Root directory from which the configuration was loaded. It allows
* later file loading (for example, when sources are CSV or TXT files).
*/
private readonly string $basePath,
) {}

#[\Override]
Expand Down Expand Up @@ -62,6 +67,7 @@ public function load(AnonymizationConfig $config): void
$anonymization->type . '_' . $key,
$anonymization->type,
new Options($anonymization->options),
$this->basePath,
));
}
}
Expand All @@ -78,6 +84,7 @@ public function load(AnonymizationConfig $config): void
$metadata->getColumnName($fieldName),
$propertyConfig->type,
new Options($propertyConfig->options),
$this->basePath,
));
}
}
Expand Down Expand Up @@ -109,6 +116,7 @@ public function load(AnonymizationConfig $config): void
$columnName,
$anonymization->type,
new Options($anonymization->options),
$this->basePath,
));
}
}
Expand Down
14 changes: 13 additions & 1 deletion src/Anonymization/Config/Loader/PhpFileLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,20 @@ class PhpFileLoader extends ArrayLoader
public function __construct(
private string $file,
string $connectionName = 'default',
/**
* Root directory from which the configuration was loaded. It allows
* later file loading (for example, when sources are CSV or TXT files).
*
* If not set, the file directory will be used instead. If set, it will
* override the file directory.
*/
?string $basePath = null,
) {
parent::__construct([], $connectionName);
// @todo dirname() is purely soft logic, it does not imply any
// syscalls, whereas realpah() may.
$basePath ??= \realpath(\dirname($file));

parent::__construct([], $connectionName, $basePath);
}

#[\Override]
Expand Down
14 changes: 13 additions & 1 deletion src/Anonymization/Config/Loader/YamlLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,20 @@ class YamlLoader extends ArrayLoader
public function __construct(
private string $file,
string $connectionName = 'default',
/**
* Root directory from which the configuration was loaded. It allows
* later file loading (for example, when sources are CSV or TXT files).
*
* If not set, the file directory will be used instead. If set, it will
* override the file directory.
*/
?string $basePath = null,
) {
parent::__construct([], $connectionName);
// @todo dirname() is purely soft logic, it does not imply any
// syscalls, whereas realpah() may.
$basePath ??= \realpath(\dirname($file));

parent::__construct([], $connectionName, $basePath);
}

#[\Override]
Expand Down
8 changes: 5 additions & 3 deletions src/Bridge/Laravel/DbToolsServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@ function (AnonymizatorFactory $factory, Application $app): void {
/** @var Repository $config */
$config = $app->make('config');

$workdir = $config->get('db-tools.workdir', $app->basePath());

foreach ($config->get('db-tools.anonymization_files', []) as $connectionName => $file) {
// 0 is not a good index for extension, this fails for false and 0.
if (!($pos = \strrpos($file, '.'))) {
Expand All @@ -155,8 +157,8 @@ function (AnonymizatorFactory $factory, Application $app): void {

$ext = \substr($file, $pos + 1);
$loader = match ($ext) {
'php' => new PhpFileLoader($file, $connectionName),
'yml', 'yaml' => new YamlLoader($file, $connectionName),
'php' => new PhpFileLoader($file, $connectionName, $workdir),
'yml', 'yaml' => new YamlLoader($file, $connectionName, $workdir),
default => throw new ConfigurationException(\sprintf(
"File extension \"%s\" is unsupported (given path: \"%s\").",
$ext,
Expand All @@ -168,7 +170,7 @@ function (AnonymizatorFactory $factory, Application $app): void {
}

foreach ($config->get('db-tools.anonymization', []) as $connectionName => $array) {
$factory->addConfigurationLoader(new ArrayLoader($array, $connectionName));
$factory->addConfigurationLoader(new ArrayLoader($array, $connectionName, $workdir));
}
}
);
Expand Down
4 changes: 2 additions & 2 deletions src/Bridge/Standalone/Bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -237,10 +237,10 @@ public static function bootstrap(array $config = [], array $configFiles = [], ?L
$anonymizatorFactory = new AnonymizatorFactory($databaseSessionRegistry, $anonymizerRegistry, $logger);

foreach (($config['anonymization_files'] ?? []) as $connectionName => $file) {
$anonymizatorFactory->addConfigurationLoader(new YamlLoader($file, $connectionName));
$anonymizatorFactory->addConfigurationLoader(new YamlLoader($file, $connectionName, $config['workdir']));
}
foreach (($config['anonymization'] ?? []) as $connectionName => $array) {
$anonymizatorFactory->addConfigurationLoader(new ArrayLoader($array, $connectionName));
$anonymizatorFactory->addConfigurationLoader(new ArrayLoader($array, $connectionName, $config['workdir']));
}

$backupperFactory = new BackupperFactory($databaseSessionRegistry, $configRegistry, $logger);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Parameter;
use Symfony\Component\DependencyInjection\Reference;

class DbToolsPass implements CompilerPassInterface
Expand Down Expand Up @@ -49,7 +50,7 @@ private function registerArrayLoader(array $data, string $connectionName, Contai
{
$definition = new Definition();
$definition->setClass(ArrayLoader::class);
$definition->setArguments([$data, $connectionName]);
$definition->setArguments([$data, $connectionName, new Parameter('kernel.project_dir')]);

$loaderId = 'db_tools.anonymization.loader.array.' . $connectionName;
$container->setDefinition($loaderId, $definition);
Expand All @@ -61,7 +62,7 @@ private function registerYamlLoader(string $file, string $connectionName, Contai
{
$definition = new Definition();
$definition->setClass(YamlLoader::class);
$definition->setArguments([$file, $connectionName]);
$definition->setArguments([$file, $connectionName, new Parameter('kernel.project_dir')]);

$loaderId = 'db_tools.anonymization.loader.yaml.' . $connectionName;
$container->setDefinition($loaderId, $definition);
Expand All @@ -73,7 +74,7 @@ private function registerAttributesLoader(ContainerBuilder $container): string
{
$definition = new Definition();
$definition->setClass(AttributesLoader::class);
$definition->setArguments([new Reference('doctrine.orm.command.entity_manager_provider')]);
$definition->setArguments([new Reference('doctrine.orm.command.entity_manager_provider'), new Parameter('kernel.project_dir')]);

$loaderId = 'db_tools.anonymization.loader.attributes';
$container->setDefinition($loaderId, $definition);
Expand Down
26 changes: 24 additions & 2 deletions src/Test/FunctionalTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,22 @@

use Doctrine\DBAL\Configuration;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\Driver\AbstractSQLiteDriver\Middleware\EnableForeignKeys;
use Doctrine\DBAL\Driver\OCI8\Middleware\InitializeSession;
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\Logging\Middleware;
use Doctrine\DBAL\Schema\Column;
use Doctrine\DBAL\Schema\DefaultSchemaManagerFactory;
use Doctrine\Persistence\ManagerRegistry;
use MakinaCorpus\DbToolsBundle\Anonymization\Anonymizator;
use MakinaCorpus\DbToolsBundle\Anonymization\Anonymizer\AnonymizerRegistry;
use MakinaCorpus\DbToolsBundle\Anonymization\Anonymizer\Options;
use MakinaCorpus\DbToolsBundle\Anonymization\Config\AnonymizationConfig;
use MakinaCorpus\DbToolsBundle\Anonymization\Config\AnonymizerConfig;
use MakinaCorpus\DbToolsBundle\Bridge\Symfony\DoctrineDatabaseSessionRegistry;
use MakinaCorpus\DbToolsBundle\Database\DatabaseSessionRegistry;
use MakinaCorpus\QueryBuilder\Bridge\Doctrine\DoctrineQueryBuilder;
use MakinaCorpus\QueryBuilder\DatabaseSession;
use MakinaCorpus\QueryBuilder\Bridge\Doctrine\DoctrineQueryBuilder;
use MakinaCorpus\QueryBuilder\Error\Server\DatabaseObjectDoesNotExistError;
use Psr\Log\AbstractLogger;

Expand Down Expand Up @@ -257,6 +258,27 @@ protected function createAnonymizatorWithConfig(AnonymizerConfig ...$anonymizerC
);
}

/**
* For anonymizers unit test, creates an anonymizator with the given
* configuration, which should register all anonymizers required for
* the test.
*/
protected function createAnonymizatorArbitrary(
string $table,
string $targetName,
string $anonymizer,
?Options $options = null,
): Anonymizator {
$config = new AnonymizationConfig();
$config->add(new AnonymizerConfig($table, $targetName, $anonymizer, $options ?? new Options(), __DIR__));

return new Anonymizator(
$this->getDatabaseSession(),
new AnonymizerRegistry(),
$config
);
}

/**
* Create database connection.
*
Expand Down
2 changes: 2 additions & 0 deletions tests/Functional/Anonymizer/AnonymizatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ public function testMultipleAnonymizersAtOnce(): void
new Options([
'sample' => ['foo', 'bar', 'baz'],
]),
__DIR__,
));
$config->add(new AnonymizerConfig(
'table_test',
Expand All @@ -64,6 +65,7 @@ public function testMultipleAnonymizersAtOnce(): void
'iban' => 'my_iban',
'bic' => 'my_bic',
]),
__DIR__,
));

$anonymizator = new Anonymizator($this->getDatabaseSession(), new AnonymizerRegistry(), $config);
Expand Down
5 changes: 2 additions & 3 deletions tests/Functional/Anonymizer/Core/AddressAnonymizerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
namespace DbToolsBundle\PackFrFR\Tests\Functional\Anonymizer\Core;

use MakinaCorpus\DbToolsBundle\Anonymization\Anonymizer\Options;
use MakinaCorpus\DbToolsBundle\Anonymization\Config\AnonymizerConfig;
use MakinaCorpus\DbToolsBundle\Test\FunctionalTestCase;

class AddressAnonymizerTest extends FunctionalTestCase
Expand Down Expand Up @@ -52,7 +51,7 @@ protected function createTestData(): void

public function testAnonymize(): void
{
$anonymizator = $this->createAnonymizatorWithConfig(new AnonymizerConfig(
$anonymizator = $this->createAnonymizatorArbitrary(
'table_test',
'data',
'address',
Expand All @@ -64,7 +63,7 @@ public function testAnonymize(): void
'region' => 'my_region',
'country' => 'my_country',
])
));
);

$this->assertSame(
"Rue Aristide Briand",
Expand Down
9 changes: 4 additions & 5 deletions tests/Functional/Anonymizer/Core/ConstantAnonymizerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
namespace MakinaCorpus\DbToolsBundle\Tests\Functional\Anonymizer\Core;

use MakinaCorpus\DbToolsBundle\Anonymization\Anonymizer\Options;
use MakinaCorpus\DbToolsBundle\Anonymization\Config\AnonymizerConfig;
use MakinaCorpus\DbToolsBundle\Test\FunctionalTestCase;

class ConstantAnonymizerTest extends FunctionalTestCase
Expand Down Expand Up @@ -37,12 +36,12 @@ public function testAnonymize(): void
],
);

$anonymizator = $this->createAnonymizatorWithConfig(new AnonymizerConfig(
$anonymizator = $this->createAnonymizatorArbitrary(
'table_test',
'data',
'constant',
new Options(['value' => 'xxxxxx'])
));
);

$this->assertSame(
"toto1@example.com",
Expand Down Expand Up @@ -86,12 +85,12 @@ public function testAnonymizeWithCustomType(): void
],
);

$anonymizator = $this->createAnonymizatorWithConfig(new AnonymizerConfig(
$anonymizator = $this->createAnonymizatorArbitrary(
'table_test',
'data',
'constant',
new Options(['value' => '2012', 'type' => 'integer'])
));
);

$this->assertSame(
52,
Expand Down
Loading