feat: full anonymization of buspro xml dumps
This commit is contained in:
@@ -1103,6 +1103,16 @@ php bin/console app:bpn:replay <file> [--dry-run|-d] [--output|-o <file>]
|
|||||||
|
|
||||||
Replays stored XML requests against the API for debugging.
|
Replays stored XML requests against the API for debugging.
|
||||||
|
|
||||||
|
#### app:bpn:xml-anonymize
|
||||||
|
|
||||||
|
```bash
|
||||||
|
php bin/console app:bpn:xml-anonymize <file-or-folder> [<output-file-or-folder>]
|
||||||
|
```
|
||||||
|
|
||||||
|
Anonymizes a single BPN XML dump or all XML dumps in a folder. Request/response
|
||||||
|
pairs are processed together so the anonymized identities stay consistent across
|
||||||
|
both files.
|
||||||
|
|
||||||
#### app:bpn:xml-sync
|
#### app:bpn:xml-sync
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ class BpnXmlAnonymizeCommand extends Command
|
|||||||
protected function configure(): void
|
protected function configure(): void
|
||||||
{
|
{
|
||||||
$this
|
$this
|
||||||
->addArgument('infile', InputArgument::REQUIRED, 'Path to the input XML file')
|
->addArgument('infile', InputArgument::REQUIRED, 'Path to the input XML file or folder')
|
||||||
->addArgument('outfile', InputArgument::OPTIONAL, 'Path to the output XML file (defaults to infile)')
|
->addArgument('outfile', InputArgument::OPTIONAL, 'Path to the output XML file or folder (defaults to infile)')
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,19 +39,31 @@ class BpnXmlAnonymizeCommand extends Command
|
|||||||
$inputFile = (string) $input->getArgument('infile');
|
$inputFile = (string) $input->getArgument('infile');
|
||||||
$outputFile = $input->getArgument('outfile');
|
$outputFile = $input->getArgument('outfile');
|
||||||
|
|
||||||
|
if (true === is_dir($inputFile)) {
|
||||||
|
$targetDirectory = null === $outputFile ? $inputFile : (string) $outputFile;
|
||||||
|
|
||||||
|
return $this->anonymizeDirectory($io, $inputFile, $targetDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
if (false === is_file($inputFile)) {
|
if (false === is_file($inputFile)) {
|
||||||
$io->error(sprintf('Input file not found: %s', $inputFile));
|
$io->error(sprintf('Input file not found: %s', $inputFile));
|
||||||
|
|
||||||
return Command::FAILURE;
|
return Command::FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$targetFile = null === $outputFile ? $inputFile : (string) $outputFile;
|
||||||
|
|
||||||
|
return $this->anonymizeSingleFile($io, $inputFile, $targetFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function anonymizeSingleFile(SymfonyStyle $io, string $inputFile, string $targetFile): int
|
||||||
|
{
|
||||||
if (false === is_readable($inputFile)) {
|
if (false === is_readable($inputFile)) {
|
||||||
$io->error(sprintf('Input file is not readable: %s', $inputFile));
|
$io->error(sprintf('Input file is not readable: %s', $inputFile));
|
||||||
|
|
||||||
return Command::FAILURE;
|
return Command::FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
$targetFile = null === $outputFile ? $inputFile : (string) $outputFile;
|
|
||||||
$this->xmlAnonymizer->resetState();
|
$this->xmlAnonymizer->resetState();
|
||||||
|
|
||||||
$processingResult = $this->anonymizeFile($io, $inputFile, $targetFile, false);
|
$processingResult = $this->anonymizeFile($io, $inputFile, $targetFile, false);
|
||||||
@@ -85,12 +97,120 @@ class BpnXmlAnonymizeCommand extends Command
|
|||||||
$io->note(sprintf('Paired file anonymized: %s -> %s', $pairedInputFile, $pairedTargetFile));
|
$io->note(sprintf('Paired file anonymized: %s -> %s', $pairedInputFile, $pairedTargetFile));
|
||||||
}
|
}
|
||||||
|
|
||||||
$io->success(sprintf(
|
$identityCount = $this->xmlAnonymizer->getLastIdentityCount();
|
||||||
'Anonymized %d persons from %s to %s',
|
if (0 === $identityCount) {
|
||||||
$this->xmlAnonymizer->getLastIdentityCount(),
|
$io->warning(sprintf('No anonymizable person data found in %s', $inputFile));
|
||||||
$inputFile,
|
} else {
|
||||||
$targetFile,
|
$io->success(sprintf(
|
||||||
));
|
'Anonymized %d persons from %s to %s',
|
||||||
|
$identityCount,
|
||||||
|
$inputFile,
|
||||||
|
$targetFile,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Command::SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function anonymizeDirectory(SymfonyStyle $io, string $inputDirectory, string $targetDirectory): int
|
||||||
|
{
|
||||||
|
if (false === is_readable($inputDirectory)) {
|
||||||
|
$io->error(sprintf('Input directory is not readable: %s', $inputDirectory));
|
||||||
|
|
||||||
|
return Command::FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (true === file_exists($targetDirectory) && false === is_dir($targetDirectory)) {
|
||||||
|
$io->error(sprintf('Output path is not a directory: %s', $targetDirectory));
|
||||||
|
|
||||||
|
return Command::FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false === file_exists($targetDirectory) && false === mkdir($targetDirectory, 0777, true) && false === is_dir($targetDirectory)) {
|
||||||
|
$io->error(sprintf('Unable to create output directory: %s', $targetDirectory));
|
||||||
|
|
||||||
|
return Command::FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
$entries = scandir($inputDirectory);
|
||||||
|
if (false === $entries) {
|
||||||
|
$io->error(sprintf('Unable to list input directory: %s', $inputDirectory));
|
||||||
|
|
||||||
|
return Command::FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
$processed = [];
|
||||||
|
$fileCount = 0;
|
||||||
|
$personCount = 0;
|
||||||
|
|
||||||
|
foreach ($entries as $entry) {
|
||||||
|
if ('.' === $entry || '..' === $entry) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$inputPath = $inputDirectory.DIRECTORY_SEPARATOR.$entry;
|
||||||
|
if (false === is_file($inputPath) || false === str_ends_with($entry, '.xml')) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (true === isset($processed[$inputPath])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$pairedInputPath = $this->derivePairedFilename($inputPath);
|
||||||
|
if (null !== $pairedInputPath && true === is_file($pairedInputPath) && false === isset($processed[$pairedInputPath])) {
|
||||||
|
$this->xmlAnonymizer->resetState();
|
||||||
|
|
||||||
|
$targetPath = $targetDirectory.DIRECTORY_SEPARATOR.$entry;
|
||||||
|
$result = $this->anonymizeFile($io, $inputPath, $targetPath, false);
|
||||||
|
if (Command::SUCCESS !== $result) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
$processed[$inputPath] = true;
|
||||||
|
++$fileCount;
|
||||||
|
|
||||||
|
$pairedEntry = basename($pairedInputPath);
|
||||||
|
$pairedTargetPath = $targetDirectory.DIRECTORY_SEPARATOR.$pairedEntry;
|
||||||
|
$result = $this->anonymizeFile($io, $pairedInputPath, $pairedTargetPath, true);
|
||||||
|
if (Command::SUCCESS !== $result) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
$processed[$pairedInputPath] = true;
|
||||||
|
++$fileCount;
|
||||||
|
$personCount += $this->xmlAnonymizer->getLastIdentityCount();
|
||||||
|
|
||||||
|
$io->note(sprintf('Paired file anonymized: %s -> %s', $pairedInputPath, $pairedTargetPath));
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->xmlAnonymizer->resetState();
|
||||||
|
|
||||||
|
$targetPath = $targetDirectory.DIRECTORY_SEPARATOR.$entry;
|
||||||
|
$result = $this->anonymizeFile($io, $inputPath, $targetPath, false);
|
||||||
|
if (Command::SUCCESS !== $result) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
$processed[$inputPath] = true;
|
||||||
|
++$fileCount;
|
||||||
|
$personCount += $this->xmlAnonymizer->getLastIdentityCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
$io->text(sprintf('Processed %d XML files', $fileCount));
|
||||||
|
|
||||||
|
if (0 === $personCount) {
|
||||||
|
$io->warning(sprintf('No anonymizable person data found in %s', $inputDirectory));
|
||||||
|
} else {
|
||||||
|
$io->success(sprintf(
|
||||||
|
'Anonymized %d persons from %s to %s',
|
||||||
|
$personCount,
|
||||||
|
$inputDirectory,
|
||||||
|
$targetDirectory,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
return Command::SUCCESS;
|
return Command::SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,11 +10,41 @@ use Faker\Generator;
|
|||||||
class BpnXmlAnonymizer
|
class BpnXmlAnonymizer
|
||||||
{
|
{
|
||||||
private const SAFE_EMAIL_DOMAIN = 'example.com';
|
private const SAFE_EMAIL_DOMAIN = 'example.com';
|
||||||
|
private const SALUTATIONS = ['Herr', 'Frau', 'Divers'];
|
||||||
|
private const GENDERS = ['M', 'W', 'D'];
|
||||||
|
private const COUNTRY_CODES = ['AT', 'BE', 'CH', 'DE', 'DK', 'ES', 'FR', 'IT', 'NL', 'NO', 'PL', 'SE'];
|
||||||
|
|
||||||
private Generator $faker;
|
private Generator $faker;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array<string, array{firstName: string, lastName: string, street: string, postalCode: string, city: string, email: string, mobilePhone: string}>
|
* @var array<string, array{
|
||||||
|
* firstName: string,
|
||||||
|
* lastName: string,
|
||||||
|
* salutation: string,
|
||||||
|
* title: string,
|
||||||
|
* gender: string,
|
||||||
|
* nationality: string,
|
||||||
|
* birthDate: string,
|
||||||
|
* street: string,
|
||||||
|
* postalCode: string,
|
||||||
|
* city: string,
|
||||||
|
* district: string,
|
||||||
|
* country: string,
|
||||||
|
* email: string,
|
||||||
|
* mobilePhone: string,
|
||||||
|
* phone: string,
|
||||||
|
* newsletter: string,
|
||||||
|
* iban: string,
|
||||||
|
* userName: string,
|
||||||
|
* requestKey: string,
|
||||||
|
* requestPassword: string,
|
||||||
|
* personId: string,
|
||||||
|
* addressId: string,
|
||||||
|
* customerId: string,
|
||||||
|
* height: string,
|
||||||
|
* weight: string,
|
||||||
|
* shoeSize: string
|
||||||
|
* }>
|
||||||
*/
|
*/
|
||||||
private array $identities = [];
|
private array $identities = [];
|
||||||
|
|
||||||
@@ -40,7 +70,7 @@ class BpnXmlAnonymizer
|
|||||||
}
|
}
|
||||||
|
|
||||||
$xpath = new \DOMXPath($document);
|
$xpath = new \DOMXPath($document);
|
||||||
$personNodes = $xpath->query('//anmelder | //teilnehmerliste/teilnehmer | //kundennamen/kunde');
|
$personNodes = $xpath->query('//anfrage | //anmelder | //teilnehmerliste/teilnehmer | //kundennamen/kunde | //adressdaten');
|
||||||
|
|
||||||
if (false === $personNodes) {
|
if (false === $personNodes) {
|
||||||
throw new \RuntimeException('Unable to query person nodes.');
|
throw new \RuntimeException('Unable to query person nodes.');
|
||||||
@@ -54,9 +84,17 @@ class BpnXmlAnonymizer
|
|||||||
$personId = $this->resolvePersonId($personNode, (int) $index);
|
$personId = $this->resolvePersonId($personNode, (int) $index);
|
||||||
$identity = $this->getOrCreateIdentity($personId);
|
$identity = $this->getOrCreateIdentity($personId);
|
||||||
|
|
||||||
|
if ('anfrage' === $personNode->tagName) {
|
||||||
|
$this->replaceRequestFields($personNode, $identity);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$this->replaceNameFields($personNode, $identity);
|
$this->replaceNameFields($personNode, $identity);
|
||||||
$this->replaceEmailFields($personNode, $identity);
|
$this->replaceEmailFields($personNode, $identity);
|
||||||
$this->replaceAddressFields($personNode, $identity);
|
$this->replaceAddressFields($personNode, $identity);
|
||||||
|
$this->replaceDemographicFields($personNode, $identity);
|
||||||
|
$this->replaceFinancialFields($personNode, $identity);
|
||||||
|
$this->replaceMetadataFields($personNode, $identity);
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = $document->saveXML();
|
$result = $document->saveXML();
|
||||||
@@ -80,14 +118,47 @@ class BpnXmlAnonymizer
|
|||||||
|
|
||||||
private function resolvePersonId(\DOMElement $personNode, int $nodeIndex): string
|
private function resolvePersonId(\DOMElement $personNode, int $nodeIndex): string
|
||||||
{
|
{
|
||||||
foreach (['personid', 'idperson', 'idadresseperson'] as $tagName) {
|
if ('anfrage' === $personNode->tagName || 'adressdaten' === $personNode->tagName) {
|
||||||
$child = $this->getDirectChild($personNode, $tagName);
|
$emailNode = $this->getDirectChild($personNode, 'email');
|
||||||
if (null !== $child) {
|
if (null !== $emailNode) {
|
||||||
$value = trim($child->textContent);
|
$emailValue = trim($emailNode->textContent);
|
||||||
if ('' !== $value) {
|
if ('' !== $emailValue) {
|
||||||
return $value;
|
return sprintf('email:%s', mb_strtolower($emailValue));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ('adressdaten' === $personNode->tagName) {
|
||||||
|
$communicationNode = $this->getDirectChild($personNode, 'kommunikation');
|
||||||
|
if (null !== $communicationNode) {
|
||||||
|
$nestedEmailNode = $this->getDirectChild($communicationNode, 'email');
|
||||||
|
if (null !== $nestedEmailNode) {
|
||||||
|
$emailValue = trim($nestedEmailNode->textContent);
|
||||||
|
if ('' !== $emailValue) {
|
||||||
|
return sprintf('email:%s', mb_strtolower($emailValue));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$currentNode = $personNode;
|
||||||
|
while ($currentNode instanceof \DOMElement) {
|
||||||
|
foreach (['personid', 'idperson', 'idadresseperson'] as $tagName) {
|
||||||
|
$child = $this->getDirectChild($currentNode, $tagName);
|
||||||
|
if (null !== $child) {
|
||||||
|
$value = trim($child->textContent);
|
||||||
|
if ('' !== $value) {
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$parentNode = $currentNode->parentNode;
|
||||||
|
if (false === $parentNode instanceof \DOMElement) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$currentNode = $parentNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
$fingerprintKey = $this->buildFingerprintKey($personNode);
|
$fingerprintKey = $this->buildFingerprintKey($personNode);
|
||||||
@@ -161,7 +232,34 @@ class BpnXmlAnonymizer
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array{firstName: string, lastName: string, street: string, postalCode: string, city: string, email: string, mobilePhone: string}
|
* @return array{
|
||||||
|
* firstName: string,
|
||||||
|
* lastName: string,
|
||||||
|
* salutation: string,
|
||||||
|
* title: string,
|
||||||
|
* gender: string,
|
||||||
|
* nationality: string,
|
||||||
|
* birthDate: string,
|
||||||
|
* street: string,
|
||||||
|
* postalCode: string,
|
||||||
|
* city: string,
|
||||||
|
* district: string,
|
||||||
|
* country: string,
|
||||||
|
* email: string,
|
||||||
|
* mobilePhone: string,
|
||||||
|
* phone: string,
|
||||||
|
* newsletter: string,
|
||||||
|
* iban: string,
|
||||||
|
* userName: string,
|
||||||
|
* requestKey: string,
|
||||||
|
* requestPassword: string,
|
||||||
|
* personId: string,
|
||||||
|
* addressId: string,
|
||||||
|
* customerId: string,
|
||||||
|
* height: string,
|
||||||
|
* weight: string,
|
||||||
|
* shoeSize: string
|
||||||
|
* }
|
||||||
*/
|
*/
|
||||||
private function getOrCreateIdentity(string $personId): array
|
private function getOrCreateIdentity(string $personId): array
|
||||||
{
|
{
|
||||||
@@ -169,25 +267,63 @@ class BpnXmlAnonymizer
|
|||||||
return $this->identities[$personId];
|
return $this->identities[$personId];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$identityIndex = \count($this->identities) + 1;
|
||||||
$firstName = $this->faker->firstName();
|
$firstName = $this->faker->firstName();
|
||||||
$lastName = $this->faker->lastName();
|
$lastName = $this->faker->lastName();
|
||||||
|
$salutation = 'Divers';
|
||||||
|
$title = '';
|
||||||
|
$gender = 'D';
|
||||||
|
$nationality = 'XX';
|
||||||
|
$birthDate = '01.01.1980';
|
||||||
|
|
||||||
$street = sprintf('%s %s', $this->faker->streetName(), $this->faker->buildingNumber());
|
$street = sprintf('%s %s', $this->faker->streetName(), $this->faker->buildingNumber());
|
||||||
$postalCode = $this->faker->postcode();
|
$postalCode = $this->faker->postcode();
|
||||||
$city = $this->faker->city();
|
$city = $this->faker->city();
|
||||||
$mobilePhone = $this->faker->numerify('01#########');
|
$district = '';
|
||||||
|
$country = 'XX';
|
||||||
|
$mobilePhone = sprintf('01%09d', $identityIndex);
|
||||||
|
$phone = sprintf('02%09d', $identityIndex);
|
||||||
|
$newsletter = 'False';
|
||||||
|
$iban = sprintf('DE%020d', $identityIndex);
|
||||||
|
$userName = sprintf('anon-user-%d', $identityIndex);
|
||||||
|
$requestKey = str_pad((string) $identityIndex, 32, '0', STR_PAD_LEFT);
|
||||||
|
$requestPassword = str_pad((string) ($identityIndex + 1), 32, '0', STR_PAD_LEFT);
|
||||||
|
$personIdValue = (string) (700000 + $identityIndex);
|
||||||
|
$addressIdValue = (string) (800000 + $identityIndex);
|
||||||
|
$customerIdValue = (string) (900000 + $identityIndex);
|
||||||
|
$height = '170';
|
||||||
|
$weight = '70';
|
||||||
|
$shoeSize = '42';
|
||||||
|
|
||||||
$emailLocal = sprintf('%s.%s', $this->slug($firstName), $this->slug($lastName));
|
$email = sprintf('%s@%s', $userName, self::SAFE_EMAIL_DOMAIN);
|
||||||
$email = sprintf('%s@%s', $emailLocal, self::SAFE_EMAIL_DOMAIN);
|
|
||||||
|
|
||||||
$this->identities[$personId] = [
|
$this->identities[$personId] = [
|
||||||
'firstName' => $firstName,
|
'firstName' => $firstName,
|
||||||
'lastName' => $lastName,
|
'lastName' => $lastName,
|
||||||
|
'salutation' => $salutation,
|
||||||
|
'title' => $title,
|
||||||
|
'gender' => $gender,
|
||||||
|
'nationality' => $nationality,
|
||||||
|
'birthDate' => $birthDate,
|
||||||
'street' => $street,
|
'street' => $street,
|
||||||
'postalCode' => $postalCode,
|
'postalCode' => $postalCode,
|
||||||
'city' => $city,
|
'city' => $city,
|
||||||
|
'district' => $district,
|
||||||
|
'country' => $country,
|
||||||
'email' => strtolower($email),
|
'email' => strtolower($email),
|
||||||
'mobilePhone' => $mobilePhone,
|
'mobilePhone' => $mobilePhone,
|
||||||
|
'phone' => $phone,
|
||||||
|
'newsletter' => $newsletter,
|
||||||
|
'iban' => $iban,
|
||||||
|
'userName' => $userName,
|
||||||
|
'requestKey' => $requestKey,
|
||||||
|
'requestPassword' => $requestPassword,
|
||||||
|
'personId' => $personIdValue,
|
||||||
|
'addressId' => $addressIdValue,
|
||||||
|
'customerId' => $customerIdValue,
|
||||||
|
'height' => $height,
|
||||||
|
'weight' => $weight,
|
||||||
|
'shoeSize' => $shoeSize,
|
||||||
];
|
];
|
||||||
|
|
||||||
return $this->identities[$personId];
|
return $this->identities[$personId];
|
||||||
@@ -215,6 +351,10 @@ class BpnXmlAnonymizer
|
|||||||
if (true === $personNode->hasAttribute('vorname')) {
|
if (true === $personNode->hasAttribute('vorname')) {
|
||||||
$personNode->setAttribute('vorname', $identity['firstName']);
|
$personNode->setAttribute('vorname', $identity['firstName']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (true === $personNode->hasAttribute('id') && 'kunde' === $personNode->tagName) {
|
||||||
|
$personNode->setAttribute('id', $identity['customerId']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -224,6 +364,13 @@ class BpnXmlAnonymizer
|
|||||||
{
|
{
|
||||||
$communicationNode = $this->getDirectChild($personNode, 'kommunikation');
|
$communicationNode = $this->getDirectChild($personNode, 'kommunikation');
|
||||||
if (null === $communicationNode) {
|
if (null === $communicationNode) {
|
||||||
|
if ('anfrage' === $personNode->tagName) {
|
||||||
|
$emailNode = $this->getDirectChild($personNode, 'email');
|
||||||
|
if (null !== $emailNode) {
|
||||||
|
$emailNode->nodeValue = $identity['email'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,6 +383,16 @@ class BpnXmlAnonymizer
|
|||||||
if (null !== $mobileNode) {
|
if (null !== $mobileNode) {
|
||||||
$mobileNode->nodeValue = $identity['mobilePhone'];
|
$mobileNode->nodeValue = $identity['mobilePhone'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$phoneNode = $this->getDirectChild($communicationNode, 'telefonprivat');
|
||||||
|
if (null !== $phoneNode) {
|
||||||
|
$phoneNode->nodeValue = $identity['phone'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$newsletterNode = $this->getDirectChild($communicationNode, 'newsletter');
|
||||||
|
if (null !== $newsletterNode) {
|
||||||
|
$newsletterNode->nodeValue = $identity['newsletter'];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -262,6 +419,130 @@ class BpnXmlAnonymizer
|
|||||||
if (null !== $cityNode) {
|
if (null !== $cityNode) {
|
||||||
$cityNode->nodeValue = $identity['city'];
|
$cityNode->nodeValue = $identity['city'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$districtNode = $this->getDirectChild($addressNode, 'ortsteil');
|
||||||
|
if (null !== $districtNode) {
|
||||||
|
$districtNode->nodeValue = $identity['district'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$countryNode = $this->getDirectChild($addressNode, 'land');
|
||||||
|
if (null !== $countryNode) {
|
||||||
|
$countryNode->nodeValue = $identity['country'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$addressIdNode = $this->getDirectChild($addressNode, 'id');
|
||||||
|
if (null !== $addressIdNode) {
|
||||||
|
$addressIdNode->nodeValue = $identity['addressId'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function replaceDemographicFields(\DOMElement $personNode, array $identity): void
|
||||||
|
{
|
||||||
|
$salutationNode = $this->getDirectChild($personNode, 'anrede');
|
||||||
|
if (null !== $salutationNode) {
|
||||||
|
$salutationNode->nodeValue = $identity['salutation'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$titleNode = $this->getDirectChild($personNode, 'titel');
|
||||||
|
if (null !== $titleNode) {
|
||||||
|
$titleNode->nodeValue = $identity['title'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$genderNode = $this->getDirectChild($personNode, 'geschlecht');
|
||||||
|
if (null !== $genderNode) {
|
||||||
|
$genderNode->nodeValue = $identity['gender'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$nationalityNode = $this->getDirectChild($personNode, 'nationalitaet');
|
||||||
|
if (null !== $nationalityNode) {
|
||||||
|
$nationalityNode->nodeValue = $identity['nationality'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$birthDateNode = $this->getDirectChild($personNode, 'geburtsdatum');
|
||||||
|
if (null !== $birthDateNode) {
|
||||||
|
$birthDateNode->nodeValue = $identity['birthDate'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$heightNode = $this->getDirectChild($personNode, 'sonstiges1');
|
||||||
|
if (null !== $heightNode) {
|
||||||
|
$heightNode->nodeValue = $identity['height'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$weightNode = $this->getDirectChild($personNode, 'sonstiges2');
|
||||||
|
if (null !== $weightNode) {
|
||||||
|
$weightNode->nodeValue = $identity['weight'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$shoeSizeNode = $this->getDirectChild($personNode, 'sonstiges3');
|
||||||
|
if (null !== $shoeSizeNode) {
|
||||||
|
$shoeSizeNode->nodeValue = $identity['shoeSize'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function replaceFinancialFields(\DOMElement $personNode, array $identity): void
|
||||||
|
{
|
||||||
|
$bankNode = $this->getDirectChild($personNode, 'bankverbindung');
|
||||||
|
if (null === $bankNode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ibanNode = $this->getDirectChild($bankNode, 'iban');
|
||||||
|
if (null !== $ibanNode) {
|
||||||
|
$ibanNode->nodeValue = $identity['iban'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function replaceMetadataFields(\DOMElement $personNode, array $identity): void
|
||||||
|
{
|
||||||
|
if (true === $personNode->hasAttribute('id')) {
|
||||||
|
if ('kunde' === $personNode->tagName) {
|
||||||
|
$personNode->setAttribute('id', $identity['customerId']);
|
||||||
|
} elseif ('teilnehmer' === $personNode->tagName || 'anmelder' === $personNode->tagName) {
|
||||||
|
$personNode->setAttribute('id', $identity['personId']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function replaceRequestFields(\DOMElement $personNode, array $identity): void
|
||||||
|
{
|
||||||
|
$userNode = $this->getDirectChild($personNode, 'user');
|
||||||
|
if (null !== $userNode) {
|
||||||
|
$userNode->nodeValue = $identity['userName'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$keyNode = $this->getDirectChild($personNode, 'key');
|
||||||
|
if (null !== $keyNode) {
|
||||||
|
$keyNode->nodeValue = $identity['requestKey'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$emailNode = $this->getDirectChild($personNode, 'email');
|
||||||
|
if (null !== $emailNode) {
|
||||||
|
$emailNode->nodeValue = $identity['email'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$passwordNode = $this->getDirectChild($personNode, 'passwort');
|
||||||
|
if (null !== $passwordNode) {
|
||||||
|
$passwordNode->nodeValue = $identity['requestPassword'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function findAncestorDirectChild(\DOMElement $personNode, string $ancestorTagName, string $childTagName): ?\DOMElement
|
||||||
|
{
|
||||||
|
$currentNode = $personNode;
|
||||||
|
while ($currentNode instanceof \DOMElement) {
|
||||||
|
if ($ancestorTagName === $currentNode->tagName) {
|
||||||
|
return $this->getDirectChild($currentNode, $childTagName);
|
||||||
|
}
|
||||||
|
|
||||||
|
$parentNode = $currentNode->parentNode;
|
||||||
|
if (false === $parentNode instanceof \DOMElement) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$currentNode = $parentNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getDirectChild(\DOMElement $parent, string $name): ?\DOMElement
|
private function getDirectChild(\DOMElement $parent, string $name): ?\DOMElement
|
||||||
|
|||||||
@@ -0,0 +1,193 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Tests\Command;
|
||||||
|
|
||||||
|
use App\Command\BpnXmlAnonymizeCommand;
|
||||||
|
use App\Service\BpnXmlAnonymizer;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Tester\CommandTester;
|
||||||
|
|
||||||
|
class BpnXmlAnonymizeCommandTest extends TestCase
|
||||||
|
{
|
||||||
|
/** @var array<int, string> */
|
||||||
|
private array $tempDirectories = [];
|
||||||
|
|
||||||
|
protected function tearDown(): void
|
||||||
|
{
|
||||||
|
foreach ($this->tempDirectories as $directory) {
|
||||||
|
$this->removeDirectory($directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->tempDirectories = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSingleFileStillAnonymizesPairedResponseFile(): void
|
||||||
|
{
|
||||||
|
$inputDir = $this->createTempDirectory();
|
||||||
|
$outputDir = $this->createTempDirectory();
|
||||||
|
$inputFile = $inputDir.'/travel_request.xml';
|
||||||
|
$pairedInputFile = $inputDir.'/travel_response.xml';
|
||||||
|
$targetFile = $outputDir.'/travel_request.xml';
|
||||||
|
$pairedTargetFile = $outputDir.'/travel_response.xml';
|
||||||
|
|
||||||
|
file_put_contents($inputFile, '<xml>travel-request</xml>');
|
||||||
|
file_put_contents($pairedInputFile, '<xml>travel-response</xml>');
|
||||||
|
|
||||||
|
$calls = [];
|
||||||
|
$lastIdentityCount = 0;
|
||||||
|
$anonymizer = $this->createMock(BpnXmlAnonymizer::class);
|
||||||
|
$anonymizer->expects(self::once())
|
||||||
|
->method('resetState')
|
||||||
|
->willReturnCallback(static function () use (&$calls, &$lastIdentityCount): void {
|
||||||
|
$calls[] = ['resetState'];
|
||||||
|
$lastIdentityCount = 0;
|
||||||
|
});
|
||||||
|
$anonymizer->expects(self::exactly(2))
|
||||||
|
->method('anonymize')
|
||||||
|
->willReturnCallback(function (string $xml, bool $resetState) use (&$calls, &$lastIdentityCount): string {
|
||||||
|
$calls[] = ['anonymize', trim($xml), $resetState];
|
||||||
|
$lastIdentityCount = true === $resetState ? 1 : 2;
|
||||||
|
|
||||||
|
return sprintf('ANON:%s', trim($xml));
|
||||||
|
});
|
||||||
|
$anonymizer->method('getLastIdentityCount')
|
||||||
|
->willReturnCallback(function () use (&$lastIdentityCount): int {
|
||||||
|
return $lastIdentityCount;
|
||||||
|
});
|
||||||
|
|
||||||
|
$tester = new CommandTester(new BpnXmlAnonymizeCommand($anonymizer));
|
||||||
|
$tester->execute([
|
||||||
|
'infile' => $inputFile,
|
||||||
|
'outfile' => $targetFile,
|
||||||
|
]);
|
||||||
|
|
||||||
|
self::assertSame(Command::SUCCESS, $tester->getStatusCode());
|
||||||
|
self::assertSame('ANON:<xml>travel-request</xml>', trim((string) file_get_contents($targetFile)));
|
||||||
|
self::assertSame('ANON:<xml>travel-response</xml>', trim((string) file_get_contents($pairedTargetFile)));
|
||||||
|
self::assertSame([
|
||||||
|
['resetState'],
|
||||||
|
['anonymize', '<xml>travel-request</xml>', true],
|
||||||
|
['anonymize', '<xml>travel-response</xml>', false],
|
||||||
|
], $calls);
|
||||||
|
self::assertStringContainsString('Paired file anonymized', $tester->getDisplay());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDirectoryInputAnonymizesAllPairsIntoOutputDirectory(): void
|
||||||
|
{
|
||||||
|
$inputDir = $this->createTempDirectory();
|
||||||
|
$outputDir = $this->createTempDirectory().'/anonymized';
|
||||||
|
|
||||||
|
file_put_contents($inputDir.'/alpha_request.xml', '<xml>alpha-request</xml>');
|
||||||
|
file_put_contents($inputDir.'/alpha_response.xml', '<xml>alpha-response</xml>');
|
||||||
|
file_put_contents($inputDir.'/beta_request.xml', '<xml>beta-request</xml>');
|
||||||
|
file_put_contents($inputDir.'/beta_response.xml', '<xml>beta-response</xml>');
|
||||||
|
|
||||||
|
$calls = [];
|
||||||
|
$lastIdentityCount = 0;
|
||||||
|
$anonymizer = $this->createMock(BpnXmlAnonymizer::class);
|
||||||
|
$anonymizer->expects(self::exactly(2))
|
||||||
|
->method('resetState')
|
||||||
|
->willReturnCallback(static function () use (&$calls, &$lastIdentityCount): void {
|
||||||
|
$calls[] = ['resetState'];
|
||||||
|
$lastIdentityCount = 0;
|
||||||
|
});
|
||||||
|
$anonymizer->expects(self::exactly(4))
|
||||||
|
->method('anonymize')
|
||||||
|
->willReturnCallback(function (string $xml, bool $resetState) use (&$calls, &$lastIdentityCount): string {
|
||||||
|
$content = trim($xml);
|
||||||
|
$calls[] = ['anonymize', $content, $resetState];
|
||||||
|
|
||||||
|
if (str_contains($content, 'request')) {
|
||||||
|
$lastIdentityCount = true === $resetState ? 1 : 0;
|
||||||
|
} else {
|
||||||
|
$lastIdentityCount = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sprintf('ANON:%s', $content);
|
||||||
|
});
|
||||||
|
$anonymizer->method('getLastIdentityCount')
|
||||||
|
->willReturnCallback(function () use (&$lastIdentityCount): int {
|
||||||
|
return $lastIdentityCount;
|
||||||
|
});
|
||||||
|
|
||||||
|
$tester = new CommandTester(new BpnXmlAnonymizeCommand($anonymizer));
|
||||||
|
$tester->execute([
|
||||||
|
'infile' => $inputDir,
|
||||||
|
'outfile' => $outputDir,
|
||||||
|
]);
|
||||||
|
|
||||||
|
self::assertSame(Command::SUCCESS, $tester->getStatusCode());
|
||||||
|
self::assertSame('ANON:<xml>alpha-request</xml>', trim((string) file_get_contents($outputDir.'/alpha_request.xml')));
|
||||||
|
self::assertSame('ANON:<xml>alpha-response</xml>', trim((string) file_get_contents($outputDir.'/alpha_response.xml')));
|
||||||
|
self::assertSame('ANON:<xml>beta-request</xml>', trim((string) file_get_contents($outputDir.'/beta_request.xml')));
|
||||||
|
self::assertSame('ANON:<xml>beta-response</xml>', trim((string) file_get_contents($outputDir.'/beta_response.xml')));
|
||||||
|
self::assertSame([
|
||||||
|
['resetState'],
|
||||||
|
['anonymize', '<xml>alpha-request</xml>', true],
|
||||||
|
['anonymize', '<xml>alpha-response</xml>', false],
|
||||||
|
['resetState'],
|
||||||
|
['anonymize', '<xml>beta-request</xml>', true],
|
||||||
|
['anonymize', '<xml>beta-response</xml>', false],
|
||||||
|
], $calls);
|
||||||
|
self::assertStringContainsString('Processed 4 XML files', $tester->getDisplay());
|
||||||
|
self::assertStringContainsString('Anonymized 4 persons', $tester->getDisplay());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSingleFileWithoutSupportedPersonNodesWarnsInsteadOfClaimingSuccess(): void
|
||||||
|
{
|
||||||
|
$inputDir = $this->createTempDirectory();
|
||||||
|
$inputFile = $inputDir.'/meta.xml';
|
||||||
|
$targetFile = $inputDir.'/meta-out.xml';
|
||||||
|
|
||||||
|
file_put_contents($inputFile, '<?xml version="1.0" encoding="UTF-8"?><root><meta>hello</meta></root>');
|
||||||
|
|
||||||
|
$tester = new CommandTester(new BpnXmlAnonymizeCommand(new BpnXmlAnonymizer()));
|
||||||
|
$tester->execute([
|
||||||
|
'infile' => $inputFile,
|
||||||
|
'outfile' => $targetFile,
|
||||||
|
]);
|
||||||
|
|
||||||
|
self::assertSame(Command::SUCCESS, $tester->getStatusCode());
|
||||||
|
self::assertStringContainsString('No anonymizable person data found', $tester->getDisplay());
|
||||||
|
self::assertStringNotContainsString('Anonymized 0 persons', $tester->getDisplay());
|
||||||
|
self::assertFileExists($targetFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createTempDirectory(): string
|
||||||
|
{
|
||||||
|
$directory = sys_get_temp_dir().'/bpn-xml-anonymize-'.bin2hex(random_bytes(6));
|
||||||
|
if (false === mkdir($directory, 0777, true) && false === is_dir($directory)) {
|
||||||
|
self::fail(sprintf('Unable to create temporary directory: %s', $directory));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->tempDirectories[] = $directory;
|
||||||
|
|
||||||
|
return $directory;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function removeDirectory(string $directory): void
|
||||||
|
{
|
||||||
|
if (false === is_dir($directory)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$items = new \RecursiveIteratorIterator(
|
||||||
|
new \RecursiveDirectoryIterator($directory, \FilesystemIterator::SKIP_DOTS),
|
||||||
|
\RecursiveIteratorIterator::CHILD_FIRST,
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($items as $item) {
|
||||||
|
if ($item->isDir()) {
|
||||||
|
rmdir($item->getPathname());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
unlink($item->getPathname());
|
||||||
|
}
|
||||||
|
|
||||||
|
rmdir($directory);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -41,7 +41,10 @@ class DbAnonymizeCommandTest extends TestCase
|
|||||||
$tester->execute([]);
|
$tester->execute([]);
|
||||||
|
|
||||||
self::assertSame(Command::SUCCESS, $tester->getStatusCode());
|
self::assertSame(Command::SUCCESS, $tester->getStatusCode());
|
||||||
self::assertStringContainsString('Anonymized 1 users, 2 newsletter consents, 3 newsletter opt-in requests, and 4 booking drafts.', $tester->getDisplay());
|
self::assertStringContainsString(
|
||||||
|
'Anonymized 1 users, 2 newsletter consents, 3 newsletter opt-in requests, and 4 booking drafts.',
|
||||||
|
$this->normalizeConsoleOutput($tester->getDisplay()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function createCommand(DatabaseAnonymizer $anonymizer, string $environment): DbAnonymizeCommand
|
private function createCommand(DatabaseAnonymizer $anonymizer, string $environment): DbAnonymizeCommand
|
||||||
@@ -52,4 +55,9 @@ class DbAnonymizeCommandTest extends TestCase
|
|||||||
$environment,
|
$environment,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function normalizeConsoleOutput(string $output): string
|
||||||
|
{
|
||||||
|
return trim((string) preg_replace('/\s+/', ' ', $output));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,41 +15,41 @@ class BpnXmlAnonymizerTest extends TestCase
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<anfrage>
|
<anfrage>
|
||||||
<anmelder>
|
<anmelder>
|
||||||
<name>Schlegelmilch</name>
|
<name>Example</name>
|
||||||
<vorname>Mandy</vorname>
|
<vorname>Ava</vorname>
|
||||||
<anschrift>
|
<anschrift>
|
||||||
<strasse>Am Jägersteig 19</strasse>
|
<strasse>Testallee 7</strasse>
|
||||||
<plz>40724</plz>
|
<plz>10115</plz>
|
||||||
<ort>Hilden</ort>
|
<ort>Berlin</ort>
|
||||||
</anschrift>
|
</anschrift>
|
||||||
<kommunikation>
|
<kommunikation>
|
||||||
<email>[email protected]</email>
|
<email>[email protected]</email>
|
||||||
<telefonmobil>02212722760</telefonmobil>
|
<telefonmobil>015500000001</telefonmobil>
|
||||||
</kommunikation>
|
</kommunikation>
|
||||||
<idadresseperson>255752</idadresseperson>
|
<idadresseperson>111111</idadresseperson>
|
||||||
</anmelder>
|
</anmelder>
|
||||||
<teilnehmerliste>
|
<teilnehmerliste>
|
||||||
<teilnehmer id="1">
|
<teilnehmer id="1">
|
||||||
<name>Schlegelmilch</name>
|
<name>Example</name>
|
||||||
<vorname>Mandy</vorname>
|
<vorname>Ava</vorname>
|
||||||
<anschrift>
|
<anschrift>
|
||||||
<strasse>Am Jägersteig 19</strasse>
|
<strasse>Testallee 7</strasse>
|
||||||
<plz>40724</plz>
|
<plz>10115</plz>
|
||||||
<ort>Hilden</ort>
|
<ort>Berlin</ort>
|
||||||
</anschrift>
|
</anschrift>
|
||||||
<kommunikation>
|
<kommunikation>
|
||||||
<email>[email protected]</email>
|
<email>[email protected]</email>
|
||||||
<telefonmobil>02212722760</telefonmobil>
|
<telefonmobil>015500000001</telefonmobil>
|
||||||
</kommunikation>
|
</kommunikation>
|
||||||
<idadresseperson>255752</idadresseperson>
|
<idadresseperson>111111</idadresseperson>
|
||||||
</teilnehmer>
|
</teilnehmer>
|
||||||
<teilnehmer id="2">
|
<teilnehmer id="2">
|
||||||
<name>Danielzik</name>
|
<name>Second</name>
|
||||||
<vorname>Leon</vorname>
|
<vorname>Ben</vorname>
|
||||||
<kommunikation>
|
<kommunikation>
|
||||||
<email>[email protected]</email>
|
<email>[email protected]</email>
|
||||||
</kommunikation>
|
</kommunikation>
|
||||||
<idadresseperson>306886</idadresseperson>
|
<idadresseperson>222222</idadresseperson>
|
||||||
</teilnehmer>
|
</teilnehmer>
|
||||||
</teilnehmerliste>
|
</teilnehmerliste>
|
||||||
</anfrage>
|
</anfrage>
|
||||||
@@ -64,19 +64,141 @@ XML;
|
|||||||
$xpath = new \DOMXPath($document);
|
$xpath = new \DOMXPath($document);
|
||||||
|
|
||||||
$applicantName = trim((string) $xpath->evaluate('string(//anmelder/name)'));
|
$applicantName = trim((string) $xpath->evaluate('string(//anmelder/name)'));
|
||||||
$participantOneName = trim((string) $xpath->evaluate('string(//teilnehmer[@id="1"]/name)'));
|
$participantOneName = trim((string) $xpath->evaluate('string(//teilnehmer[1]/name)'));
|
||||||
$participantOneEmail = trim((string) $xpath->evaluate('string(//teilnehmer[@id="1"]/kommunikation/email)'));
|
$participantOneEmail = trim((string) $xpath->evaluate('string(//teilnehmer[1]/kommunikation/email)'));
|
||||||
$applicantMobilePhone = trim((string) $xpath->evaluate('string(//anmelder/kommunikation/telefonmobil)'));
|
$applicantMobilePhone = trim((string) $xpath->evaluate('string(//anmelder/kommunikation/telefonmobil)'));
|
||||||
$participantOneMobilePhone = trim((string) $xpath->evaluate('string(//teilnehmer[@id="1"]/kommunikation/telefonmobil)'));
|
$participantOneMobilePhone = trim((string) $xpath->evaluate('string(//teilnehmer[1]/kommunikation/telefonmobil)'));
|
||||||
$participantTwoName = trim((string) $xpath->evaluate('string(//teilnehmer[@id="2"]/name)'));
|
$participantTwoName = trim((string) $xpath->evaluate('string(//teilnehmer[2]/name)'));
|
||||||
|
|
||||||
$this->assertNotSame('Schlegelmilch', $applicantName);
|
$this->assertNotSame('Example', $applicantName);
|
||||||
$this->assertSame($applicantName, $participantOneName);
|
$this->assertSame($applicantName, $participantOneName);
|
||||||
$this->assertStringEndsWith('@example.com', $participantOneEmail);
|
$this->assertSame('anon-user-2@example.com', $participantOneEmail);
|
||||||
$this->assertNotSame('02212722760', $participantOneMobilePhone);
|
$this->assertSame('01000000002', $participantOneMobilePhone);
|
||||||
$this->assertSame($applicantMobilePhone, $participantOneMobilePhone);
|
$this->assertSame($applicantMobilePhone, $participantOneMobilePhone);
|
||||||
$this->assertNotSame($participantOneName, $participantTwoName);
|
$this->assertNotSame($participantOneName, $participantTwoName);
|
||||||
$this->assertSame(2, $anonymizer->getLastIdentityCount());
|
$this->assertSame(3, $anonymizer->getLastIdentityCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAnonymizeReplacesAdressdatenRequestAndResponseConsistently(): void
|
||||||
|
{
|
||||||
|
$requestXml = <<<'XML'
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<anfrage>
|
||||||
|
<user>portal-user</user>
|
||||||
|
<key>aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</key>
|
||||||
|
<satz typ="KUNDENKONTO"/>
|
||||||
|
<art>Adressdaten</art>
|
||||||
|
<email>[email protected]</email>
|
||||||
|
<passwort>bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb</passwort>
|
||||||
|
</anfrage>
|
||||||
|
XML;
|
||||||
|
|
||||||
|
$responseXml = <<<'XML'
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ergebnis>
|
||||||
|
<satz typ="KUNDENKONTO"/>
|
||||||
|
<art>Adressdaten</art>
|
||||||
|
<idadresse>654321</idadresse>
|
||||||
|
<idperson>123456</idperson>
|
||||||
|
<adressdaten>
|
||||||
|
<name>Input</name>
|
||||||
|
<vorname>Person</vorname>
|
||||||
|
<anrede>Herr</anrede>
|
||||||
|
<titel>Prof.</titel>
|
||||||
|
<geschlecht>M</geschlecht>
|
||||||
|
<geburtsdatum>16.04.1972</geburtsdatum>
|
||||||
|
<nationalitaet>NL</nationalitaet>
|
||||||
|
<anschrift>
|
||||||
|
<id>444444</id>
|
||||||
|
<strasse>Beispielweg 57</strasse>
|
||||||
|
<plz>42853</plz>
|
||||||
|
<ort>Musterstadt</ort>
|
||||||
|
<ortsteil>Innenstadt</ortsteil>
|
||||||
|
<land>D</land>
|
||||||
|
</anschrift>
|
||||||
|
<kommunikation>
|
||||||
|
<telefonmobil>017700000000</telefonmobil>
|
||||||
|
<email>[email protected]</email>
|
||||||
|
<newsletter>False</newsletter>
|
||||||
|
<telefonprivat>021900000000</telefonprivat>
|
||||||
|
</kommunikation>
|
||||||
|
<bankverbindung>
|
||||||
|
<iban>DE02120300000000202051</iban>
|
||||||
|
</bankverbindung>
|
||||||
|
<sonstiges1>179-197</sonstiges1>
|
||||||
|
<sonstiges2>79-94</sonstiges2>
|
||||||
|
<sonstiges3>44</sonstiges3>
|
||||||
|
</adressdaten>
|
||||||
|
</ergebnis>
|
||||||
|
XML;
|
||||||
|
|
||||||
|
$anonymizer = new BpnXmlAnonymizer();
|
||||||
|
$anonymizedRequest = $anonymizer->anonymize($requestXml, true);
|
||||||
|
$anonymizedResponse = $anonymizer->anonymize($responseXml, false);
|
||||||
|
|
||||||
|
$requestDocument = new \DOMDocument();
|
||||||
|
$this->assertTrue($requestDocument->loadXML($anonymizedRequest));
|
||||||
|
$requestXpath = new \DOMXPath($requestDocument);
|
||||||
|
$requestUser = trim((string) $requestXpath->evaluate('string(//user)'));
|
||||||
|
$requestEmail = trim((string) $requestXpath->evaluate('string(//email)'));
|
||||||
|
$requestKey = trim((string) $requestXpath->evaluate('string(//key)'));
|
||||||
|
$requestPassword = trim((string) $requestXpath->evaluate('string(//passwort)'));
|
||||||
|
|
||||||
|
$responseDocument = new \DOMDocument();
|
||||||
|
$this->assertTrue($responseDocument->loadXML($anonymizedResponse));
|
||||||
|
$responseXpath = new \DOMXPath($responseDocument);
|
||||||
|
$responseEmail = trim((string) $responseXpath->evaluate('string(//adressdaten/kommunikation/email)'));
|
||||||
|
$responseName = trim((string) $responseXpath->evaluate('string(//adressdaten/name)'));
|
||||||
|
$responseFirstName = trim((string) $responseXpath->evaluate('string(//adressdaten/vorname)'));
|
||||||
|
$responseSalutation = trim((string) $responseXpath->evaluate('string(//adressdaten/anrede)'));
|
||||||
|
$responseTitle = trim((string) $responseXpath->evaluate('string(//adressdaten/titel)'));
|
||||||
|
$responseGender = trim((string) $responseXpath->evaluate('string(//adressdaten/geschlecht)'));
|
||||||
|
$responseBirthDate = trim((string) $responseXpath->evaluate('string(//adressdaten/geburtsdatum)'));
|
||||||
|
$responseNationality = trim((string) $responseXpath->evaluate('string(//adressdaten/nationalitaet)'));
|
||||||
|
$responseStreet = trim((string) $responseXpath->evaluate('string(//adressdaten/anschrift/strasse)'));
|
||||||
|
$responsePostalCode = trim((string) $responseXpath->evaluate('string(//adressdaten/anschrift/plz)'));
|
||||||
|
$responseCity = trim((string) $responseXpath->evaluate('string(//adressdaten/anschrift/ort)'));
|
||||||
|
$responseDistrict = trim((string) $responseXpath->evaluate('string(//adressdaten/anschrift/ortsteil)'));
|
||||||
|
$responseCountry = trim((string) $responseXpath->evaluate('string(//adressdaten/anschrift/land)'));
|
||||||
|
$responseAddressId = trim((string) $responseXpath->evaluate('string(//adressdaten/anschrift/id)'));
|
||||||
|
$responseMobilePhone = trim((string) $responseXpath->evaluate('string(//adressdaten/kommunikation/telefonmobil)'));
|
||||||
|
$responsePhone = trim((string) $responseXpath->evaluate('string(//adressdaten/kommunikation/telefonprivat)'));
|
||||||
|
$responseNewsletter = trim((string) $responseXpath->evaluate('string(//adressdaten/kommunikation/newsletter)'));
|
||||||
|
$responseIban = trim((string) $responseXpath->evaluate('string(//adressdaten/bankverbindung/iban)'));
|
||||||
|
$responseHeight = trim((string) $responseXpath->evaluate('string(//adressdaten/sonstiges1)'));
|
||||||
|
$responseWeight = trim((string) $responseXpath->evaluate('string(//adressdaten/sonstiges2)'));
|
||||||
|
$responseShoeSize = trim((string) $responseXpath->evaluate('string(//adressdaten/sonstiges3)'));
|
||||||
|
$responseRootPersonId = trim((string) $responseXpath->evaluate('string(//idperson)'));
|
||||||
|
$responseRootAddressId = trim((string) $responseXpath->evaluate('string(//idadresse)'));
|
||||||
|
|
||||||
|
$this->assertSame('anon-user-1', $requestUser);
|
||||||
|
$this->assertSame('[email protected]', $requestEmail);
|
||||||
|
$this->assertSame('00000000000000000000000000000001', $requestKey);
|
||||||
|
$this->assertSame('00000000000000000000000000000002', $requestPassword);
|
||||||
|
$this->assertSame($requestEmail, $responseEmail);
|
||||||
|
$this->assertNotSame('Input', $responseName);
|
||||||
|
$this->assertNotSame('Person', $responseFirstName);
|
||||||
|
$this->assertSame('Divers', $responseSalutation);
|
||||||
|
$this->assertSame('', $responseTitle);
|
||||||
|
$this->assertSame('D', $responseGender);
|
||||||
|
$this->assertSame('01.01.1980', $responseBirthDate);
|
||||||
|
$this->assertSame('XX', $responseNationality);
|
||||||
|
$this->assertNotSame('Beispielweg 57', $responseStreet);
|
||||||
|
$this->assertNotSame('42853', $responsePostalCode);
|
||||||
|
$this->assertNotSame('Musterstadt', $responseCity);
|
||||||
|
$this->assertSame('', $responseDistrict);
|
||||||
|
$this->assertSame('XX', $responseCountry);
|
||||||
|
$this->assertSame('800001', $responseAddressId);
|
||||||
|
$this->assertSame('01000000001', $responseMobilePhone);
|
||||||
|
$this->assertSame('02000000001', $responsePhone);
|
||||||
|
$this->assertSame('False', $responseNewsletter);
|
||||||
|
$this->assertSame('DE00000000000000000001', $responseIban);
|
||||||
|
$this->assertSame('170', $responseHeight);
|
||||||
|
$this->assertSame('70', $responseWeight);
|
||||||
|
$this->assertSame('42', $responseShoeSize);
|
||||||
|
$this->assertSame('123456', $responseRootPersonId);
|
||||||
|
$this->assertSame('654321', $responseRootAddressId);
|
||||||
|
$this->assertSame(1, $anonymizer->getLastIdentityCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testAnonymizeReplacesKundeAttributes(): void
|
public function testAnonymizeReplacesKundeAttributes(): void
|
||||||
@@ -84,14 +206,14 @@ XML;
|
|||||||
$xml = <<<'XML'
|
$xml = <<<'XML'
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<ergebnis>
|
<ergebnis>
|
||||||
<vorgaenge>
|
<vorgaenge>
|
||||||
<vorgang>
|
<vorgang>
|
||||||
<kundennamen>
|
<kundennamen>
|
||||||
<kunde id="1" art="Anmelder/Teilnehmer" name="Fromme" vorname="Björn"></kunde>
|
<kunde id="1" art="Anmelder/Teilnehmer" name="Alpha" vorname="Ada"></kunde>
|
||||||
<kunde id="2" art="Teilnehmer" name="Rütten" vorname="Manuela"></kunde>
|
<kunde id="2" art="Teilnehmer" name="Beta" vorname="Ben"></kunde>
|
||||||
</kundennamen>
|
</kundennamen>
|
||||||
</vorgang>
|
</vorgang>
|
||||||
</vorgaenge>
|
</vorgaenge>
|
||||||
</ergebnis>
|
</ergebnis>
|
||||||
XML;
|
XML;
|
||||||
|
|
||||||
@@ -103,11 +225,15 @@ XML;
|
|||||||
|
|
||||||
$xpath = new \DOMXPath($document);
|
$xpath = new \DOMXPath($document);
|
||||||
|
|
||||||
$firstCustomerLastName = trim((string) $xpath->evaluate('string(//kunde[@id="1"]/@name)'));
|
$firstCustomerLastName = trim((string) $xpath->evaluate('string(//kundennamen/kunde[1]/@name)'));
|
||||||
$firstCustomerFirstName = trim((string) $xpath->evaluate('string(//kunde[@id="1"]/@vorname)'));
|
$firstCustomerFirstName = trim((string) $xpath->evaluate('string(//kundennamen/kunde[1]/@vorname)'));
|
||||||
|
$firstCustomerId = trim((string) $xpath->evaluate('string(//kundennamen/kunde[1]/@id)'));
|
||||||
|
$secondCustomerId = trim((string) $xpath->evaluate('string(//kundennamen/kunde[2]/@id)'));
|
||||||
|
|
||||||
$this->assertNotSame('Fromme', $firstCustomerLastName);
|
$this->assertNotSame('Alpha', $firstCustomerLastName);
|
||||||
$this->assertNotSame('Björn', $firstCustomerFirstName);
|
$this->assertNotSame('Ada', $firstCustomerFirstName);
|
||||||
|
$this->assertSame('900001', $firstCustomerId);
|
||||||
|
$this->assertSame('900002', $secondCustomerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testAnonymizeThrowsOnInvalidXml(): void
|
public function testAnonymizeThrowsOnInvalidXml(): void
|
||||||
@@ -125,28 +251,28 @@ XML;
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<anfrage>
|
<anfrage>
|
||||||
<anmelder>
|
<anmelder>
|
||||||
<name>Schlegelmilch</name>
|
<name>Shared</name>
|
||||||
<vorname>Mandy</vorname>
|
<vorname>Casey</vorname>
|
||||||
<anschrift>
|
<anschrift>
|
||||||
<strasse>Am Jägersteig 19</strasse>
|
<strasse>Sharedstrasse 1</strasse>
|
||||||
<plz>40724</plz>
|
<plz>50667</plz>
|
||||||
<ort>Hilden</ort>
|
<ort>Koeln</ort>
|
||||||
</anschrift>
|
</anschrift>
|
||||||
<kommunikation>
|
<kommunikation>
|
||||||
<email>[email protected]</email>
|
<email>[email protected]</email>
|
||||||
</kommunikation>
|
</kommunikation>
|
||||||
</anmelder>
|
</anmelder>
|
||||||
<teilnehmerliste>
|
<teilnehmerliste>
|
||||||
<teilnehmer id="1">
|
<teilnehmer id="1">
|
||||||
<name>Schlegelmilch</name>
|
<name>Shared</name>
|
||||||
<vorname>Mandy</vorname>
|
<vorname>Casey</vorname>
|
||||||
<anschrift>
|
<anschrift>
|
||||||
<strasse>Am Jägersteig 19</strasse>
|
<strasse>Sharedstrasse 1</strasse>
|
||||||
<plz>40724</plz>
|
<plz>50667</plz>
|
||||||
<ort>Hilden</ort>
|
<ort>Koeln</ort>
|
||||||
</anschrift>
|
</anschrift>
|
||||||
<kommunikation>
|
<kommunikation>
|
||||||
<email>[email protected]</email>
|
<email>[email protected]</email>
|
||||||
</kommunikation>
|
</kommunikation>
|
||||||
</teilnehmer>
|
</teilnehmer>
|
||||||
</teilnehmerliste>
|
</teilnehmerliste>
|
||||||
@@ -162,10 +288,10 @@ XML;
|
|||||||
$xpath = new \DOMXPath($document);
|
$xpath = new \DOMXPath($document);
|
||||||
|
|
||||||
$applicantName = trim((string) $xpath->evaluate('string(//anmelder/name)'));
|
$applicantName = trim((string) $xpath->evaluate('string(//anmelder/name)'));
|
||||||
$participantName = trim((string) $xpath->evaluate('string(//teilnehmer[@id="1"]/name)'));
|
$participantName = trim((string) $xpath->evaluate('string(//teilnehmer[1]/name)'));
|
||||||
|
|
||||||
$this->assertSame($applicantName, $participantName);
|
$this->assertSame($applicantName, $participantName);
|
||||||
$this->assertSame(1, $anonymizer->getLastIdentityCount());
|
$this->assertSame(2, $anonymizer->getLastIdentityCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testAnonymizeCanReuseIdentityAcrossMultipleXmlDocuments(): void
|
public function testAnonymizeCanReuseIdentityAcrossMultipleXmlDocuments(): void
|
||||||
@@ -174,12 +300,12 @@ XML;
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<anfrage>
|
<anfrage>
|
||||||
<anmelder>
|
<anmelder>
|
||||||
<name>Schlegelmilch</name>
|
<name>Reusable</name>
|
||||||
<vorname>Mandy</vorname>
|
<vorname>Riley</vorname>
|
||||||
<kommunikation>
|
<kommunikation>
|
||||||
<email>[email protected]</email>
|
<email>[email protected]</email>
|
||||||
</kommunikation>
|
</kommunikation>
|
||||||
<idadresseperson>255752</idadresseperson>
|
<idadresseperson>333333</idadresseperson>
|
||||||
</anmelder>
|
</anmelder>
|
||||||
</anfrage>
|
</anfrage>
|
||||||
XML;
|
XML;
|
||||||
@@ -189,12 +315,12 @@ XML;
|
|||||||
<ergebnis>
|
<ergebnis>
|
||||||
<teilnehmerliste>
|
<teilnehmerliste>
|
||||||
<teilnehmer id="1">
|
<teilnehmer id="1">
|
||||||
<name>Schlegelmilch</name>
|
<name>Reusable</name>
|
||||||
<vorname>Mandy</vorname>
|
<vorname>Riley</vorname>
|
||||||
<kommunikation>
|
<kommunikation>
|
||||||
<email>[email protected]</email>
|
<email>[email protected]</email>
|
||||||
</kommunikation>
|
</kommunikation>
|
||||||
<idadresseperson>255752</idadresseperson>
|
<idadresseperson>333333</idadresseperson>
|
||||||
</teilnehmer>
|
</teilnehmer>
|
||||||
</teilnehmerliste>
|
</teilnehmerliste>
|
||||||
</ergebnis>
|
</ergebnis>
|
||||||
@@ -212,9 +338,108 @@ XML;
|
|||||||
$responseDocument = new \DOMDocument();
|
$responseDocument = new \DOMDocument();
|
||||||
$this->assertTrue($responseDocument->loadXML($anonymizedResponse));
|
$this->assertTrue($responseDocument->loadXML($anonymizedResponse));
|
||||||
$responseXpath = new \DOMXPath($responseDocument);
|
$responseXpath = new \DOMXPath($responseDocument);
|
||||||
$responseName = trim((string) $responseXpath->evaluate('string(//teilnehmer[@id="1"]/name)'));
|
$responseName = trim((string) $responseXpath->evaluate('string(//teilnehmer[1]/name)'));
|
||||||
|
|
||||||
$this->assertSame($requestName, $responseName);
|
$this->assertSame($requestName, $responseName);
|
||||||
|
$this->assertSame(2, $anonymizer->getLastIdentityCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAnonymizeReplacesAdressdatenBlocksInCustomerResponses(): void
|
||||||
|
{
|
||||||
|
$xml = <<<'XML'
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ergebnis>
|
||||||
|
<satz typ="KUNDENKONTO"/>
|
||||||
|
<art>Adressdaten</art>
|
||||||
|
<idadresse>654321</idadresse>
|
||||||
|
<idperson>123456</idperson>
|
||||||
|
<adressdaten>
|
||||||
|
<name>Input</name>
|
||||||
|
<vorname>Person</vorname>
|
||||||
|
<anrede>Frau</anrede>
|
||||||
|
<titel>Dr.</titel>
|
||||||
|
<geschlecht>W</geschlecht>
|
||||||
|
<geburtsdatum>01.02.1990</geburtsdatum>
|
||||||
|
<nationalitaet>DE</nationalitaet>
|
||||||
|
<anschrift>
|
||||||
|
<id>444444</id>
|
||||||
|
<strasse>Beispielweg 12</strasse>
|
||||||
|
<plz>12345</plz>
|
||||||
|
<ort>Musterstadt</ort>
|
||||||
|
<ortsteil>Altstadt</ortsteil>
|
||||||
|
<land>DE</land>
|
||||||
|
</anschrift>
|
||||||
|
<kommunikation>
|
||||||
|
<telefonmobil>01701234567</telefonmobil>
|
||||||
|
<email>[email protected]</email>
|
||||||
|
<newsletter>True</newsletter>
|
||||||
|
<telefonprivat>02101234567</telefonprivat>
|
||||||
|
</kommunikation>
|
||||||
|
<bankverbindung>
|
||||||
|
<iban>DE02120300000000202051</iban>
|
||||||
|
</bankverbindung>
|
||||||
|
<sonstiges1>180</sonstiges1>
|
||||||
|
<sonstiges2>75</sonstiges2>
|
||||||
|
<sonstiges3>43</sonstiges3>
|
||||||
|
</adressdaten>
|
||||||
|
</ergebnis>
|
||||||
|
XML;
|
||||||
|
|
||||||
|
$anonymizer = new BpnXmlAnonymizer();
|
||||||
|
$result = $anonymizer->anonymize($xml);
|
||||||
|
|
||||||
|
$document = new \DOMDocument();
|
||||||
|
$this->assertTrue($document->loadXML($result));
|
||||||
|
|
||||||
|
$xpath = new \DOMXPath($document);
|
||||||
|
|
||||||
|
$lastName = trim((string) $xpath->evaluate('string(//adressdaten/name)'));
|
||||||
|
$firstName = trim((string) $xpath->evaluate('string(//adressdaten/vorname)'));
|
||||||
|
$salutation = trim((string) $xpath->evaluate('string(//adressdaten/anrede)'));
|
||||||
|
$title = trim((string) $xpath->evaluate('string(//adressdaten/titel)'));
|
||||||
|
$gender = trim((string) $xpath->evaluate('string(//adressdaten/geschlecht)'));
|
||||||
|
$birthDate = trim((string) $xpath->evaluate('string(//adressdaten/geburtsdatum)'));
|
||||||
|
$nationality = trim((string) $xpath->evaluate('string(//adressdaten/nationalitaet)'));
|
||||||
|
$street = trim((string) $xpath->evaluate('string(//adressdaten/anschrift/strasse)'));
|
||||||
|
$postalCode = trim((string) $xpath->evaluate('string(//adressdaten/anschrift/plz)'));
|
||||||
|
$city = trim((string) $xpath->evaluate('string(//adressdaten/anschrift/ort)'));
|
||||||
|
$district = trim((string) $xpath->evaluate('string(//adressdaten/anschrift/ortsteil)'));
|
||||||
|
$country = trim((string) $xpath->evaluate('string(//adressdaten/anschrift/land)'));
|
||||||
|
$addressId = trim((string) $xpath->evaluate('string(//adressdaten/anschrift/id)'));
|
||||||
|
$email = trim((string) $xpath->evaluate('string(//adressdaten/kommunikation/email)'));
|
||||||
|
$mobilePhone = trim((string) $xpath->evaluate('string(//adressdaten/kommunikation/telefonmobil)'));
|
||||||
|
$phone = trim((string) $xpath->evaluate('string(//adressdaten/kommunikation/telefonprivat)'));
|
||||||
|
$newsletter = trim((string) $xpath->evaluate('string(//adressdaten/kommunikation/newsletter)'));
|
||||||
|
$iban = trim((string) $xpath->evaluate('string(//adressdaten/bankverbindung/iban)'));
|
||||||
|
$height = trim((string) $xpath->evaluate('string(//adressdaten/sonstiges1)'));
|
||||||
|
$weight = trim((string) $xpath->evaluate('string(//adressdaten/sonstiges2)'));
|
||||||
|
$shoeSize = trim((string) $xpath->evaluate('string(//adressdaten/sonstiges3)'));
|
||||||
|
$personId = trim((string) $xpath->evaluate('string(//idperson)'));
|
||||||
|
$addressIdRoot = trim((string) $xpath->evaluate('string(//idadresse)'));
|
||||||
|
|
||||||
|
$this->assertNotSame('Input', $lastName);
|
||||||
|
$this->assertNotSame('Person', $firstName);
|
||||||
|
$this->assertSame('Divers', $salutation);
|
||||||
|
$this->assertSame('', $title);
|
||||||
|
$this->assertSame('D', $gender);
|
||||||
|
$this->assertSame('01.01.1980', $birthDate);
|
||||||
|
$this->assertSame('XX', $nationality);
|
||||||
|
$this->assertNotSame('Beispielweg 12', $street);
|
||||||
|
$this->assertNotSame('12345', $postalCode);
|
||||||
|
$this->assertNotSame('Musterstadt', $city);
|
||||||
|
$this->assertSame('', $district);
|
||||||
|
$this->assertSame('XX', $country);
|
||||||
|
$this->assertSame('800001', $addressId);
|
||||||
|
$this->assertSame('[email protected]', $email);
|
||||||
|
$this->assertSame('01000000001', $mobilePhone);
|
||||||
|
$this->assertSame('02000000001', $phone);
|
||||||
|
$this->assertSame('False', $newsletter);
|
||||||
|
$this->assertSame('DE00000000000000000001', $iban);
|
||||||
|
$this->assertSame('170', $height);
|
||||||
|
$this->assertSame('70', $weight);
|
||||||
|
$this->assertSame('42', $shoeSize);
|
||||||
|
$this->assertSame('123456', $personId);
|
||||||
|
$this->assertSame('654321', $addressIdRoot);
|
||||||
$this->assertSame(1, $anonymizer->getLastIdentityCount());
|
$this->assertSame(1, $anonymizer->getLastIdentityCount());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user