entity_type_access_conditions-1.0.1/src/EntityAlters.php
src/EntityAlters.php
<?php
declare(strict_types=1);
namespace Drupal\entity_type_access_conditions;
use Drupal\conditions_helper\ConditionsEvaluator;
use Drupal\conditions_helper\Form\ConditionsFormBuilder;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\DependencyInjection\DependencySerializationTrait;
use Drupal\Core\Entity\EntityFormInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\Context\ContextRepositoryInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\entity_type_access_conditions\Form\SettingsForm;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Entity Alters class for altering entity type forms and access.
*/
class EntityAlters implements ContainerInjectionInterface {
use DependencySerializationTrait;
use StringTranslationTrait;
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
$context_repository = $container->get('context.repository');
$entity_type_manager = $container->get('entity_type.manager');
$conditions_helper_form_builder = $container->get('conditions_helper.form_builder');
$conditions_evaluator = $container->get('conditions_helper.evaluator');
$plugin_manager = $container->get('plugin.manager.entity_type_access_conditions');
$module_handler = $container->get('module_handler');
assert($context_repository instanceof ContextRepositoryInterface);
assert($entity_type_manager instanceof EntityTypeManagerInterface);
assert($conditions_helper_form_builder instanceof ConditionsFormBuilder);
assert($conditions_evaluator instanceof ConditionsEvaluator);
assert($plugin_manager instanceof EntityTypeAccessConditionsPluginManager);
assert($module_handler instanceof ModuleHandlerInterface);
return new self(
$context_repository,
$entity_type_manager,
$conditions_helper_form_builder,
$conditions_evaluator,
$plugin_manager,
$module_handler,
);
}
/**
* Constructor for FormAlters.
*/
public function __construct(
protected readonly ContextRepositoryInterface $contextRepository,
protected readonly EntityTypeManagerInterface $entityTypeManager,
protected readonly ConditionsFormBuilder $conditionsHelperFormBuilder,
protected readonly ConditionsEvaluator $conditionsEvaluator,
protected readonly EntityTypeAccessConditionsPluginManager $pluginManager,
protected readonly ModuleHandlerInterface $moduleHandler,
) {
}
/**
* Get the form IDs that we want to alter.
*
* @return array
* The form IDs.
*/
public function getFormIds(): array {
$form_ids = $this->pluginManager->getAlteredForms();
$this->moduleHandler->alter('entity_type_access_conditions_form_ids', $form_ids);
return $form_ids;
}
/**
* Alter the form.
*
* @param array $form
* The form array.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form state object.
* @param string $form_id
* The form ID.
*/
public function formAlter(array &$form, FormStateInterface $form_state, $form_id): void {
$form_object = $form_state->getFormObject();
if ($form_object instanceof EntityFormInterface) {
// Grab the entity from the form.
$entity = $form_object->getEntity();
if (!empty($entity) && $entity instanceof EntityInterface) {
$form['third_party_settings'] = [
'#tree' => TRUE,
];
$form['third_party_settings']['entity_type_access_conditions'] = [
'#type' => 'details',
'#title' => $this->t('Entity Type Access Conditions'),
'#open' => TRUE,
'#tree' => TRUE,
];
$available_conditions = $this->conditionsHelperFormBuilder->getAvailableConditions(SettingsForm::SETTINGS);
$available_contexts = $this->contextRepository->getAvailableContexts();
$stored_values = $entity->getThirdPartySettings('entity_type_access_conditions') ?? [];
$this->conditionsHelperFormBuilder->buildConditionsForm($form['third_party_settings']['entity_type_access_conditions'], $form_state, $available_conditions, $available_contexts, $stored_values);
// Add our submission handler to be first.
array_unshift(
$form['actions']['submit']['#submit'],
[$this, 'formAlterSubmit']
);
}
}
}
/**
* Submit callback for the form being submitted.
*
* @param array $form
* The form being altered.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form state object.
*/
public function formAlterSubmit(array &$form, FormStateInterface $form_state): void {
$this->conditionsHelperFormBuilder->submitConditionsForm(
$form,
$form_state,
['third_party_settings', 'entity_type_access_conditions']
);
}
/**
* Check if the entity is accessible and block if not.
*/
public function entityAccess(EntityInterface $entity, $operation, AccountInterface $account) {
if ($account->hasPermission('bypass entity type access conditions')) {
return AccessResult::neutral();
}
return $this->checkAccess($entity, $operation, $account);
}
/**
* Check if the entity can be created.
*/
public function entityCreateAccess(AccountInterface $account, array $context, ?string $entity_bundle) {
if ($account->hasPermission('bypass entity type access conditions')) {
return AccessResult::neutral();
}
if (empty($entity_bundle)) {
return AccessResult::neutral();
}
if (empty($context['entity_type_id'])) {
return AccessResult::neutral();
}
$plugin = $this->pluginManager->getDefinition($context['entity_type_id'], FALSE);
if (!$plugin) {
return AccessResult::neutral();
}
// If the operation is not restricted, return neutral.
$restricted_operations = $plugin['restricted_operations'];
if (!in_array('create', $restricted_operations)) {
return AccessResult::neutral();
}
$entity_definition = $this->entityTypeManager->getDefinition($context['entity_type_id']);
$entity_type = $entity_definition->getBundleEntityType();
if (empty($entity_type)) {
return AccessResult::neutral();
}
$entity_type_plugin = $this->pluginManager->getDefinition($entity_type, FALSE);
if (!$entity_type_plugin) {
return AccessResult::neutral();
}
$entity = $this->entityTypeManager->getStorage($entity_type_plugin['id'])->load($entity_bundle);
if (!$entity) {
return AccessResult::neutral();
}
return $this->checkAccess($entity, 'create', $account);
}
/**
* Check if the entity is accessible.
*/
private function checkAccess(EntityInterface $entity, string $operation, AccountInterface $account) {
// Check if the entity supports third party settings.
if (!method_exists($entity, 'getThirdPartySettings')) {
return AccessResult::neutral();
}
$type = $entity->getEntityTypeId();
$plugin = $this->pluginManager->getDefinition($type, FALSE);
// If we don't have a plugin defined for this entity type, return neutral.
if (!$plugin) {
return AccessResult::neutral();
}
// If the operation is not restricted, return neutral.
$restricted_operations = $plugin['restricted_operations'];
if (!in_array($operation, $restricted_operations)) {
return AccessResult::neutral();
}
// If we have no conditions set, return neutral.
$entity_access_conditions = $entity->getThirdPartySettings('entity_type_access_conditions') ?? [];
if (empty($entity_access_conditions)) {
return AccessResult::neutral();
}
// Evaluate the conditions.
$result = $this->conditionsEvaluator->evaluateConditions($entity_access_conditions);
// If the conditions are not met, return forbidden.
if ($result === FALSE) {
$access_result = AccessResult::forbidden();
$access_result->addCacheableDependency($entity);
return $access_result;
}
// Default to neutral.
return AccessResult::neutral();
}
}
