Skip to content

Commit

Permalink
Merge pull request #23 from superbrave/create-anonymizers
Browse files Browse the repository at this point in the history
Anonymization ready
  • Loading branch information
Jelle authored May 8, 2018
2 parents b19576c + bf941b7 commit 5efd22b
Show file tree
Hide file tree
Showing 29 changed files with 1,735 additions and 185 deletions.
65 changes: 0 additions & 65 deletions Annotation/Anonymize.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
use Doctrine\Common\Annotations\Annotation;
use Doctrine\Common\Annotations\Annotation\Attribute;
use Doctrine\Common\Annotations\Annotation\Attributes;
use Doctrine\Common\Annotations\AnnotationException;

/**
* Annotation to flag an entity field to be anonymized
Expand All @@ -33,54 +32,9 @@
*/
class Anonymize
{
/**
* Alias of TYPE_CONCAT
*/
const TYPE_STRING = 'string';

/**
* Anonymize a string to <columnName>-<primaryKey>
*/
const TYPE_CONCAT = 'concat';

/**
* Anonymize a field by emptying it
* Alias of TYPE_FIXED with an empty value.
*/
const TYPE_TRUNCATE = 'truncate';

/**
* Anonymize an IP field by setting the last bytes to 0
*
* @see https://support.google.com/analytics/answer/2763052
*
* Supports string fields only
*/
const TYPE_IP = 'ip';

/**
* Anonymize by providing a fixed value
* Requires the value property to be given
*/
const TYPE_FIXED = 'fixed';

/**
* Anonymize an email to "<primaryKey>@localhost"
*/
const TYPE_EMAIL = 'email';

/**
* The type used to specify what kind of anonymizer should be used for the field
*
* @Annotation\Enum({
* Anonymize::TYPE_STRING,
* Anonymize::TYPE_IP,
* Anonymize::TYPE_FIXED,
* Anonymize::TYPE_EMAIL,
* Anonymize::TYPE_CONCAT,
* Anonymize::TYPE_TRUNCATE
* })
*
* @var string
*/
public $type;
Expand All @@ -91,23 +45,4 @@ class Anonymize
* @var string
*/
public $value;

/**
* Performs a validation check according to the type given.
* If this type is 'Fixed' then a value has to be passed in as second argument
*
* @param array $arguments Array of arguments passed into the annotation
*
* @throws \Exception
* @throws AnnotationException
*/
public function __construct(array $arguments)
{
$this->type = $arguments['type'];
$this->value = $arguments['value'];

if (self::TYPE_FIXED === $this->type && null === $this->value) {
throw new AnnotationException("'fixed' type requires 'value' property to be set.");
}
}
}
78 changes: 78 additions & 0 deletions Anonymize/Anonymizer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php
/**
* This file is part of the GDPR bundle.
*
* @category Bundle
* @package Gdpr
* @author SuperBrave <info@superbrave.nl>
* @copyright 2018 SuperBrave <info@superbrave.nl>
* @license https://github.com/superbrave/gdpr-bundle/blob/master/LICENSE MIT
* @link https://www.superbrave.nl/
*/

namespace SuperBrave\GdprBundle\Anonymize;

use SuperBrave\GdprBundle\Annotation\AnnotationReader;
use SuperBrave\GdprBundle\Annotation\Anonymize;
use InvalidArgumentException;
use ReflectionException;
use ReflectionClass;

/**
* Class Anonymizer
*
* @package SuperBrave\GdprBundle\Anonymize
*/
class Anonymizer
{
/**
* @var AnnotationReader
*/
private $annotationReader;

/**
* @var PropertyAnonymizer
*/
private $propertyAnonymizer;

/**
* Anonymizer constructor.
*
* @param AnnotationReader $annotationReader The annotation reader that should be used.
* @param PropertyAnonymizer $propertyAnonymizer The property anonymizer.
*/
public function __construct(
AnnotationReader $annotationReader,
PropertyAnonymizer $propertyAnonymizer
) {
$this->annotationReader = $annotationReader;
$this->propertyAnonymizer = $propertyAnonymizer;
}

/**
* Anonymizes the given object which should contain the @see Anonymize annotations.
*
* @param object $object The object to anonymize.
*
* @return void
*
* @throws InvalidArgumentException If argument supplied is not an object.
* @throws ReflectionException If class doesn't exist.
*/
public function anonymize(/*object */$object)
{
if (!is_object($object)) {
throw new InvalidArgumentException(sprintf(
'Invalid argument given "%s" should be of type object.',
gettype($object)
));
}

$reflectionClass = new ReflectionClass($object);
$annotations = $this->annotationReader->getPropertiesWithAnnotation($reflectionClass, Anonymize::class);

foreach ($annotations as $property => $annotation) {
$this->propertyAnonymizer->anonymizeField($object, $property, $annotation);
}
}
}
68 changes: 68 additions & 0 deletions Anonymize/AnonymizerCollection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php
/**
* This file is part of the GDPR bundle.
*
* @category Bundle
* @package Gdpr
* @author SuperBrave <info@superbrave.nl>
* @copyright 2018 SuperBrave <info@superbrave.nl>
* @license https://github.com/superbrave/gdpr-bundle/blob/master/LICENSE MIT
* @link https://www.superbrave.nl/
*/

