You are here

class Anonymizer in General Data Protection Regulation 8

Same name in this branch
  1. 8 modules/gdpr_tasks/src/Anonymizer.php \Drupal\gdpr_tasks\Anonymizer
  2. 8 modules/anonymizer/src/Annotation/Anonymizer.php \Drupal\anonymizer\Annotation\Anonymizer
Same name and namespace in other branches
  1. 8.2 modules/gdpr_tasks/src/Anonymizer.php \Drupal\gdpr_tasks\Anonymizer
  2. 3.0.x modules/gdpr_tasks/src/Anonymizer.php \Drupal\gdpr_tasks\Anonymizer

Anonymizes or removes field values for GDPR.

Hierarchy

Expanded class hierarchy of Anonymizer

1 file declares its use of Anonymizer
TaskActionsForm.php in modules/gdpr_tasks/src/Form/TaskActionsForm.php
4 string references to 'Anonymizer'
anonymizer.info.yml in modules/anonymizer/anonymizer.info.yml
modules/anonymizer/anonymizer.info.yml
gdpr_tasks.services.yml in modules/gdpr_tasks/gdpr_tasks.services.yml
modules/gdpr_tasks/gdpr_tasks.services.yml
TaskLogItem::propertyDefinitions in modules/gdpr_tasks/src/Plugin/Field/FieldType/TaskLogItem.php
Defines field item properties.
TaskLogItemWidget::formElement in modules/gdpr_tasks/src/Plugin/Field/FieldWidget/TaskLogItemWidget.php
Returns the form for a single field widget.
1 service uses Anonymizer
gdpr_tasks.anonymizer in modules/gdpr_tasks/gdpr_tasks.services.yml
Drupal\gdpr_tasks\Anonymizer

File

modules/gdpr_tasks/src/Anonymizer.php, line 19

Namespace

Drupal\gdpr_tasks
View source
class Anonymizer {
  use StringTranslationTrait;

  /**
   * Database instance for the request.
   *
   * @var \Drupal\Core\Database\Connection
   */
  private $database;

  /**
   * Entity Type manager used to retrieve field storage info.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  private $entityTypeManager;

  /**
   * The current user.
   *
   * @var \Drupal\Core\Session\AccountProxyInterface
   */
  private $currentUser;

  /**
   * Config factory.
   *
   * @var \Drupal\Core\Config\ConfigFactoryInterface
   */
  private $configFactory;

  /**
   * Traverses the entity hierarchy finding GDPR fields.
   *
   * @var \Drupal\gdpr_tasks\Traversal\RightToBeForgottenEntityTraversal
   */
  private $traversalFactory;

  /**
   * Anonymizer constructor.
   *
   * @param \Drupal\Core\Database\Connection $database
   *   The database connection.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
   *   The entity type manager.
   * @param \Drupal\Core\Session\AccountProxyInterface $currentUser
   *   The current user.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
   *   The config factory.
   * @param \Drupal\gdpr_fields\EntityTraversalFactory $traversalFactory
   *   Instantiates a traverser class.
   */
  public function __construct(Connection $database, EntityTypeManagerInterface $entityTypeManager, AccountProxyInterface $currentUser, ConfigFactoryInterface $configFactory, EntityTraversalFactory $traversalFactory) {
    $this->database = $database;
    $this->entityTypeManager = $entityTypeManager;
    $this->currentUser = $currentUser;
    $this->configFactory = $configFactory;
    $this->traversalFactory = $traversalFactory;
  }

