Skip to content

Commit

Permalink
#90 - LoremIpsumAnonymizer - Add customization options + documentation (
Browse files Browse the repository at this point in the history
  • Loading branch information
SimonMellerin committed Mar 8, 2024
1 parent 589a9f6 commit 120e95b
Show file tree
Hide file tree
Showing 7 changed files with 305 additions and 16 deletions.
2 changes: 1 addition & 1 deletion docs/content/anonymization/command.md
Expand Up @@ -67,7 +67,7 @@ Let's assume the environment we have besides *production* is called *another_env

## Options

You can specify the behaviour of the `db-tools:anonymize`command with some options detailed below.
You can specify the behavior of the `db-tools:anonymize`command with some options detailed below.

### Anonymizing local database

Expand Down
66 changes: 66 additions & 0 deletions docs/content/anonymization/core-anonymizers.md
Expand Up @@ -424,6 +424,72 @@ customer:
```
:::

## LoremIpsumAnonymizer

Replace a text with some *lorem ipsum*.
Default behavior is to generate a single paragraph.

Available options:
- `paragraphs`: (int) number of paragraphs to generate,
- `words`: (int) number of words to generate
(could not be used in combination with `paragraphs` option),
- `html`: (bool) surround each paragraph with `<p>`, default is false.
- `sample_count`: (int) how many different values to use (default is 100).

::: code-group
```php [Attribute]
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use MakinaCorpus\DbToolsBundle\Attribute\Anonymize;

#[ORM\Entity()]
#[ORM\Table(name: 'customer')]
class Customer
{
// ...

#[ORM\Column(length: 255)]
#[Anonymize('lorem')] // [!code ++]
private ?string $message = null;

#[ORM\Column(length: 255)]
// Will generate 10 paragraphs, each one surrounded by a html `<p>` tag
#[Anonymize('lorem', ['paragraphs' => 10, 'html' => true])] // [!code ++]
private ?string $message = null;

#[ORM\Column(length: 255)]
// Will only generate 5 words
#[Anonymize('lorem', ['words' => 5])] // [!code ++]
private ?string $message = null;

// ...
}
```

```yaml [YAML]
# config/anonymization.yaml

customer:
message: lorem

customer:
# Will generate 10 paragraphs, each one surrounded by a html `<p>` tag
message:
anonymizer: lorem
options:
paragaphs: 10
html: true

customer:
# Will only generate 5 words
message:
anonymizer: lorem
options: {words: 5}
#...
```
:::

## AddressAnonymizer

This *Anonymizer* is multicolumn. It let you anonymize, at once, mutiple columns on one table
Expand Down
6 changes: 3 additions & 3 deletions docs/content/backup_restore.md
Expand Up @@ -19,7 +19,7 @@ backup files (i.e. files that have passed their expiration date).
console db-tools:backup
```

You can specify the behaviour of the command with some options detailed below.
You can specify the behavior of the command with some options detailed below.

### Connection

Expand Down Expand Up @@ -89,7 +89,7 @@ to restore your database from an existing backup files.
console db-tools:restore
```

You can specify the behaviour of the command with some options detailed below.
You can specify the behavior of the command with some options detailed below.

### Connection

Expand Down Expand Up @@ -147,7 +147,7 @@ will be added to the [default options](./configuration#default-binary-options).

### Ignoring default options

If necessary, [default options](./configuration#default-binary-options) can be
If necessary, [default options](./configuration#default-binary-options) can be
ignored for a restoration by using the `--ignore-default-options` option:

```sh
Expand Down
2 changes: 1 addition & 1 deletion docs/content/configuration.md
@@ -1,6 +1,6 @@
# Bundle configuration

The *DbToolsBundle* let you configure some of its behaviours. As with any classic Symfony Bundle,
The *DbToolsBundle* let you configure some of its behaviors. As with any classic Symfony Bundle,
all will take place in the `config/packages/db_tools.yaml` file.

:::tip
Expand Down
45 changes: 37 additions & 8 deletions src/Anonymization/Anonymizer/Core/LoremIpsumAnonymizer.php
Expand Up @@ -10,19 +10,17 @@

/**
* Generates lorem ipsum text.
*
* Available options:
* - paragraphs: (int) number of paragraphs, default is 1,
* - html: (bool) surround each paragraph with <p>, default is false.
* - sample_count: (int) how many different values to use (default is 100).
*/
#[AsAnonymizer(
name: 'lorem',
pack: 'core',
description: <<<TXT
Replace a text with lorem ipsum.
Replace a text with some lorem ipsum.
Default behavior is to generate a single paragraph.
Available options:
- 'paragraphs': (int) number of paragraphs, default is 1,
- 'paragraphs': (int) number of paragraphs to generate,
- 'words': (int) number of words to generate
(could not be used in combination with 'paragraphs' option),
- 'html': (bool) surround each paragraph with <p>, default is false.
- 'sample_count': (int) how many different values to use (default is 100).
TXT
Expand All @@ -34,10 +32,29 @@ class LoremIpsumAnonymizer extends AbstractEnumAnonymizer
*/
protected function getSample(): array
{
$tag = $this->options->get('html') ? 'p' : null;
$tag = $this->options->get('html', false) ? 'p' : null;
$sampleCount = (int) $this->options->get('sample_count', 100);
$paragraphs = (int) $this->options->get('paragraphs', 1);

if ($this->options->has('words')) {
$words = (int) $this->options->get('words');
if ($words <= 0) {
throw new \InvalidArgumentException("'words' should be greater than 0.");
}

return $this->generateWordsSample($words, $sampleCount);
} else {
$paragraphs = (int) $this->options->get('paragraphs', 1);
if ($paragraphs <= 0) {
throw new \InvalidArgumentException("'paragraphs' should be greater than 0.");
}

return $this->generateParagraphsSample($paragraphs, $sampleCount, $tag);
}
}

private function generateParagraphsSample(int $paragraphs, int $sampleCount, ?string $tag): array
{
$loremIpsum = new LoremIpsum();

$ret = [];
Expand All @@ -47,4 +64,16 @@ protected function getSample(): array

return $ret;
}

private function generateWordsSample(int $words, int $sampleCount): array
{
$loremIpsum = new LoremIpsum();

$ret = [];
for ($i = 0; $i < $sampleCount; ++$i) {
$ret[] = $loremIpsum->words($words);
}

return $ret;
}
}
194 changes: 194 additions & 0 deletions tests/Functional/Anonymizer/Core/LoremIpsumAnonymizerTest.php
@@ -0,0 +1,194 @@
<?php

declare(strict_types=1);

namespace MakinaCorpus\DbToolsBundle\Tests\Functional\Anonymizer\Core;

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

class LoremIpsumAnonymizerTest extends FunctionalTestCase
{
/** @before */
protected function createTestData(): void
{
$this->createOrReplaceTable(
'table_test',
[
'id' => 'integer',
'data' => 'text',
],
[
[
'id' => '1',
'data' => 'test1',
],
[
'id' => '2',
'data' => 'test2',
],
[
'id' => '3',
'data' => 'test3',
],
[
'id' => '4',
],
],
);
}

public function testAnonymizeWithDefaultOptions(): void
{
$config = new AnonymizationConfig();
$config->add(new AnonymizerConfig(
'table_test',
'data',
'lorem',
new Options()
));

$anonymizator = new Anonymizator(
$this->getConnection(),
new AnonymizerRegistry(),
$config
);

$this->assertSame(
'test1',
$this->getConnection()->executeQuery('select data from table_test where id = 1')->fetchOne(),
);

foreach ($anonymizator->anonymize() as $message) {
}

$datas = $this->getConnection()->executeQuery('select data from table_test order by id asc')->fetchFirstColumn();

// Default behavior is to create on paragraph, without HTML '<p>' tag.
$data = $datas[0];
$this->assertNotNull($data);
$this->assertNotSame('test1', $data);
$this->assertStringNotContainsString('<p>', $data);
$this->assertStringNotContainsString('</p>', $data);

$data = $datas[1];
$this->assertNotNull($data);
$this->assertNotSame('test2', $data);
$this->assertStringNotContainsString('<p>', $data);
$this->assertStringNotContainsString('</p>', $data);

$data = $datas[2];
$this->assertNotNull($data);
$this->assertNotSame('test3', $data);
$this->assertStringNotContainsString('<p>', $data);
$this->assertStringNotContainsString('</p>', $data);

$this->assertNull($datas[3]);

$this->assertGreaterThan(1, \array_unique($datas), 'All generated values are different.');
}

public function testAnonymizeWithParagraphsAndTag(): void
{
$config = new AnonymizationConfig();
$config->add(new AnonymizerConfig(
'table_test',
'data',
'lorem',
new Options([
'paragraphs' => 5,
'html' => true
])
));

$anonymizator = new Anonymizator(
$this->getConnection(),
new AnonymizerRegistry(),
$config
);

$this->assertSame(
'test1',
$this->getConnection()->executeQuery('select data from table_test where id = 1')->fetchOne(),
);

foreach ($anonymizator->anonymize() as $message) {
}

$datas = $this->getConnection()->executeQuery('select data from table_test order by id asc')->fetchFirstColumn();

$data = $datas[0];
$this->assertNotNull($data);
$this->assertNotSame('test1', $data);
$this->assertEquals(5, \substr_count($data, '<p>'));
$this->assertEquals(5, \substr_count($data, '</p>'));

$data = $datas[1];
$this->assertNotNull($data);
$this->assertEquals(5, \substr_count($data, '<p>'));
$this->assertEquals(5, \substr_count($data, '</p>'));

$data = $datas[2];
$this->assertNotNull($data);
$this->assertEquals(5, \substr_count($data, '<p>'));
$this->assertEquals(5, \substr_count($data, '</p>'));

$this->assertNull($datas[3]);

$this->assertGreaterThan(1, \array_unique($datas), 'All generated values are different.');
}

public function testAnonymizeWithWords(): void
{
$config = new AnonymizationConfig();
$config->add(new AnonymizerConfig(
'table_test',
'data',
'lorem',
new Options(['words' => 5])
));

$anonymizator = new Anonymizator(
$this->getConnection(),
new AnonymizerRegistry(),
$config
);

$this->assertSame(
'test1',
$this->getConnection()->executeQuery('select data from table_test where id = 1')->fetchOne(),
);

foreach ($anonymizator->anonymize() as $message) {
}

$datas = $this->getConnection()->executeQuery('select data from table_test order by id asc')->fetchFirstColumn();

$data = $datas[0];
$this->assertNotNull($data);
$this->assertNotSame('test1', $data);
$this->assertStringNotContainsString('<p>', $data);
$this->assertStringNotContainsString('</p>', $data);
$this->assertEquals(5, \str_word_count($data));

$data = $datas[1];
$this->assertNotNull($data);
$this->assertStringNotContainsString('<p>', $data);
$this->assertStringNotContainsString('</p>', $data);
$this->assertEquals(5, \str_word_count($data));

$data = $datas[2];
$this->assertNotNull($data);
$this->assertStringNotContainsString('<p>', $data);
$this->assertStringNotContainsString('</p>', $data);
$this->assertEquals(5, \str_word_count($data));

$this->assertNull($datas[3]);

$this->assertGreaterThan(1, \array_unique($datas), 'All generated values are different.');
}
}

0 comments on commit 120e95b

Please sign in to comment.