You are here

eck.module in Entity Construction Kit (ECK) 8

Same filename and directory in other branches
  1. 7.3 eck.module
  2. 7 eck.module
  3. 7.2 eck.module

Contains hook implementations.

File

eck.module
View source
<?php

/**
 * @file
 * Contains hook implementations.
 */
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Config\Entity\ConfigEntityType;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Entity\ContentEntityType;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Url;
use Drupal\eck\ArrayDeprecationWrapper;
use Drupal\eck\Entity\EckEntity;
use Drupal\eck\Entity\EckEntityType;
use Drupal\field\Plugin\migrate\source\d7\Field;
use Drupal\field\Plugin\migrate\source\d7\FieldInstance;
use Drupal\migrate_drupal\Plugin\migrate\FieldMigration;

/**
 * Defines the online documentation url of the ECK module.
 */
const ECK_DOCUMENTATION_PAGE = 'https://drupal.org/node/1366144';

/**
 * Defines the max length of entity id machine name.
 */
const ECK_ENTITY_ID_MAX_LENGTH = 27;

/**
 * Implements hook_help().
 */
function eck_help($route_name, RouteMatchInterface $route_match) {
  switch ($route_name) {
    case 'help.page.eck':
      $output = '<h3>' . t('About') . '</h3>';
      $output .= '<p>' . t('The Entity Construction Kit (ECK) builds upon the entity system to create a flexible and extensible data modeling system both with a UI for site builders, and with useful abstractions (classes, plugins, etc) to help developers use entities with ease. For more information, see the <a href="@eck">online documentation for the ECK module</a>.', [
        '@eck' => ECK_DOCUMENTATION_PAGE,
      ]) . '</p>';
      break;
    default:
      break;
  }
  return !empty($output) ? $output : '';
}

/**
 * Implements hook_entity_type_build().
 */