  /**
   * Runs anonymization routines against a user.
   *
   * @param \Drupal\gdpr_tasks\Entity\TaskInterface $task
   *   The current task being executed.
   *
   * @return array
   *   Returns array containing any error messages.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   * @throws \Drupal\Core\TypedData\Exception\ReadOnlyException
   */
  public function run(TaskInterface $task) {

    // Make sure we load a fresh copy of the entity (bypassing the cache)
    // so we don't end up affecting any other references to the entity.
    $user = $task
      ->getOwner();
    $errors = [];
    if (!$this
      ->checkExportDirectoryExists()) {
      $errors[] = $this
        ->t('An export directory has not been set. Please set this %link.', [
        '%link' => Link::fromTextAndUrl('here', Url::fromRoute('gdpr_tasks.remove_settings'))
          ->toString(),
      ]);
      return $errors;
    }

    // Traverser does the actual anonymizing.
    $traverser = $this->traversalFactory
      ->getTraversal($user);
    $result = $traverser
      ->getResults();
    $log = $result['log'];
    $errors = $result['errors'];
    $successes = $result['successes'];
    $failures = $result['failures'];
    $deletions = $result['to_delete'];
    $task
      ->get('removal_log')
      ->setValue($log);
    if (count($failures) === 0) {
      $transaction = $this->database
        ->startTransaction();
      try {

        /* @var \Drupal\Core\Entity\EntityInterface $entity */
        foreach ($successes as $entity) {
          $entity
            ->save();
        }
        foreach ($deletions as $entity) {
          $entity
            ->delete();
        }

        // Re-fetch the user so we see any changes that were made.
        $user = $this
          ->refetchUser($task
          ->getOwnerId());
        $user
          ->block();
        $user
          ->save();
        $this
          ->writeLogToFile($task, $log);
      } catch (\Exception $e) {
        $transaction
          ->rollBack();
        $errors[] = $e
          ->getMessage();
      }
    }
    return $errors;
  }

  /**
   * Re-fetches the user bypassing the cache.
   *
   * @param string $user_id
   *   The ID of the user to fetch.
   *
   * @return \Drupal\user\UserInterface
   *   The user that was fetched.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  private function refetchUser($user_id) {
    return $this->entityTypeManager
      ->getStorage('user')
      ->loadUnchanged($user_id);
  }

  /**
   * Checks that the export directory has been set.
   *
   * @return bool
   *   Indicates whether the export directory has been configured and exists.
   */
  private function checkExportDirectoryExists() {
    $directory = $this->configFactory
      ->get(RemovalSettingsForm::CONFIG_KEY)
      ->get(RemovalSettingsForm::EXPORT_DIRECTORY);
    return !empty($directory) && \file_prepare_directory($directory);
  }

  /**
   * Stores the task log to the configured directory as JSON.
   *
   * @param \Drupal\gdpr_tasks\Entity\TaskInterface $task
   *   The task in progress.
   * @param array $log
   *   Log of processed fields.
   */
  private function writeLogToFile(TaskInterface $task, array $log) {
    $filename = 'GDPR_RTF_' . \date('Y-m-d H-i-s') . '_' . $task
      ->uuid() . '.json';
    $dir = $this->configFactory
      ->get(RemovalSettingsForm::CONFIG_KEY)
      ->get(RemovalSettingsForm::EXPORT_DIRECTORY);
    $filename = $dir . '/' . $filename;

    // Don't serialize the whole entity as we don't need all fields.
    $output = [
      'task_id' => $task
        ->id(),
      'task_uuid' => $task
        ->uuid(),
      'owner_id' => $task
        ->getOwnerId(),
      'created' => $task
        ->getCreatedTime(),
      'processed_by' => $this->currentUser
        ->id(),
      'log' => $log,
    ];
    \file_put_contents($filename, \json_encode($output));
  }

}

Members

Namesort descending Modifiers Type Description Overrides
Anonymizer::$configFactory private property Config factory.
Anonymizer::$currentUser private property The current user.
Anonymizer::$database private property Database instance for the request.
Anonymizer::$entityTypeManager private property Entity Type manager used to retrieve field storage info.
Anonymizer::$traversalFactory private property Traverses the entity hierarchy finding GDPR fields.
Anonymizer::checkExportDirectoryExists private function Checks that the export directory has been set.
Anonymizer::refetchUser private function Re-fetches the user bypassing the cache.
Anonymizer::run public function Runs anonymization routines against a user.
Anonymizer::writeLogToFile private function Stores the task log to the configured directory as JSON.
Anonymizer::__construct public function Anonymizer constructor.
StringTranslationTrait::$stringTranslation protected property The string translation service. 1
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.