namespace SuperBrave\GdprBundle\Anonymize;

use LogicException;
use SuperBrave\GdprBundle\Anonymize\Type\AnonymizerInterface;

/**
* Class AnonymizerCollection
*
* @package SuperBrave\GdprBundle\Anonymize
*/
class AnonymizerCollection
{
/**
* Array of anonymizers
*
* @var AnonymizerInterface[]
*/
private $anonymizers = [];

/**
* Adds an anonymizer to the collection.
*
* @param string $type The anonymizer type to be added.
* @param AnonymizerInterface $anonymizer The anonymizer class to be added.
*
* @return void
*
* @throws LogicException On duplicate anonymizer keys.
*/
public function addAnonymizer($type, $anonymizer)
{
if (array_key_exists($type, $this->anonymizers)) {
throw new LogicException(sprintf('Anonymizer %s already exists.', $type));
}

$this->anonymizers[$type] = $anonymizer;
}

/**
* Get an anonymizer by its type from the collection.
*
* @param string $type The anonymizer type to be fetched.
*
* @return AnonymizerInterface
*
* @throws LogicException If the anonymizer type is not registered.
*/
public function getAnonymizer($type)
{
if (!array_key_exists($type, $this->anonymizers)) {
throw new LogicException(sprintf('Anonymizer %s is not registered.', $type));
}

return $this->anonymizers[$type];
}
}
74 changes: 74 additions & 0 deletions Anonymize/PropertyAnonymizer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?php
/**
* This file is part of the GDPR bundle.
*
* @category Bundle
* @package Gdpr
* @author SuperBrave <info@superbrave.nl>
* @copyright 2018 SuperBrave <info@superbrave.nl>
* @license https://github.com/superbrave/gdpr-bundle/blob/master/LICENSE MIT
* @link https://www.superbrave.nl/
*/

namespace SuperBrave\GdprBundle\Anonymize;

use SuperBrave\GdprBundle\Annotation\Anonymize;
use SuperBrave\GdprBundle\Manipulator\PropertyManipulator;

/**
* Class PropertyAnonymizer
*
* @package SuperBrave\GdprBundle\Anonymizer
*/
class PropertyAnonymizer
{
/**
* Property manipulator service
*
* @var PropertyManipulator
*/
private $propertyManipulator;

/**
* The collection of anonymizers
*
* @var AnonymizerCollection
*/
private $anonymizerCollection;

/**
* Constructs the class given the parameters
*
* @param PropertyManipulator $propertyManipulator The PropertyManipulator class used to get the property value
* @param AnonymizerCollection $anonymizerCollection A collection of anonymizers registered by the compiler pass
*/
public function __construct(PropertyManipulator $propertyManipulator, AnonymizerCollection $anonymizerCollection)
{
$this->propertyManipulator = $propertyManipulator;
$this->anonymizerCollection = $anonymizerCollection;
}

/**
* Anonymize the property the annotation is on.
* Takes into account the type specified in the annotation
*
* @param object $object The owner of the property being anonymized
* @param string $property The property being anonymized
* @param Anonymize $annotation The annotation gotten from the object
*
* @return void
*/
public function anonymizeField($object, $property, Anonymize $annotation)
{
$anonymizer = $this->anonymizerCollection->getAnonymizer($annotation->type);

$propertyValue = $this->propertyManipulator->getPropertyValue($object, $property);

$newPropertyValue = $anonymizer->anonymize($propertyValue, array(
'annotationValue' => $annotation->value,
'object' => $object,
));

$this->propertyManipulator->setPropertyValue($object, $property, $newPropertyValue);
}
}
31 changes: 31 additions & 0 deletions Anonymize/Type/AnonymizerInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php
/**
* This file is part of the GDPR bundle.
*
* @category Bundle
* @package Gdpr
* @author SuperBrave <info@superbrave.nl>
* @copyright 2018 SuperBrave <info@superbrave.nl>
* @license https://github.com/superbrave/gdpr-bundle/blob/master/LICENSE MIT
* @link https://www.superbrave.nl/
*/

namespace SuperBrave\GdprBundle\Anonymize\Type;

/**
* Interface AnonymizerInterface
*
* @package SuperBrave\GdprBundle\Anonymize\Type
*/
interface AnonymizerInterface
{
/**
* Anonymizes the given property value.
*
* @param mixed $propertyValue The value of the property.
* @param array $options The options for the anonymizer.
*
* @return mixed
*/
public function anonymize($propertyValue, array $options = []);
}
Loading

0 comments on commit 5efd22b

Please sign in to comment.