Created
January 27, 2017 23:14
-
-
Save grayside/a7b8aba74ccf36ff984b0b9499b3a188 to your computer and use it in GitHub Desktop.
Finding Backreferences and relevant backreferencing fields.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Drupal\back_reference; | |
use Drupal\field\Entity\FieldConfig; | |
use Drupal\Core\Entity\Query\QueryFactory; | |
use Drupal\Core\Entity\EntityTypeManager; | |
use Drupal\Core\Entity\EntityFieldManager; | |
/** | |
* Identifies backreferences from entities to the specified node. | |
*/ | |
class BackReferenceFinder { | |
/** | |
* The entity query factory service. | |
* | |
* @var \Drupal\Core\Entity\Query\QueryFactory | |
*/ | |
protected $entityQuery; | |
/** | |
* Entity Type Manager service. | |
* | |
* @var \Drupal\Core\Entity\EntityTypeManager | |
*/ | |
protected $entityTypeManager; | |
/** | |
* Entity Field Manager service. | |
* | |
* @var \Drupal\Core\Entity\EntityFieldManager | |
*/ | |
protected $entityFieldManager; | |
/** | |
* Array of all fields that can reference the given entity/bundle. | |
* | |
* @var array | |
*/ | |
protected $backReferenceFields = []; | |
/** | |
* Stores an array of entity IDs that are backreferencing. | |
* | |
* @var array | |
*/ | |
protected $backReferenceEntityIds = []; | |
/** | |
* Constructs a \Drupal\back_reference\BackReferenceFinder | |
* | |
* @param \Drupal\Core\Entity\Query\QueryFactory $entity_query | |
* Entity Field Query. | |
* @param \Drupal\Core\Entity\EntityTypeManager $entity_type_manager | |
* Entity Type Manager. | |
* @param \Drupal\Core\Entity\EntityFieldManager $entity_field_manager | |
* Entity Field Manager. | |
*/ | |
public function __construct(QueryFactory $entity_query, EntityTypeManager $entity_type_manager, EntityFieldManager $entity_field_manager) { | |
$this->entityQuery = $entity_query; | |
$this->entityTypeManager = $entity_type_manager; | |
$this->entityFieldManager = $entity_field_manager; | |
} | |
/** | |
* Load all entities that reference the entity of the given identifier. | |
* | |
* This method does not perform any checks on the targeted entity to verify | |
* the applicability of the field, as those are assumed to have been handled | |
* as part of deriving a confirmed FieldConfig object. | |
* | |
* @param \Drupal\field\Entity\FieldConfig $field | |
* The field definition from which we derive query conditions. | |
* @param string $target_id | |
* The entity identifier the reference field should target. | |
* | |
* @return \Drupal\Core\Entity\EntityInterface[] | |
* Array of Entities that reference our specified target ID. | |
* | |
* @todo Expand for workflow/workspace if and when those elements are added. | |
*/ | |
public function loadReferencingEntities(FieldConfig $field, $target_id) { | |
$cid = $field->getTargetEntityTypeId() . $field->getName() . $target_id; | |
if (!isset($this->backReferenceEntityIds[$cid])) { | |
$query = $this->entityQuery->get($field->getTargetEntityTypeId(), 'AND') | |
->condition($field->getName(), $target_id) | |
->condition('status', 1) | |
->addTag('node_access'); | |
$this->backReferenceFields[$cid] = $query->execute(); | |
} | |
$ids = $this->backReferenceFields[$cid]; | |
return $this->entityTypeManager->getStorage($field->getTargetEntityTypeId()) | |
->loadMultiple($ids); | |
} | |
/** | |
* Retrieves every reference field which can point at the current entity. | |
* | |
* @param string $entity_type_id | |
* The machine name identifier for the entity type. | |
* @param string $entity_bundle_id | |
* The machine name identifier for the entity bundle. Defaults to NULL. | |
* | |
* @return \Drupal\field\Entity\FieldConfig[] | |
* Array of all applicable fields keyed by field name. | |
* | |
* @todo Determine if we need specific fields instead of all fields. If so, | |
* add a array $mask = [] parameter as whitelist. | |
*/ | |
public function referencingFields($entity_type_id, $entity_bundle_id) { | |
$cid = $entity_type_id . $entity_bundle_id; | |
if (isset($this->backReferenceFields[$cid])) { | |
return $this->backReferenceFields[$cid]; | |
} | |
$entity_reference_fields = $this->entityFieldManager->getFieldMapByFieldType('entity_reference'); | |
$fields = []; | |
foreach ($entity_reference_fields as $entity_type_field_is_on => $field_info) { | |
foreach ($field_info as $field_name => $field_data) { | |
foreach ($field_data['bundles'] as $entity_bundle_field_is_on) { | |
/* @var \Drupal\field\Entity\FieldConfig */ | |
$field = FieldConfig::loadByName($entity_type_field_is_on, $entity_bundle_field_is_on, $field_name); | |
// Check to see if the field is applicable to our entity and check for | |
// references if so. | |
if ($field && static::referenceFieldAppliesToEntity($field, $entity_type_id, $entity_bundle_id)) { | |
$fields[$field_name] = $field; | |
} | |
} | |
} | |
} | |
$this->backReferenceFields[$entity_type_id . $entity_bundle_id] = $fields; | |
return $this->backReferenceFields[$cid]; | |
} | |
/** | |
* Identifies if supplied field is applicable to the given entity. | |
* | |
* @param \Drupal\field\Entity\FieldConfig $field | |
* The field configuration we are testing. | |
* @param string $entity_type_id | |
* The machine name identifier for the entity type. | |
* @param string $entity_bundle_id | |
* The machine name identifier for the entity bundle. Defaults to NULL. | |
* | |
* @return bool | |
* TRUE if the field is applicable, FALSE otherwise. | |
*/ | |
public static function referenceFieldAppliesToEntity(FieldConfig $field, $entity_type_id, $entity_bundle_id = NULL) { | |
$entity_type_targeted_by_field = $field->getSetting('target_type'); | |
$field_handler = $field->getSetting('handler_settings'); | |
return $entity_type_targeted_by_field == $entity_type_id && | |
isset($field_handler['target_bundles']) && | |
isset($field_handler['target_bundles'][$entity_bundle_id]); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment