entity_value_inheritance-1.3.0/src/Services/Helper.php
src/Services/Helper.php
<?php
namespace Drupal\entity_value_inheritance\Services;
use Drupal\Component\EventDispatcher\Event;
use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException;
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldTypePluginManagerInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\entity_value_inheritance\EntityValueInheritanceUpdaterPluginInterface;
use Drupal\entity_value_inheritance\EntityValueInheritanceUpdaterPluginManager;
use Psr\Log\LoggerInterface;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
/**
* Service used for helping get more complex details.
*/
final class Helper {
use StringTranslationTrait;
/**
* Constructs a new \Drupal\entity_value_inheritance\Services\Helper object.
*/
public function __construct(protected FieldTypePluginManagerInterface $fieldTypePluginManager, protected EntityTypeManagerInterface $entityTypeManager, protected EntityTypeBundleInfoInterface $entityTypeBundleInfo, protected EntityFieldManagerInterface $entityFieldManager, protected ModuleHandlerInterface $moduleHandler, protected EntityValueInheritanceUpdaterPluginManager $pluginManager, protected LoggerInterface $logger, protected EventDispatcherInterface $eventDispatcher) {
}
/**
* Return a list of all field types.
*
* @return array
* List of all field types.
*/
protected function getFieldTypeList(): array {
$list = $this->fieldTypePluginManager->getDefinitions();
$this->moduleHandler->alter('entity_value_inheritance_field_type_list', $list);
return $list;
}
/**
* Return a list of all entities.
*
* @return \Drupal\Core\Entity\EntityTypeInterface[]
* List of entity types.
*/
public function getEntityTypeList(): array {
$list = $this->entityTypeManager->getDefinitions();
array_filter($list, function ($item) {
return !$item->entityClassImplements(FieldableEntityInterface::class);
});
$this->moduleHandler->alter('entity_value_inheritance_entity_type_list', $list);
return $list;
}
/**
* Return a list of all entity bundles.
*
* @param string $entityTypeId
* Entity Type ID.
*
* @return array
* List of all entity bundles.
*/
public function getEntityBundleList(string $entityTypeId): array {
$entity = $this->entityTypeManager->getDefinition($entityTypeId);
if (!$entity->entityClassImplements(FieldableEntityInterface::class)) {
return [];
}
$list = $this->entityTypeBundleInfo->getBundleInfo($entityTypeId);
$hooks = [
'entity_value_inheritance_entity_bundle_list',
'entity_value_inheritance_entity_bundle_list__' . $entityTypeId,
];
$this->moduleHandler->alter($hooks, $list, $entityTypeId);
return $list;
}
/**
* Return a list of all entity bundle fields.
*
* @param string $entityTypeId
* Entity Type ID.
* @param string $entityBundleId
* Entity Bundle ID.
*
* @return array
* List of fields for the provided entity and bundle.
*/
public function getEntityBundleFieldList(string $entityTypeId, string $entityBundleId): array {
$entity = $this->entityTypeManager->getDefinition($entityTypeId);
if (!$entity->entityClassImplements(FieldableEntityInterface::class)) {
return [];
}
$list = $this->entityFieldManager->getFieldDefinitions($entityTypeId, $entityBundleId);
// List of fields that should be excluded.
$exclude = ['nid', 'vid'];
$list = array_filter($list, function ($key) use ($exclude) {
return !in_array($key, $exclude);
}, ARRAY_FILTER_USE_KEY);
$hooks = [
'entity_value_inheritance_entity_bundle_field_list',
'entity_value_inheritance_entity_bundle_field_list__' . $entityTypeId,
'entity_value_inheritance_entity_bundle_field_list__' . $entityTypeId . '__' . $entityBundleId,
];
$this->moduleHandler->alter($hooks, $list, $entityTypeId, $entityBundleId);
return $list;
}
/**
* Return a list of entity fields by type.
*
* @param string $entityTypeId
* Entity Type ID.
* @param string $entityBundleId
* Entity Bundle ID.
* @param string $fieldType
* Field type to search for.
*
* @return array
* Return a list of fields.
*/
public function getEntityBundleFieldListByType(string $entityTypeId, string $entityBundleId, string $fieldType): array {
$entity = $this->entityTypeManager->getDefinition($entityTypeId);
if (!$entity->entityClassImplements(FieldableEntityInterface::class)) {
return [];
}
$list = [];
foreach ($this->getEntityBundleFieldList($entityTypeId, $entityBundleId) as $fieldId => $field) {
if ($field->getType() !== $fieldType) {
continue;
}
$list[$fieldId] = $field;
}
return $list;
}
/**
* Return a list of field types.
*
* @return array<string, array<string>>
* List of field types.
*/
public function getFieldTypes(): array {
$fieldTypes = [];
foreach ($this->getFieldTypeList() as $fieldTypeId => $fieldType) {
$fieldTypes[$this->getText($fieldType['category'])][$fieldTypeId] = $this->getText($fieldType['label']);
asort($fieldTypes[$this->getText($fieldType['category'])]);
}
ksort($fieldTypes);
return $fieldTypes;
}
/**
* Return a list of entities.
*
* @return string[]
* List of entities.
*/
public function getEntities(): array {
$entityTypes = [];
foreach ($this->getEntityTypeList() as $entityTypeId => $entityType) {
if (!$entityType->entityClassImplements(FieldableEntityInterface::class)) {
continue;
}
$entityTypes[$entityTypeId] = $this->getText($entityType->getLabel());
}
asort($entityTypes);
return $entityTypes;
}
/**
* Return the entity type label.
*
* @param string $entityTypeId
* Entity type to look up.
*
* @return string
* Label for entity type.
*/
public function getEntityTypeLabel(string $entityTypeId): string {
$list = $this->getEntities();
return $list[$entityTypeId] ?? $this->t('Unknown entity type');
}
/**
* Return a list of entities and bundles.
*
* @return string[][]
* List of entity bundles.
*/
public function getEntityBundles(): array {
$bundles = [];
foreach ($this->getEntityTypeList() as $entityTypeId => $entityType) {
if (!$entityType->entityClassImplements(FieldableEntityInterface::class)) {
continue;
}
$entityKey = $this->getText($entityType->getLabel());
foreach ($this->getEntityBundleList($entityTypeId) as $entityBundleId => $entityBundle) {
$bundles[$entityKey]["{$entityTypeId}.{$entityBundleId}"] = $this->getText($entityBundle['label']);
}
if (isset($bundles[$entityKey])) {
asort($bundles[$entityKey]);
}
}
ksort($bundles);
return $bundles;
}
/**
* Return the label for the provided bundle.
*
* @param string $entityTypeId
* Entity Type to search.
* @param string $bundleId
* Bundle Key to look up.
*
* @return string
* String to return for the bundle.
*/
public function getEntityBundleLabel(string $entityTypeId, string $bundleId): string {
$bundles = $this->getEntityBundleList($entityTypeId);
return array_key_exists($bundleId, $bundles) && array_key_exists('label', $bundles[$bundleId]) ?
$this->getText($bundles[$bundleId]['label']) :
$this->t('Unknown bundle');
}
/**
* Return a list of bundles for the provided entity type.
*
* @param string $entityTypeId
* Entity types to search for.
*
* @return string[]
* List of bundles for entity.
*/
public function getBundlesOptions(string $entityTypeId): array {
if (empty($entityTypeId)) {
return [];
}
$list = [];
foreach ($this->getEntityBundleList($entityTypeId) as $bundle_id => $bundle) {
$list[$bundle_id] = $this->getText($bundle['label']);
}
asort($list);
return $list;
}
/**
* Return a field definition.
*
* @param string $entityTypeId
* Entity Type ID to search.
* @param string $entityBundleId
* Entity Bundle ID to search.
* @param string $entityFieldId
* Entity Field ID to search.
*
* @return \Drupal\Core\Field\FieldDefinitionInterface|null
* List of all fields for entity.
*/
public function getEntityBundleField(string $entityTypeId, string $entityBundleId, string $entityFieldId): ?FieldDefinitionInterface {
$list = $this->getEntityBundleFieldList($entityTypeId, $entityBundleId);
return $list[$entityFieldId] ?? NULL;
}
/**
* Return a list of all fields for a bundle.
*/
public function getEntityBundleFieldsOptions(string $entityTypeId, string $entityBundleId, ?string $sourceFieldId = NULL): array {
if (empty($entityTypeId) || empty($entityBundleId)) {
return [];
}
$list = [];
$sourceFieldType = NULL;
if ($sourceFieldId !== NULL) {
[$sourceEntityId, $sourceEntityBundleId, $sourceEntityFieldId] = explode('.', $sourceFieldId);
$fieldList = $this->getEntityBundleFieldList($sourceEntityId, $sourceEntityBundleId);
$sourceFieldType = $fieldList[$sourceEntityFieldId]?->getType();
}
foreach ($this->getEntityBundleFieldList($entityTypeId, $entityBundleId) as $entityBundleFieldId => $entityBundleField) {
if (!is_null($sourceFieldType) && $entityBundleField->getType() !== $sourceFieldType) {
continue;
}
$list[$entityBundleFieldId] = sprintf(
'%s (%s) - %s',
$this->getText($entityBundleField->getLabel()),
$entityBundleFieldId,
$entityBundleField->getType()
);
}
return $list;
}
/**
* Return the label for the provided field.
*
* @param string $entityTypeId
* Entity Type ID.
* @param string $bundleId
* Bundle ID to look up.
* @param string $fieldId
* Field ID to look up.
*
* @return string
* Label for the field.
*/
public function getEntityBundleFieldLabel(string $entityTypeId, string $bundleId, string $fieldId): ?string {
$list = $this->getEntityBundleFieldList($entityTypeId, $bundleId);
return array_key_exists($fieldId, $list) ? $this->getText($list[$fieldId]->getLabel()) : $this->t('Unknown field');
}
/**
* Return a list of entity reference fields.
*
* @param string $entityTypeId
* Entity Type ID to search for.
* @param string $entityBundleId
* Entity Bundle ID to search for.
* @param string $targetEntity
* Entity Type to search reference fields for.
*/
public function getEntityReferenceFieldsOptions(string $entityTypeId, string $entityBundleId, string $targetEntity): array {
if (empty($entityTypeId) || empty($entityBundleId)) {
return [];
}
$list = [];
foreach ($this->getEntityBundleFieldListByType($entityTypeId, $entityBundleId, 'entity_reference') as $field_id => $field) {
if ($field->getItemDefinition()->getSetting('target_type') !== $targetEntity) {
continue;
}
$list[$field_id] = sprintf(
'%s - %s (%s)',
$this->getText($field->getLabel()),
$field->getType(),
$field_id
);
}
asort($list);
return $list;
}
/**
* Return a list of fields for an entity bundle.
*
* @return string[][]
* Return a list of entity bundle fields.
*/
public function getEntityBundleFields(): array {
$fields = [];
foreach ($this->getEntityTypeList() as $entityTypeId => $entityType) {
if (!$entityType->entityClassImplements(FieldableEntityInterface::class)) {
continue;
}
foreach ($this->getEntityBundleList($entityTypeId) as $entityBundleId => $entityBundle) {
$entityBundleKey = "{$this->getText($entityType->getLabel())} - {$this->getText($entityBundle['label'])}";
foreach ($this->getEntityBundleFieldList($entityTypeId, $entityBundleId) as $entityBundleFieldId => $entityBundleField) {
$fields[$entityBundleKey]["{$entityTypeId}.{$entityBundleId}.{$entityBundleFieldId}"] = $this->getText($entityBundleField->getLabel());
}
if (isset($fields[$entityBundleKey])) {
asort($fields[$entityBundleKey]);
}
}
}
ksort($fields);
return $fields;
}
/**
* Get the text value for the provided item.
*
* @return string
* Return the value for the string.
*/
public function getText(TranslatableMarkup|string $text): string {
return ($text instanceof TranslatableMarkup) ? $text->__toString() : $text;
}
/**
* Get a list of all the plugins.
*
* @return \Drupal\entity_value_inheritance\EntityValueInheritanceUpdaterPluginInterface[]
* List of plugins.
*/
public function getPlugins(): array {
$list = $this->pluginManager->getDefinitions();
uasort($list, function ($a, $b) {
if ($a['title'] === $b['title']) {
return 0;
}
return $a['title'] > $b['title'] ? 1 : -1;
});
return $list;
}
/**
* Search storage for inheritances for the provided criteria.
*
* @param array $search
* Search parameters.
*
* @return \Drupal\entity_value_inheritance\Entity\InheritanceInterface[]
* Return a list of enabled inheritance items.
*/
protected function searchStorage(array $search): array {
$items = [];
try {
/** @var \Drupal\entity_value_inheritance\Entity\InheritanceInterface[] $items */
$items = $this
->entityTypeManager
->getStorage('inheritance')
->loadByProperties($search);
}
catch (InvalidPluginDefinitionException | PluginNotFoundException $exception) {
$this->logger->error(
'Searching Storage Error. <pre>@message</pre>',
['@message' => $exception->getMessage()]
);
}
return $items;
}
/**
* Query for entities based on their reference.
*
* @param string $entity_type
* Entity type to search against.
* @param \Drupal\entity_value_inheritance\Entity\InheritanceInterface[] $inheritances
* Inheritances to group together to find the destinations.
* @param \Drupal\Core\Entity\EntityInterface $refEntity
* Source Entity to search for a reference to.
*
* @return \Drupal\Core\Entity\EntityInterface[]
* Entities returned from the query.
*/
public function queryEntities(string $entity_type, array $inheritances, EntityInterface $refEntity): array {
try {
$query = $this
->entityTypeManager
->getStorage($entity_type)
// @todo Question Does this pose a security risk?
->getQuery()
->accessCheck(FALSE);
$group = $query->orConditionGroup();
$searchGroup = [];
foreach ($inheritances as $inheritance) {
$key = sprintf('%s.%s', $inheritance->getDestinationBundle(), $inheritance->getDestinationReferenceField());
if (!isset($searchGroup[$key])) {
$tmpCondition = $query->andConditionGroup();
$tmpCondition->condition("type", $inheritance->getDestinationBundle());
$tmpCondition->condition("{$inheritance->getDestinationReferenceField()}.target_id", $refEntity->id());
$group->condition($tmpCondition);
$searchGroup[$key] = TRUE;
}
}
$query->condition($group);
$ids = $query->execute();
$list = $this
->entityTypeManager
->getStorage($entity_type)
->loadMultiple($ids);
}
catch (PluginNotFoundException | InvalidPluginDefinitionException $exception) {
$this->logger->error(
'Error trying load entities - <pre>@message</pre>',
['@message' => $exception->getMessage()]
);
return [];
}
return $list;
}
/**
* Return an array of inheritances by specific field.
*
* @param \Drupal\entity_value_inheritance\Entity\InheritanceInterface[] $inheritances
* Array of inheritances.
* @param string $property
* Property within Inheritance entity to group by.
*
* @return \Drupal\entity_value_inheritance\Entity\InheritanceInterface[][]
* List of inheritances grouped by property.
*/
public function groupByProperty(array $inheritances, string $property): array {
$list = [];
foreach ($inheritances as $inheritance) {
$key = $inheritance->get($property);
if (!array_key_exists($key, $list)) {
$list[$key] = [];
}
$list[$key][] = $inheritance;
}
return $list;
}
/**
* Execute Event for event dispatcher.
*
* @param \Drupal\Component\EventDispatcher\Event $event
* Event to get processed and returned.
* @param string $eventName
* Event Name being announced.
*
* @return \Drupal\Component\EventDispatcher\Event
* Event returned from dispatcher.
*/
public function dispatchEvent(Event $event, string $eventName): Event {
return $this->eventDispatcher->dispatch($event, $eventName);
}
/**
* Return a list of all items that are matching the source item.
*
* @param string $entityTypeId
* Source Entity to search for destinations.
* @param string|null $bundleId
* Source Bundle to search for.
*
* @return \Drupal\entity_value_inheritance\Entity\InheritanceInterface[]
* Return a list of enabled inheritance items.
*/
public function getSourceItems(string $entityTypeId, ?string $bundleId = NULL): array {
$search = [
'source_entity_type' => $entityTypeId,
'status' => 1,
];
if ($bundleId) {
$search['source_entity_bundle'] = $bundleId;
}
return $this->searchStorage($search);
}
/**
* Return a list of all items where destination entity is provided.
*
* @param string $entityTypeId
* Entity Type ID to search.
* @param string|null $bundleId
* Bundle ID to search.
*
* @return \Drupal\entity_value_inheritance\Entity\InheritanceInterface[]
* Return a list of enabled inheritance items.
*/
public function getDestinationItems(string $entityTypeId, ?string $bundleId = NULL): array {
$search = [
'destination_entity_type' => $entityTypeId,
'status' => 1,
];
if ($bundleId) {
$search['destination_entity_bundle'] = $bundleId;
}
return $this->searchStorage($search);
}
/**
* Return all inheritances by the destination entity type.
*
* @param string $entityType
* Entity Type to search.
*
* @return \Drupal\entity_value_inheritance\Entity\InheritanceInterface[]
*/
public function getDestinationByEntityType(string $entityType): array {
return $this->searchStorage([
'destination_entity_type' => $entityType,
'status' => 1,
]);
}
/**
* Return a list of inheritances by destination configuration.
*/
public function getDestinationsByField(string $entityType, string $bundleType, string $field, string $fieldName = 'destination_entity_field'): array {
return $this->searchStorage([
'destination_entity_type' => $entityType,
'destination_entity_bundle' => $bundleType,
$fieldName => $field,
'status' => 1,
]);
}
/**
* Get all the inherited items for the provided source entity.
*
* @param \Drupal\Core\Entity\EntityInterface $sourceEntity
* Source Entity to search for.
*
* @return \Drupal\entity_value_inheritance\Entity\InheritanceInterface[]
* Items put into a multidimensional array.
*/
public function getInheritanceItemsBySource(EntityInterface $sourceEntity): array {
return $this->getSourceItems($sourceEntity->getEntityTypeId(), $sourceEntity->bundle());
}
/**
* Get all the inherited items for the provided destination entity.
*
* @param \Drupal\Core\Entity\EntityInterface $destinationEntity
* Destination entity to search for.
*
* @return \Drupal\entity_value_inheritance\Entity\InheritanceInterface[]
* Inheritances put into array.
*/
public function getInheritanceItemsByDestination(EntityInterface $destinationEntity): array {
return $this->getDestinationItems($destinationEntity->getEntityTypeId(), $destinationEntity->bundle());
}
/**
* Check to see if there are active records for the entity type.
*
* @param string $entityType
* Entity type id to search.
* @param bool $source
* Check the source type.
*
* @return bool
* TRUE if records are found
*/
public function hasActiveRecords(string $entityType, bool $source = FALSE): bool {
return count($this->searchStorage([
($source ? 'source' : 'destination') . '_entity_type' => $entityType,
'status' => 1,
])) > 0;
}
/**
* Return the logger service.
*
* @return \Psr\Log\LoggerInterface
* Logging service.
*/
public function logger(): LoggerInterface {
return $this->logger;
}
/**
* Return the strategy label.
*
* @param \Drupal\entity_value_inheritance\EntityValueInheritanceUpdaterPluginInterface $plugin
* Strategy Plugin.
*
* @return string
* Label to return.
*/
public function getStrategyLabel(EntityValueInheritanceUpdaterPluginInterface $plugin): string {
return $plugin->getTitle();
}
}