function eck_entity_type_build(array &$entity_types) {
  static $recursionDepth;

  // Infinite loops can occur when workspaces module is enabled. We therefore
  // keep track of the number of times this function is called without being
  // completed. We know we're in an infinite recursion when that number grows
  // beyond 1, so we just return early to break out of the recursion.
  if ($recursionDepth++ > 2) {
    return;
  }

  // Check for eck_entity_type config entity.
  if (!empty($entity_types['eck_entity_type'])) {
    $eck_entity_type = $entity_types['eck_entity_type'];
    $eck_types = \Drupal::entityTypeManager()
      ->createHandlerInstance($eck_entity_type
      ->getHandlerClass('storage'), $eck_entity_type)
      ->loadMultiple();

    // Base definitions for the entity type.
    $base_definition = [
      'handlers' => [
        'view_builder' => 'Drupal\\Core\\Entity\\EntityViewBuilder',
        'form' => [
          'default' => 'Drupal\\eck\\Form\\Entity\\EckEntityForm',
          'edit' => 'Drupal\\eck\\Form\\Entity\\EckEntityForm',
          'delete' => 'Drupal\\eck\\Form\\Entity\\EckEntityDeleteForm',
        ],
        'list_builder' => 'Drupal\\eck\\Controller\\EckEntityListBuilder',
        'access' => 'Drupal\\eck\\EckEntityAccessControlHandler',
        'views_data' => 'Drupal\\views\\EntityViewsData',
        'translation' => 'Drupal\\content_translation\\ContentTranslationHandler',
        'route_provider' => [
          'html' => 'Drupal\\eck\\Entity\\EckEntityRouteProvider',
        ],
      ],
      'entity_keys' => [
        'id' => 'id',
        'bundle' => 'type',
        'label' => 'title',
        'uuid' => 'uuid',
        'langcode' => 'langcode',
        'published' => 'status',
      ],
      'translatable' => TRUE,
      'provider' => 'eck',
      'class' => 'Drupal\\eck\\Entity\\EckEntity',
    ];

    // Base definitions for bundles.
    $bundle_base_definition = [
      'entity_keys' => [
        'id' => 'type',
        'label' => 'name',
      ],
      'provider' => 'eck',
      'class' => 'Drupal\\eck\\Entity\\EckEntityBundle',
      'handlers' => [
        'form' => [
          'add' => 'Drupal\\eck\\Form\\EntityBundle\\EckEntityBundleForm',
          'edit' => 'Drupal\\eck\\Form\\EntityBundle\\EckEntityBundleForm',
          'delete' => 'Drupal\\eck\\Form\\EntityBundle\\EckEntityBundleDeleteConfirm',
          'default' => 'Drupal\\eck\\Form\\Entity\\EckEntityForm',
        ],
        'list_builder' => 'Drupal\\eck\\Controller\\EckEntityBundleListBuilder',
        'access' => 'Drupal\\eck\\EckBundleAccessControlHandler',
      ],
      'admin_permission' => 'administer eck entity bundles',
    ];

    // Add custom particular definitions for each entity.
    foreach ($eck_types as $eck_type) {

      // Definitions for the entity type.
      $definition = [
        'id' => $eck_type->id,
        'label' => t($eck_type->label),
        'bundle_label' => t('@eck_type type', [
          '@eck_type' => $eck_type->label,
        ]),
        'base_table' => $eck_type->id,
        'data_table' => $eck_type->id . '_field_data',
        'links' => [
          'canonical' => "/{$eck_type->id}/{{$eck_type->id}}",
          'edit-form' => "/{$eck_type->id}/{{$eck_type->id}}/edit",
          'delete-form' => "/{$eck_type->id}/{{$eck_type->id}}/delete",
        ],
        'bundle_entity_type' => $eck_type->id . '_type',
        'field_ui_base_route' => 'entity.' . $eck_type->id . '_type.edit_form',
        'permission_granularity' => 'bundle',
        'group' => 'content',
        'group_label' => t('Content'),
      ];

      // Merge the definitions.
      $definition = array_merge($definition, $base_definition);

      // Add the new content entity to the entity types.
      $entity_types[$definition['id']] = new ContentEntityType($definition);

      // Definitions for the entity types bundle.
      $bundle_definition = [
        'id' => $eck_type->id . '_type',
        'label' => t('@entity_type type', [
          '@entity_type' => $eck_type->label,
        ]),
        'bundle_of' => $eck_type->id,
        'config_prefix' => 'eck_type.' . $eck_type->id,
        'group' => 'configuration',
        'group_label' => t('Configuration'),
        'links' => [
          'edit-form' => '/admin/structure/eck/entity/' . $eck_type->id . '/bundles/{' . $eck_type->id . '_type}/edit',
          'delete-form' => '/admin/structure/eck/entity/' . $eck_type->id . '/bundles/{' . $eck_type->id . '_type}/delete',
          'collection' => '/admin/structure/eck/' . $eck_type->id . '/bundles',
        ],
        'config_export' => [
          'type',
          'name',
          'description',
        ],
      ];

      // Merge the definitions.
      $bundle_definition = array_merge($bundle_definition, $bundle_base_definition);

      // Add the new content entity to the entity types.
      $entity_types[$bundle_definition['id']] = new ConfigEntityType($bundle_definition);
    }
  }

  // We reset the recursion depth tracker to ensure consecutive calls to this
  // function don't return without processing.
  $recursionDepth = 0;
}

/**
 * Implements hook_menu_local_actions_alter().
 */
