0

Is there a way to allow/prevent users to create a new entity based on an entity field? Because the checkCreateAccess() / hook_entity_create_access() function is not receiving the actual entity as a parameter, just the bundle.

Is is ok to do a check on 'hook_entity_presave()' and throw an exception there?

2
  • This sounds weird to me. My approach would be to limit the allowed values of the field before, instead of throwing a failure later when an invalid option is selected. See e.g. api.drupal.org/api/drupal/…
    – Hudri
    Commented Dec 19, 2019 at 11:59
  • This is not possible because the site will be used to handle REST requests and basically you can add any value you want. Commented Dec 19, 2019 at 12:12

2 Answers 2

0

Since the method invoking hook_entity_presave() already throws an exception, throwing an exception in hook_entity_presave() is safe, and it's going to tell Drupal an error is not allowing to save the entity.

protected function doPreSave(EntityInterface $entity) {
  $id = $entity->id();

  // Track the original ID.
  if ($entity->getOriginalId() !== NULL) {
    $id = $entity->getOriginalId();
  }

  // Track if this entity exists already.
  $id_exists = $this->has($id, $entity);

  // A new entity should not already exist.
  if ($id_exists && $entity->isNew()) {
    throw new EntityStorageException("'{$this->entityTypeId}' entity with ID '{$id}' already exists.");
  }

  // Load the original entity, if any.
  if ($id_exists && !isset($entity->original)) {
    $entity->original = $this->loadUnchanged($id);
  }

  // Allow code to run before saving.
  $entity->preSave($this);
  $this->invokeHook('presave', $entity);
  return $id;
}

It doesn't make sense to use an entity field to decide if a user is allowed to create an entity, though. It would mean that, basing on the value the user chooses for that field, the user is allowed, or not, to create the entity. hook_entity_presave() would also show the error message after the users filled the entity creation form and clicked on the _Save__ button, which is a way too late to tell them they cannot create an entity. (Users are used to Drupal not showing them a link to which they don't have access, or for an operation they don't have the permission to do.)

If instead of the actual entity field value, you are deciding if the user has the permission to create the entity basing on the default value of the entity field (which could change basing on the entity or its bundle), then EntityFieldManager::getFieldDefinitions() returns the list of entity fields (an array of objects implementing FieldDefinitionInterface), for which FieldDefinitionInterface::getDefaultValue() can be used to retrieve the default value an entity field gets when a new entity is created. (EntityFieldManager is the class that implements the _entity_field.manager_ service.)

Alternatively, instead of depending on the default value an entity field has, which has sense when also the current value of the entity field is used in someway, the code could check the value of a configuration entity (linked to the entity itself or its bundles) to decide which users can create the entity.
In this case, hook_entity_create_access() can be used, as it just needs to know which entity is going to be created, or which bundle of that entity will be created.

2
  • I am using this check because Drupal is used as an REST API, so the user can enter whatever he wants. I need to make sure he doesn't try to manually make calls to the server with wrong data. Commented Dec 23, 2019 at 9:59
  • 1
    Checking that an entity field has the correct values is done adding constrains to the entity field, as described in Providing a custom validation constraint.
    – apaderno
    Commented Dec 23, 2019 at 15:28
0

Use the rules module instead? https://www.drupal.org/project/rules

  1. Before saving entity of type X
  2. Entity has field Y
  3. Entity field Y is Z
  4. Allow, else deny
1
  • I think the Rules module will not be production ready for more than a year. Plus, I think that 1. Before saving entity of type is using either the hook_entity_presave() or hook_entity_update() Commented Dec 19, 2019 at 13:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.