class RightToBeForgottenEntityTraversal in General Data Protection Regulation 8
Same name and namespace in other branches
- 8.2 modules/gdpr_tasks/src/Traversal/RightToBeForgottenEntityTraversal.php \Drupal\gdpr_tasks\Traversal\RightToBeForgottenEntityTraversal
- 3.0.x modules/gdpr_tasks/src/Traversal/RightToBeForgottenEntityTraversal.php \Drupal\gdpr_tasks\Traversal\RightToBeForgottenEntityTraversal
Entity traversal used for Right to be Forgotten requests.
@package Drupal\gdpr_tasks\Traversal
Hierarchy
- class \Drupal\gdpr_fields\EntityTraversal implements EntityTraversalInterface
- class \Drupal\gdpr_tasks\Traversal\RightToBeForgottenEntityTraversal
Expanded class hierarchy of RightToBeForgottenEntityTraversal
1 string reference to 'RightToBeForgottenEntityTraversal'
- gdpr_tasks.services.yml in modules/
gdpr_tasks/ gdpr_tasks.services.yml - modules/gdpr_tasks/gdpr_tasks.services.yml
File
- modules/
gdpr_tasks/ src/ Traversal/ RightToBeForgottenEntityTraversal.php, line 24
Namespace
Drupal\gdpr_tasks\TraversalView source
class RightToBeForgottenEntityTraversal extends EntityTraversal {
/**
* Factory used to retrieve anonymizer to use on a particular field.
*
* @var \Drupal\anonymizer\Anonymizer\AnonymizerFactory
*/
private $anonymizerFactory;
/**
* Drupal module handler for hooks.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
private $moduleHandler;
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, EntityInterface $base_entity) {
return new static($container
->get('entity_type.manager'), $container
->get('entity_field.manager'), $base_entity, $container
->get('module_handler'), $container
->get('anonymizer.anonymizer_factory'));
}
/**
* {@inheritdoc}
*/
public function __construct(EntityTypeManagerInterface $entityTypeManager, EntityFieldManagerInterface $entityFieldManager, $base_entity, ModuleHandlerInterface $module_handler, AnonymizerFactory $anonymizer_factory) {
parent::__construct($entityTypeManager, $entityFieldManager, $base_entity);
$this->moduleHandler = $module_handler;
$this->anonymizerFactory = $anonymizer_factory;
}
/**
* {@inheritdoc}
*/
public function traverseEntity(EntityInterface $entity) {
$this->results = [
'errors' => [],
'successes' => [],
'failures' => [],
'log' => [],
'to_delete' => [],
];
$this
->doTraversalRecursive($entity);
}
/**
* {@inheritdoc}
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Core\Entity\EntityStorageException
*/
protected function processEntity(FieldableEntityInterface $entity, GdprFieldConfigEntity $config, $row_id, GdprField $parent_config = NULL) {
$entity_success = TRUE;
$entity_type = $entity
->getEntityTypeId();
$fields = $this->entityFieldManager
->getFieldDefinitions($entity_type, $entity
->bundle());
$field_configs = $config
->getFieldsForBundle($entity
->bundle());
// Re-load a fresh copy of the entity from storage so we don't
// end up modifying any other references to the entity in memory.
/* @var \Drupal\Core\Entity\FieldableEntityInterface $entity */
$entity = $this->entityTypeManager
->getStorage($entity_type)
->loadUnchanged($entity
->id());
foreach ($fields as $field_id => $field_definition) {
$field_config = isset($field_configs[$field_id]) ? $field_configs[$field_id] : NULL;
// If the field is not configured, not enabled,
// or not enabled for RTF, then skip it.
if ($field_config === NULL || !$field_config->enabled || !in_array($field_config->rtf, [
'anonymize',
'remove',
'maybe',
])) {
continue;
}
$mode = $field_config->rtf;
$field = $entity
->get($field_id);
$success = TRUE;
$msg = NULL;
$anonymizer = '';
if ($mode == 'anonymize') {
list($success, $msg, $anonymizer) = $this
->anonymize($field, $field_definition, $field_config);
}
elseif ($mode == 'remove') {
list($success, $msg, $should_delete) = $this
->remove($field, $field_config, $entity);
}
if ($success === TRUE) {
$this->results['log'][] = [
'entity_id' => $entity
->id(),
'entity_type' => $entity_type . '.' . $entity
->bundle(),
'field_name' => $field
->getName(),
'action' => $mode,
'anonymizer' => $anonymizer,
];
}
else {
// Could not anonymize/remove field. Record to errors list.
// Prevent entity from being saved.
$entity_success = FALSE;
$this->results['errors'][] = $msg;
}
}
if ($entity_success) {
if (isset($should_delete) && $should_delete) {
$this->results['to_delete'][] = $entity;
}
else {
$this->results['successes'][] = $entity;
}
}
else {
$this->results['failures'][] = $entity;
}
}
/**
* Removes the field value.
*
* @param \Drupal\Core\Field\FieldItemListInterface $field
* The current field to process.
* @param \Drupal\gdpr_fields\Entity\GdprField $field_config
* The current field config.
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity to remove.
*
* @return array
* First element is success boolean, second element is the error message,
* third element is boolean indicating whether the whole
* entity should be deleted.
*/
private function remove(FieldItemListInterface $field, GdprField $field_config, EntityInterface $entity) {
try {
$should_delete = FALSE;
// If this is the entity's ID, treat the removal as remove the entire
// entity.
$entity_type = $entity
->getEntityType();
$error_message = NULL;
if ($entity_type
->getKey('id') == $field
->getName()) {
$should_delete = TRUE;
return [
TRUE,
NULL,
$should_delete,
];
}
elseif (!$field_config
->propertyCanBeRemoved($field
->getFieldDefinition(), $error_message)) {
return [
FALSE,
$error_message,
$should_delete,
];
}
// Otherwise assume we can simply clear the field.
$field
->setValue(NULL);
return [
TRUE,
NULL,
$should_delete,
];
} catch (ReadOnlyException $e) {
return [
FALSE,
$e
->getMessage(),
$should_delete,
];
}
}
/**
* Runs anonymize functionality against a field.
*
* @param \Drupal\Core\Field\FieldItemListInterface $field
* The field to anonymize.
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
* The field definition.
* @param \Drupal\gdpr_fields\Entity\GdprField $field_config
* GDPR field configuration.
*
* @return array
* First element is success boolean, second element is the error message.
*/
private function anonymize(FieldItemListInterface $field, FieldDefinitionInterface $field_definition, GdprField $field_config) {
$anonymizer_id = $this
->getAnonymizerId($field_definition, $field_config);
if (!$anonymizer_id) {
return [
FALSE,
"Could not anonymize field {$field->getName()}. Please consider changing this field from 'anonymize' to 'remove', or register a custom anonymizer.",
NULL,
];
}
try {
$anonymizer = $this->anonymizerFactory
->get($anonymizer_id);
$field
->setValue($anonymizer
->anonymize($field->value, $field));
return [
TRUE,
NULL,
$anonymizer_id,
];
} catch (\Exception $e) {
return [
FALSE,
$e
->getMessage(),
NULL,
];
}
}
/**
* Gets the ID of the anonymizer plugin to use on this field.
*
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
* The field definition.
* @param \Drupal\gdpr_fields\Entity\GdprField $field_config
* GDPR field configuration.
*
* @return string
* The anonymizer ID or null.
*/
private function getAnonymizerId(FieldDefinitionInterface $field_definition, GdprField $field_config) {
$anonymizer = $field_config->anonymizer;
$type = $field_definition
->getType();
if (!$anonymizer) {
// No anonymizer defined directly on the field.
// Instead try and get one for the datatype.
$anonymizers = [
'string' => 'gdpr_text_anonymizer',
'datetime' => 'gdpr_date_anonymizer',
];
$this->moduleHandler
->alter('gdpr_type_anonymizers', $anonymizers);
$anonymizer = $anonymizers[$type];
}
return $anonymizer;
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
EntityTraversal:: |
protected | property | The starting entity for the traversal. | |
EntityTraversal:: |
protected | property | Entity storage for GDPR config entities. | |
EntityTraversal:: |
protected | property | The processed entities. | |
EntityTraversal:: |
protected | property | Entity field manager. | |
EntityTraversal:: |
protected | property | Entity type manager. | |
EntityTraversal:: |
protected | property | The results of the traversal. | |
EntityTraversal:: |
private | property | Reverse relationship information. | |
EntityTraversal:: |
protected | property | Whether or not the traversal has happened successfully. | |
EntityTraversal:: |
protected | function | Traverses the entity relationship tree. | |
EntityTraversal:: |
protected | function | Gets all reverse relationships configured in the system. | |
EntityTraversal:: |
protected | function | Gets the entity bundle label. Useful for display traversal. | |
EntityTraversal:: |
public | function | Get the calculated actual calling points. | |
EntityTraversal:: |
public | function |
Get the traversal results. Overrides EntityTraversalInterface:: |
|
EntityTraversal:: |
public | function |
Traverses the entity relationship tree if not done before. Overrides EntityTraversalInterface:: |
|
RightToBeForgottenEntityTraversal:: |
private | property | Factory used to retrieve anonymizer to use on a particular field. | |
RightToBeForgottenEntityTraversal:: |
private | property | Drupal module handler for hooks. | |
RightToBeForgottenEntityTraversal:: |
private | function | Runs anonymize functionality against a field. | |
RightToBeForgottenEntityTraversal:: |
public static | function |
Creates an instance of the traversal for this specific entity. Overrides EntityTraversal:: |
|
RightToBeForgottenEntityTraversal:: |
private | function | Gets the ID of the anonymizer plugin to use on this field. | |
RightToBeForgottenEntityTraversal:: |
protected | function |
Overrides EntityTraversal:: |
|
RightToBeForgottenEntityTraversal:: |
private | function | Removes the field value. | |
RightToBeForgottenEntityTraversal:: |
public | function |
Traverses the entity relationship tree. Overrides EntityTraversal:: |
|
RightToBeForgottenEntityTraversal:: |
public | function |
EntityTraversal constructor. Overrides EntityTraversal:: |