View source
<?php
namespace Drupal\field_encrypt\EventSubscriber;
use Drupal\Core\Config\Config;
use Drupal\Core\Config\ConfigCrudEvent;
use Drupal\Core\Config\ConfigEvents;
use Drupal\Core\Entity\ContentEntityTypeInterface;
use Drupal\Core\Entity\DynamicallyFieldableEntityStorageInterface;
use Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Queue\QueueFactory;
use Drupal\Core\State\StateInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\Core\Url;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\field_encrypt\EncryptedFieldValueManagerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class ConfigSubscriber implements EventSubscriberInterface {
use StringTranslationTrait;
protected $entityTypeManager;
protected $queueFactory;
protected $encryptedFieldValueManager;
protected $state;
protected $entitySchemaRepository;
protected $messenger;
public function __construct(EntityTypeManagerInterface $entity_type_manager, QueueFactory $queue_factory, TranslationInterface $translation, EncryptedFieldValueManagerInterface $encrypted_field_value_manager, StateInterface $state, EntityLastInstalledSchemaRepositoryInterface $entity_schema_repository, MessengerInterface $messenger) {
$this->entityTypeManager = $entity_type_manager;
$this->queueFactory = $queue_factory;
$this->stringTranslation = $translation;
$this->encryptedFieldValueManager = $encrypted_field_value_manager;
$this->state = $state;
$this->entitySchemaRepository = $entity_schema_repository;
$this->messenger = $messenger;
}
public static function getSubscribedEvents() {
$events[ConfigEvents::SAVE][] = array(
'onConfigSave',
0,
);
$events[ConfigEvents::DELETE][] = array(
'onConfigDelete',
0,
);
return $events;
}
public function onConfigSave(ConfigCrudEvent $event) {
$config = $event
->getConfig();
if (substr($config
->getName(), 0, 14) == 'field.storage.') {
$original_config = $config
->getOriginal('third_party_settings.field_encrypt');
$this
->setUncacheableEntityTypes();
if ($this
->encryptionConfigChanged($config)) {
$storage_name = substr($config
->getName(), 14);
list($entity_type, $field_name) = explode('.', $storage_name, 2);
$field_storage_config = FieldStorageConfig::loadByName($entity_type, $field_name);
if ($field_storage_config) {
if ($field_storage_config
->hasData()) {
$query = $this->entityTypeManager
->getStorage($entity_type)
->getQuery();
$query
->exists($field_name);
if ($this->entityTypeManager
->getDefinition($entity_type)
->hasKey('revision')) {
$query
->allRevisions();
}
$entity_ids = $query
->execute();
if (!empty($entity_ids)) {
$queue = $this->queueFactory
->get('cron_encrypted_field_update');
foreach (array_keys($entity_ids) as $entity_id) {
$data = [
"entity_id" => $entity_id,
"field_name" => $field_name,
"entity_type" => $entity_type,
"original_config" => $original_config,
];
$queue
->createItem($data);
}
}
$this->messenger
->addMessage($this
->t('Updates to entities with existing data for this field have been queued to be processed. You should immediately <a href=":url">run this process manually</a>. Alternatively, the updates will be performed automatically by cron.', array(
':url' => Url::fromRoute('field_encrypt.field_update')
->toString(),
)));
}
}
}
}
}
public function onConfigDelete(ConfigCrudEvent $event) {
$config = $event
->getConfig();
if (substr($config
->getName(), 0, 14) == 'field.storage.') {
$storage_name = substr($config
->getName(), 14);
list($entity_type, $field_name) = explode('.', $storage_name, 2);
$this->encryptedFieldValueManager
->deleteEncryptedFieldValuesForField($entity_type, $field_name);
}
}
protected function encryptionConfigChanged(Config $config) {
$new_config = $config
->get('third_party_settings.field_encrypt');
$original_config = $config
->getOriginal('third_party_settings.field_encrypt');
unset($new_config['uncacheable']);
unset($original_config['uncacheable']);
return $new_config !== $original_config;
}
protected function setUncacheableEntityTypes() {
$types = [];
$entity_types = $this->entityTypeManager
->getDefinitions();
$old_uncacheable_types = $this->state
->get('uncacheable_entity_types', []);
foreach ($entity_types as $entity_type) {
if ($entity_type instanceof ContentEntityTypeInterface) {
$storage_class = $this->entityTypeManager
->createHandlerInstance($entity_type
->getStorageClass(), $entity_type);
if ($storage_class instanceof DynamicallyFieldableEntityStorageInterface) {
$ids = $this->entityTypeManager
->getStorage('field_storage_config')
->getQuery()
->condition('id', $entity_type
->id() . '.', 'STARTS_WITH')
->execute();
$field_storages = FieldStorageConfig::loadMultiple($ids);
if ($field_storages) {
foreach ($field_storages as $storage) {
if ($storage
->getThirdPartySetting('field_encrypt', 'uncacheable', FALSE) == TRUE) {
$type = $storage
->getTargetEntityTypeId();
$types[$type] = $type;
}
}
}
}
}
}
$this->state
->set('uncacheable_entity_types', $types);
$this->entityTypeManager
->clearCachedDefinitions();
$entity_types = $this->entityTypeManager
->getDefinitions();
$changed_types = array_merge(array_diff($old_uncacheable_types, $types), array_diff($types, $old_uncacheable_types));
foreach ($changed_types as $type) {
$last_installed_definition = $this->entitySchemaRepository
->getLastInstalledDefinition($type);
$last_installed_definition
->set('static_cache', $entity_types[$type]
->get('static_cache') ?? FALSE)
->set('render_cache', $entity_types[$type]
->get('render_cache') ?? FALSE)
->set('persistent_cache', $entity_types[$type]
->get('persistent_cache') ?? FALSE);
$this->entitySchemaRepository
->setLastInstalledDefinition($last_installed_definition);
}
}
}