subentity-1.x-dev/src/ReferencedEntityAccessControlHandler.php
src/ReferencedEntityAccessControlHandler.php
<?php
namespace Drupal\subentity;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Entity\EntityAccessControlHandler;
use Drupal\Core\Entity\EntityHandlerInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Session\AccountInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Access control handler for the referenced entity.
*
* Finding parent entity permissions to assign them to this entity.
*/
class ReferencedEntityAccessControlHandler extends EntityAccessControlHandler implements EntityHandlerInterface {
/**
* Entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* Constructs an access control handler instance for referenced entity.
*
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
* The entity type.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
*/
public function __construct(EntityTypeInterface $entity_type, EntityTypeManagerInterface $entity_type_manager) {
parent::__construct($entity_type);
$this->entityTypeManager = $entity_type_manager;
}
/**
* {@inheritdoc}
*/
public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
// @phpstan-ignore new.static
return new static($entity_type, $container->get('entity_type.manager'));
}
/**
* {@inheritdoc}
*/
protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
$storage_by_entity_type = $this->getStorageByEntityType();
$target_id = $entity->id();
// Finds the parent which references this entity.
foreach ($storage_by_entity_type as $entity_type => $storages) {
$entity_storage = $this->entityTypeManager->getStorage($entity_type);
$query = $entity_storage->getQuery('OR')->accessCheck();
/** @var \Drupal\field\FieldStorageConfigInterface $storage */
foreach ($storages as $storage) {
$query->condition($storage->get('field_name') . '.target_id', $target_id);
}
$result = $query->execute();
// If the parent is found, check its access control.
if ($result) {
$entities = $entity_storage->loadMultiple($result);
/** @var \Drupal\Core\Entity\ContentEntityInterface $entity_parent */
foreach ($entities as $entity_parent) {
if ($entity_parent->access($operation)) {
return AccessResult::allowed();
}
}
}
}
// Unknown operation, no opinion.
return AccessResult::neutral();
}
/**
* {@inheritdoc}
*/
protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL) {
$storage_by_entity_type = $this->getStorageByEntityType();
foreach ($storage_by_entity_type as $entity_type => $storages) {
$access_control_handler = $this->entityTypeManager->getAccessControlHandler($entity_type);
/** @var \Drupal\field\FieldStorageConfigInterface $storage */
foreach ($storages as $storage) {
foreach ($storage->getBundles() as $bundle) {
if ($access_control_handler->createAccess($bundle, $account)) {
return AccessResult::allowed();
}
}
}
}
return AccessResult::forbidden();
}
/**
* Return storages of referenced fields targeting the current entity type.
*
* @return array<string, \Drupal\field\FieldStorageConfigInterface[]>
* Associative array.
*/
protected function getStorageByEntityType() {
/** @var \Drupal\subentity\Entity\EntityParentHandler $handler */
$handler = $this->entityTypeManager->getHandler($this->entityTypeId, 'parent');
return $handler->getStorageByEntityType();
}
}