function eck_menu_local_actions_alter(&$local_actions) {
  $eck_types = EckEntityType::loadMultiple();

  /** @var \Drupal\eck\EckEntityTypeBundleInfo $eckBundleInfo */
  $eckBundleInfo = Drupal::service('eck.entity_type.bundle.info');
  $defaults = [
    'class' => 'Drupal\\Core\\Menu\\LocalActionDefault',
    'provider' => 'eck',
    'options' => [],
    'weight' => 0,
  ];

  /* @var string $name */

  /* @var \Drupal\eck\Entity\EckEntity $type */
  foreach ($eck_types as $name => $type) {
    $local_actions['eck.bundle.' . $type
      ->id() . '.add'] = $defaults + [
      'id' => 'eck.bundle.' . $type
        ->id() . '.add',
      'route_name' => 'eck.entity.' . $type
        ->id() . '_type.add',
      'title' => t('Add @label bundle', [
        '@label' => $type
          ->label(),
      ]),
      'appears_on' => [
        'eck.entity.' . $type
          ->id() . '_type.list',
      ],
    ];
    if ($eckBundleInfo
      ->entityTypeHasBundles($type
      ->id())) {
      $bundle_machine_names = $eckBundleInfo
        ->getEntityTypeBundleMachineNames($type
        ->id());
      $local_actions['eck.' . $type
        ->id() . '.add'] = $defaults + [
        'id' => 'eck.' . $type
          ->id() . '.add',
        'title' => t('Add @label', [
          '@label' => $type
            ->label(),
        ]),
        'appears_on' => [
          'eck.entity.' . $type
            ->id() . '.list',
        ],
        'route_parameters' => [
          'eck_entity_type' => $type
            ->id(),
        ],
      ];
      if (count($bundle_machine_names) === 1) {
        $local_actions['eck.' . $type
          ->id() . '.add']['route_name'] = 'eck.entity.add';
        $local_actions['eck.' . $type
          ->id() . '.add']['route_parameters']['eck_entity_bundle'] = reset($bundle_machine_names);
      }
      else {
        $local_actions['eck.' . $type
          ->id() . '.add']['route_name'] = 'eck.entity.add_page';
      }
    }
  }
}

/**
 * Implements hook_entity_view_alter().
 */
function eck_entity_view_alter(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display) {
  if ($entity instanceof EckEntity) {

    // Generalize the entity-type-specific defaults for easier default theming.
    $build['#theme'] = 'eck_entity';
    $build['#eck_entity'] = $entity;
  }
}

/**
 * Implements hook_theme().
 */
function eck_theme() {
  $templates['eck_entity'] = [
    'render element' => 'elements',
  ];
  $templates['eck_content_add_list'] = [
    'variables' => [
      'content' => NULL,
      'entity_type' => NULL,
    ],
    'file' => 'eck.pages.inc',
  ];
  return $templates;
}

/**
 * Implements hook_theme_suggestions_HOOK().
 */
function eck_theme_suggestions_eck_entity(array $variables) {

  /** @var \Drupal\eck\Entity\EckEntity $entity */
  $entity = $variables['elements']['#eck_entity'];
  $sanitized_view_mode = strtr($variables['elements']['#view_mode'], '.', '_');
  $suggestions[] = 'eck_entity__' . $sanitized_view_mode;
  $suggestions[] = 'eck_entity__' . $entity
    ->getEntityTypeId();
  $suggestions[] = 'eck_entity__' . $entity
    ->getEntityTypeId() . '__' . $sanitized_view_mode;
  $suggestions[] = 'eck_entity__' . $entity
    ->getEntityTypeId() . '__' . $entity
    ->bundle();
  $suggestions[] = 'eck_entity__' . $entity
    ->getEntityTypeId() . '__' . $entity
    ->bundle() . '__' . $sanitized_view_mode;
  $suggestions[] = 'eck_entity__' . $entity
    ->id();
  $suggestions[] = 'eck_entity__' . $entity
    ->id() . '__' . $sanitized_view_mode;
  return $suggestions;
}

/**
 * Implements template_preprocess_HOOK().
 */
