You are here

farm_entity.module in farmOS 2.x

Contains farm_entity.module.

File

modules/core/entity/farm_entity.module
View source
<?php

/**
 * @file
 * Contains farm_entity.module.
 */
use Drupal\Core\Entity\ContentEntityFormInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\entity\EntityAccessControlHandler;
use Drupal\entity\EntityPermissionProvider;
use Drupal\farm_entity\BundlePlugin\FarmEntityBundlePluginHandler;
use Drupal\farm_entity\Routing\DefaultHtmlRouteProvider;

/**
 * Implements hook_module_implements_alter().
 */
function farm_entity_module_implements_alter(&$implementations, $hook) {

  // Make sure this module's hook_entity_type_build() runs before the
  // entity module's implementation, so that we can override the bundle plugin
  // handler, and so that we can set the Log entity type's bundle_plugin_type.
  $module = 'farm_entity';
  if ($hook == 'entity_type_build') {
    $implementation = [
      $module => $implementations[$module],
    ];
    unset($implementations[$module]);
    $implementations = array_merge($implementation, $implementations);
  }
}

/**
 * Implements hook_entity_type_build().
 */
function farm_entity_entity_type_build(array &$entity_types) {

  /** @var \Drupal\Core\Entity\EntityTypeInterface[] $entity_types */

  // Allow the "view label" operation on the bundle entity type.
  foreach ([
    'asset',
    'log',
    'plan',
    'quantity',
    'data_stream',
  ] as $entity_type) {
    if (!empty($entity_types[$entity_type])) {
      $bundle_entity_type = $entity_types[$entity_type]
        ->getBundleEntityType();
      $entity_types[$bundle_entity_type]
        ->setHandlerClass('access', EntityAccessControlHandler::class);
      $entity_types[$bundle_entity_type]
        ->setHandlerClass('permission_provider', EntityPermissionProvider::class);
    }
  }

  // Enable the use of bundle plugins on specific entity types.
  foreach ([
    'asset',
    'log',
    'plan',
    'quantity',
  ] as $entity_type) {
    if (!empty($entity_types[$entity_type])) {
      $entity_types[$entity_type]
        ->set('bundle_plugin_type', $entity_type . '_type');
      $entity_types[$entity_type]
        ->setHandlerClass('bundle_plugin', FarmEntityBundlePluginHandler::class);

      // Deny access to the entity type add form. New entity types of entities
      // with bundle plugins cannot be created in the UI.
      // See https://www.drupal.org/project/farm/issues/3196423
      $bundle_entity_type = $entity_types[$entity_type]
        ->getBundleEntityType();
      $route_providers = $entity_types[$bundle_entity_type]
        ->getRouteProviderClasses();
      $route_providers['default'] = DefaultHtmlRouteProvider::class;
      $entity_types[$bundle_entity_type]
        ->setHandlerClass('route_provider', $route_providers);
    }
  }
}

/**
 * Implements hook_entity_field_storage_info_alter().
 *
 * @todo https://www.drupal.org/project/farm/issues/3194206
 */
function farm_entity_entity_field_storage_info_alter(&$fields, EntityTypeInterface $entity_type) {

  // Bail if not a farm entity type that allows bundle plugins.
  if (!in_array($entity_type
    ->id(), [
    'log',
    'asset',
    'plan',
    'quantity',
  ])) {
    return;
  }

  // Get all bundles of the entity type.
  $bundles = \Drupal::service('entity_type.bundle.info')
    ->getBundleInfo($entity_type
    ->id());

  // Get all modules that provide bundle fields.
  $modules = \Drupal::moduleHandler()
    ->getImplementations('farm_entity_bundle_field_info');

  // Invoke the hook for each module with each bundle.
  foreach ($modules as $module) {
    foreach (array_keys($bundles) as $bundle) {
      $definitions = \Drupal::moduleHandler()
        ->invoke($module, 'farm_entity_bundle_field_info', [
        $entity_type,
        $bundle,
      ]);

      // Set the provider for each field the module provided.
      // This is required so that field storage definitions are created in the
      // database when the module is installed.
      foreach (array_keys($definitions) as $field) {
        if (isset($fields[$field])) {
          $fields[$field]
            ->setProvider($module);
        }
      }
    }
  }
}

/**
 * Implements hook_entity_presave().
 *
 * Forces revisions on all farm entities if the entity type supports them and
 * the bundle has them enabled. This removes the option for users to disable a
 * revision per-entity but as JSON:API doesn't support revisions yet, this is a
 * trade-off that allows us to create revisions consistently on both the UI and
 * the API.
 */
function farm_entity_entity_presave(EntityInterface $entity) {

  // Only apply to farm controlled entities.
  $entity_types = [
    'asset',
    'log',
    'plan',
    'quantity',
  ];
  if (!in_array($entity
    ->getEntityTypeId(), $entity_types)) {
    return;
  }

  // Force create new revision as json api doesn't do that by default.
  // @see https://www.drupal.org/project/drupal/issues/2993557
  // @see https://www.drupal.org/project/drupal/issues/2795279
  // @see https://github.com/json-api/json-api/pull/824
  if ($entity->type->entity
    ->shouldCreateNewRevision() && $entity
    ->getEntityType()
    ->isRevisionable()) {

    /** @var \Drupal\Core\Entity\RevisionLogInterface $entity */

    // Always create a new revision.
    $entity
      ->setNewRevision(TRUE);

    // If the new revision log message matches the original, then set a blank
    // revision log message. We don't want the same message repeated across
    // every revision created by the API.
    if (!empty($entity->original)) {
      if ($entity->original
        ->get('revision_log_message')->value == $entity
        ->get('revision_log_message')->value) {
        $entity
          ->setRevisionLogMessage('');
      }
    }

    // Set the user ID and creation time.
    $entity
      ->setRevisionUserId(\Drupal::currentUser()
      ->getAccount()
      ->id());
    $entity
      ->setRevisionCreationTime(\Drupal::time()
      ->getRequestTime());
  }
}

/**
 * Implements hook_form_alter().
 *
 * Hides the revision control from the user, @see farm_entity_entity_presave()
 */
function farm_entity_form_alter(&$form, FormStateInterface $form_state, $form_id) {

  // Only alter content entity forms.
  $form_object = $form_state
    ->getFormObject();
  if (!$form_object instanceof ContentEntityFormInterface) {
    return;
  }

  // Only apply to farm controlled entities.
  $entity = $form_object
    ->getEntity();
  $entity_types = [
    'asset',
    'log',
    'plan',
    'quantity',
  ];
  if (!in_array($entity
    ->getEntityTypeId(), $entity_types)) {
    return;
  }

  // Disable access to the revision checkbox.
  $form['revision']['#access'] = FALSE;
}