|
|
|
|
@ -7,13 +7,26 @@ use Drupal\Component\Plugin\Exception\PluginNotFoundException;
|
|
|
|
|
use Drupal\Core\Entity\EntityFieldManagerInterface; |
|
|
|
|
use Drupal\Core\Entity\EntityTypeManagerInterface; |
|
|
|
|
use Drupal\Core\Logger\LoggerChannelInterface; |
|
|
|
|
use Drupal\Core\Cache\Cache; |
|
|
|
|
use Drupal\Core\Cache\CacheBackendInterface; |
|
|
|
|
|
|
|
|
|
class ZombieReferenceHunterQuery { |
|
|
|
|
|
|
|
|
|
class ZombieReferenceHunterQuery |
|
|
|
|
{ |
|
|
|
|
/** |
|
|
|
|
* Default number of entities loaded per batch. |
|
|
|
|
*/ |
|
|
|
|
const BATCH_SIZE = 200; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Cache ID for scan results. |
|
|
|
|
*/ |
|
|
|
|
const CACHE_ID = 'zombie_reference_hunter.issues'; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Cached scan results. |
|
|
|
|
*/ |
|
|
|
|
protected CacheBackendInterface $cache; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* The entity type manager. |
|
|
|
|
* |
|
|
|
|
@ -48,11 +61,13 @@ class ZombieReferenceHunterQuery
|
|
|
|
|
public function __construct( |
|
|
|
|
EntityTypeManagerInterface $entityTypeManager, |
|
|
|
|
EntityFieldManagerInterface $entityFieldManager, |
|
|
|
|
LoggerChannelInterface $logger |
|
|
|
|
LoggerChannelInterface $logger, |
|
|
|
|
CacheBackendInterface $cache |
|
|
|
|
) { |
|
|
|
|
$this->entityTypeManager = $entityTypeManager; |
|
|
|
|
$this->entityFieldManager = $entityFieldManager; |
|
|
|
|
$this->logger = $logger; |
|
|
|
|
$this->cache = $cache; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
@ -63,8 +78,8 @@ class ZombieReferenceHunterQuery
|
|
|
|
|
*/ |
|
|
|
|
protected function getFieldMaps(): array { |
|
|
|
|
return [ |
|
|
|
|
// 'entity_reference' => $this->entityFieldManager->getFieldMapByFieldType('entity_reference'), |
|
|
|
|
// 'entity_reference_revisions' => $this->entityFieldManager->getFieldMapByFieldType('entity_reference_revisions'), |
|
|
|
|
// 'entity_reference' => $this->entityFieldManager->getFieldMapByFieldType('entity_reference'), |
|
|
|
|
// 'entity_reference_revisions' => $this->entityFieldManager->getFieldMapByFieldType('entity_reference_revisions'), |
|
|
|
|
'typed_relation' => $this->entityFieldManager->getFieldMapByFieldType('typed_relation'), |
|
|
|
|
]; |
|
|
|
|
} |
|
|
|
|
@ -90,7 +105,7 @@ class ZombieReferenceHunterQuery
|
|
|
|
|
$source_storage = $this->entityTypeManager->getStorage($entity_type_id); |
|
|
|
|
$storage_definitions = $this->entityFieldManager->getFieldStorageDefinitions($entity_type_id); |
|
|
|
|
} |
|
|
|
|
catch (PluginNotFoundException | InvalidPluginDefinitionException $exception) { |
|
|
|
|
catch (PluginNotFoundException|InvalidPluginDefinitionException $exception) { |
|
|
|
|
$this->logger->warning('Skipping entity type %type due to storage error: %message', [ |
|
|
|
|
'%type' => $entity_type_id, |
|
|
|
|
'%message' => $exception->getMessage(), |
|
|
|
|
@ -104,9 +119,9 @@ class ZombieReferenceHunterQuery
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
$field_storage = $storage_definitions[$field_name]; |
|
|
|
|
// $field_storage->isComputed() || !$field_storage->isQueryable()) { |
|
|
|
|
// continue; |
|
|
|
|
// } |
|
|
|
|
// $field_storage->isComputed() || !$field_storage->isQueryable()) { |
|
|
|
|
// continue; |
|
|
|
|
// } |
|
|
|
|
|
|
|
|
|
$target_type = $field_storage->getSetting('target_type'); |
|
|
|
|
if (empty($target_type)) { |
|
|
|
|
@ -116,7 +131,7 @@ class ZombieReferenceHunterQuery
|
|
|
|
|
try { |
|
|
|
|
$target_storage = $this->entityTypeManager->getStorage($target_type); |
|
|
|
|
} |
|
|
|
|
catch (PluginNotFoundException | InvalidPluginDefinitionException $exception) { |
|
|
|
|
catch (PluginNotFoundException|InvalidPluginDefinitionException $exception) { |
|
|
|
|
$this->logger->warning('Skipping target type %type due to storage error: %message', [ |
|
|
|
|
'%type' => $target_type, |
|
|
|
|
'%message' => $exception->getMessage(), |
|
|
|
|
@ -187,4 +202,47 @@ class ZombieReferenceHunterQuery
|
|
|
|
|
|
|
|
|
|
return $issues; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Gets the current report results. |
|
|
|
|
* |
|
|
|
|
* Uses cached results when available. If there is no cached scan, |
|
|
|
|
* a new scan is performed automatically. |
|
|
|
|
* |
|
|
|
|
* @return array |
|
|
|
|
* Broken reference records. |
|
|
|
|
*/ |
|
|
|
|
public function getIssues(): array { |
|
|
|
|
if ($cache = $this->cache->get(self::CACHE_ID)) { |
|
|
|
|
return $cache->data; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return $this->rebuildCache(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Performs a fresh scan and caches the results. |
|
|
|
|
* |
|
|
|
|
* @return array |
|
|
|
|
* Broken reference records. |
|
|
|
|
*/ |
|
|
|
|
public function rebuildCache(): array { |
|
|
|
|
$issues = $this->scan(); |
|
|
|
|
|
|
|
|
|
$this->cache->set( |
|
|
|
|
self::CACHE_ID, |
|
|
|
|
$issues, |
|
|
|
|
Cache::PERMANENT |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
return $issues; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Clears the cached scan. |
|
|
|
|
*/ |
|
|
|
|
public function clearCache(): void { |
|
|
|
|
$this->cache->delete(self::CACHE_ID); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|