function template_preprocess_eck_entity(&$variables) {
  $variables['eck_entity'] = $variables['elements']['#eck_entity'];
  $variables['entity_type'] = $variables['eck_entity']
    ->getEntityTypeId();
  $variables['bundle'] = $variables['eck_entity']
    ->bundle();
  $variables['view_mode'] = $variables['elements']['#view_mode'];

  // Build the $content variable for templates.
  $variables += [
    'content' => [],
  ];
  foreach (Element::children($variables['elements']) as $key) {
    $variables['content'][$key] = $variables['elements'][$key];
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 *
 * Alters the theme form to use the admin theme on eck editing.
 *
 * @see eck_form_system_themes_admin_form_submit()
 */
function eck_form_system_themes_admin_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  $form['admin_theme']['eck_use_admin_theme'] = [
    '#type' => 'checkbox',
    '#title' => t('Use the administration theme when editing or creating ECK entities'),
    '#description' => t('Control which roles can "View the administration theme" on the <a href=":permissions">Permissions page</a>.', [
      ':permissions' => Url::fromRoute('user.admin_permissions')
        ->toString(),
    ]),
    '#default_value' => \Drupal::configFactory()
      ->getEditable('eck.settings')
      ->get('use_admin_theme'),
  ];
  $form['#submit'][] = 'eck_form_system_themes_admin_form_submit';
}

/**
 * Form submission handler for system_themes_admin_form().
 *
 * @see eck_form_system_themes_admin_form_alter()
 */
function eck_form_system_themes_admin_form_submit($form, FormStateInterface $form_state) {
  \Drupal::configFactory()
    ->getEditable('eck.settings')
    ->set('use_admin_theme', $form_state
    ->getValue('eck_use_admin_theme'))
    ->save();
  \Drupal::service('router.builder')
    ->setRebuildNeeded();
}

/**
 * Implements hook_jsonapi_entity_filter_access() for all eck entities.
 */
function eck_jsonapi_entity_filter_access(ContentEntityType $entity_type, AccountInterface $account) {
  $result = [];
  if ($entity_type
    ->getProvider() == 'eck') {
    $result = [
      JSONAPI_FILTER_AMONG_ALL => AccessResult::allowedIfHasPermission($account, "view any {$entity_type->id()} entities"),
      JSONAPI_FILTER_AMONG_OWN => AccessResult::allowedIfHasPermission($account, "view own {$entity_type->id()} entities"),
    ];
  }
  return $result;
}

/**
 * Implements hook_migration_plugins_alter().
 */
function eck_migration_plugins_alter(array &$migrations) {
  foreach ($migrations as $key => &$migration) {

    // Do not alter a migration that is already configured.
    if (strstr($key, 'migration_config_deriver:')) {
      continue;
    }

    /** @var \Drupal\migrate\Plugin\MigrationPluginManager $migration_plugin_manager */
    $migration_plugin_manager = \Drupal::service('plugin.manager.migration');
    $migration_stub = $migration_plugin_manager
      ->createStubMigration($migration);

    /** @var \Drupal\migrate\Plugin\MigrateSourcePluginManager $source_plugin_manager */
    $source_plugin_manager = \Drupal::service('plugin.manager.migrate.source');
    $source = NULL;
    $configuration = $migration['source'];
    $source = $source_plugin_manager
      ->createInstance($migration['source']['plugin'], $configuration, $migration_stub);
    if ($source) {
      if (is_a($migration['class'], FieldMigration::class, TRUE)) {

        // Field storage.
        if (is_a($source, Field::class)) {
          $migration['migration_dependencies']['required'][] = 'd7_eck_type';
        }

        // Field instance.
        if (get_class($source) === FieldInstance::class) {
          $migration['migration_dependencies']['required'][] = 'd7_eck_bundle';
        }
      }
    }
  }
}

Functions

Constants

Namesort descending Description
ECK_DOCUMENTATION_PAGE Defines the online documentation url of the ECK module.
ECK_ENTITY_ID_MAX_LENGTH Defines the max length of entity id machine name.