civicrm_entity-8.x-3.0-beta1/civicrm_entity.module

civicrm_entity.module
<?php

/**
 * @file
 * Module file for the CiviCRM Entity module.
 */

use Drupal\civicrm_entity\CivicrmEntityAccessHandler;
use Drupal\civicrm_entity\CivicrmEntityListBuilder;
use Drupal\civicrm_entity\CiviCrmEntityViewBuilder;
use Drupal\civicrm_entity\CivicrmEntityViewsData;
use Drupal\civicrm_entity\CiviEntityStorage;
use Drupal\civicrm_entity\Entity\CivicrmEntity;
use Drupal\civicrm_entity\Entity\Sql\CivicrmEntityStorageSchema;
use Drupal\civicrm_entity\Form\CivicrmEntityForm;
use Drupal\civicrm_entity\Routing\CiviCrmEntityRouteProvider;
use Drupal\civicrm_entity\SupportedEntities;
use Drupal\Core\Database\Query\AlterableInterface;
use Drupal\Core\Entity\ContentEntityDeleteForm;
use Drupal\Core\Entity\ContentEntityType;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Entity\EntityDisplayRepositoryInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\FieldConfigInterface;
use Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay;
use Drupal\views\ViewExecutable;
use Drupal\views\Plugin\views\query\QueryPluginBase;
use Drupal\Core\Database\Database;
use Drupal\Core\Entity\Display\EntityDisplayInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\civicrm_entity\Plugin\search_api\datasource\CivicrmEntity as DatasourceCivicrmEntity;
use Drupal\Core\Field\Entity\BaseFieldOverride;

/**
 * Implements hook_theme().
 */
function civicrm_entity_theme() {
  return [
    'civicrm_entity_entity_form' => [
      'render element' => 'form',
    ],
    'civicrm_entity' => [
      'render element' => 'elements',
    ],
  ];
}

/**
 * Implements hook_entity_type_build().
 *
 * Populates supported CiviCRM Entity definitions.
 */
function civicrm_entity_entity_type_build(array &$entity_types) {
  $logger = \Drupal::logger('civicrm-entity');
  $supported_entities = SupportedEntities::getInfo();
  $config = \Drupal::config('civicrm_entity.settings');
  $enabled_entity_types = $config->get('enabled_entity_types') ?: [];
  $enable_links_per_type = $config->get('enable_links_per_type') ?: [];
  foreach ($supported_entities as $entity_type_id => $civicrm_entity_info) {
    $clean_entity_type_id = str_replace('_', '-', $entity_type_id);
    $civicrm_entity_name = $civicrm_entity_info['civicrm entity name'];

    if (empty($civicrm_entity_info['label property'])) {
      $logger->debug(sprintf('Missing label property: %s', $entity_type_id));
      continue;
    }

    $entity_type_info = [
      'provider' => 'civicrm_entity',
      'class' => CivicrmEntity::class,
      'originalClass' => CivicrmEntity::class,
      'id' => $entity_type_id,
      'component' => $civicrm_entity_info['component'] ?? NULL,
      'civicrm_entity' => $civicrm_entity_name,
      'civicrm_entity_ui_exposed' => in_array($entity_type_id, $enabled_entity_types),
      'label' => new TranslatableMarkup('CiviCRM :name', [':name' => $civicrm_entity_info['civicrm entity label']]),
      // @todo add label_singular
      // @todo add label_plural
      // @todo add label_count
      'entity_keys' => [
        'id' => 'id',
        'label' => $civicrm_entity_info['label property'],
      ],
      'base_table' => $entity_type_id,
      'admin_permission' => 'administer civicrm entity',
      'permission_granularity' => 'entity_type',
      'handlers' => [
        'storage' => CiviEntityStorage::class,
        'access' => CivicrmEntityAccessHandler::class,
        'views_data' => CivicrmEntityViewsData::class,
        'storage_schema' => CivicrmEntityStorageSchema::class,
      ],
    ];

    if (in_array($entity_type_id, $enabled_entity_types)) {
      $entity_type_info = array_merge_recursive($entity_type_info, [
        'handlers' => [
          'list_builder' => CivicrmEntityListBuilder::class,
          'view_builder' => CiviCrmEntityViewBuilder::class,
          'route_provider' => [
            'default' => CiviCrmEntityRouteProvider::class,
          ],
          'form' => [
            'default' => CivicrmEntityForm::class,
            'add' => CivicrmEntityForm::class,
            'edit' => CivicrmEntityForm::class,
            'delete' => ContentEntityDeleteForm::class,
          ],
        ],
        // Generate route paths.
        'links' => [
          'canonical' => sprintf('/%s/{%s}', $clean_entity_type_id, $entity_type_id),
          'delete-form' => sprintf('/%s/{%s}/delete', $clean_entity_type_id, $entity_type_id),
          'edit-form' => sprintf('/%s/{%s}/edit', $clean_entity_type_id, $entity_type_id),
          'add-form' => sprintf('/%s/add', $clean_entity_type_id, $entity_type_id),
          'collection' => sprintf('/admin/structure/civicrm-entity/%s', $clean_entity_type_id),
        ],
        'field_ui_base_route' => "entity.$entity_type_id.collection",
      ]);

      if (!empty($enable_links_per_type) && in_array($entity_type_id, array_keys($enable_links_per_type))) {
        $enable_links = array_filter($enable_links_per_type[$entity_type_id]['values']);

        if (!in_array('view', $enable_links)) {
          unset($entity_type_info['links']['canonical']);
        }

        if (!in_array('delete', $enable_links)) {
          unset($entity_type_info['links']['delete-form']);
        }

        if (!in_array('edit', $enable_links)) {
          unset($entity_type_info['links']['edit-form']);
        }

        if (!in_array('add', $enable_links)) {
          unset($entity_type_info['links']['add-form']);
        }
      }

      if ($config->get('disable_links')) {
        unset(
          $entity_type_info['links']['canonical'],
          $entity_type_info['links']['delete-form'],
          $entity_type_info['links']['edit-form'],
          $entity_type_info['links']['add-form'],
        );
      }
    }

    // If this entity has bundle support, we define the bundle field as "bundle"
    // and will use the "bundle property" as the field to fetch field options
    // from CiviCRM with.
    //
    // @see civicrm_entity_entity_bundle_info()
    // @see \Drupal\civicrm_entity\Entity\CivicrmEntity::baseFieldDefinitions()
    if (!empty($civicrm_entity_info['bundle property'])) {
      $entity_type_info['entity_keys']['bundle'] = 'bundle';
      $entity_type_info['civicrm_bundle_property'] = $civicrm_entity_info['bundle property'];
      if (isset($entity_type_info['links']['add-form'])) {
        // For entities with bundles that are exposed, add the `bundle` key to
        // the add-form route. In CiviCrmEntityRouteProvider::getAddFormRoute
        // we default the value, so that it isn't actually required in the URL.
        $entity_type_info['links']['add-form'] = sprintf('%s/{%s}', $entity_type_info['links']['add-form'], $entity_type_info['entity_keys']['bundle']);
      }
    }

    $entity_types[$entity_type_id] = new ContentEntityType($entity_type_info);
  }
}

/**
 * Implements hook_entity_bundle_info().
 */
function civicrm_entity_entity_bundle_info() {
  $transliteration = \Drupal::transliteration();
  /** @var \Drupal\civicrm_entity\CiviCrmApiInterface $civicrm_api */
  $civicrm_api = \Drupal::service('civicrm_entity.api');

  $bundles = [];
  $entity_types_with_bundles = array_filter(SupportedEntities::getInfo(), static function (array $civicrm_entity_info) {
    return !empty($civicrm_entity_info['bundle property']);
  });
  foreach ($entity_types_with_bundles as $entity_type_id => $civicrm_entity_info) {
    // We keep a bundle that is the same as the entity type ID. This allows us
    // to create fields as if this entity has no bundles.
    $bundles[$entity_type_id] = [
      $entity_type_id => [
        'label' => $civicrm_entity_info['civicrm entity label'],
      ],
    ];
    $options = $civicrm_api->getOptions($civicrm_entity_info['civicrm entity name'], $civicrm_entity_info['bundle property']);
    foreach ($options as $option) {
      $machine_name = SupportedEntities::optionToMachineName($option, $transliteration);
      $bundles[$entity_type_id][$machine_name]['label'] = $option;
    }
  }
  return $bundles;
}

/**
 * Implements hook_entity_bundle_field_info().
 *
 * This ensures CiviCRM Entity entity types have their field config instances
 * across all bundles. It's a copy of the Field module's logic, but clones
 * field config definitions.
 *
 * @see field_entity_bundle_field_info()
 */
function civicrm_entity_entity_bundle_field_info(EntityTypeInterface $entity_type, $bundle, array $base_field_definitions) {
  $result = [];
  if ($entity_type->get('civicrm_entity_ui_exposed') && $entity_type->hasKey('bundle')) {
    // Query by filtering on the ID as this is more efficient than filtering
    // on the entity_type property directly.
    $ids = \Drupal::entityQuery('field_config')
      ->condition('id', $entity_type->id() . '.', 'STARTS_WITH')
      ->accessCheck(FALSE)
      ->execute();
    // Fetch all fields and key them by field name.
    $field_configs = FieldConfig::loadMultiple($ids);

    // Clone the field configs, so that we can modify them and change the
    // target bundle type without manipulating the statically cached entries
    // in the entity storage;.
    $cloned_field_configs = array_map(static function (FieldConfigInterface $field) use ($bundle) {
      $cloned = clone $field;
      $cloned->set('bundle', $bundle);
      return $cloned;
    }, $field_configs);
    foreach ($cloned_field_configs as $field_instance) {
      $result[$field_instance->getName()] = $field_instance;
    }
  }
  // Ensure all fields have a definition.
  if ($entity_type->get('civicrm_entity_ui_exposed') && $entity_type->hasKey('bundle')) {
    foreach ($base_field_definitions as $field_name => $definition) {
      if (isset($result[$field_name])) {
        continue;
      }
      $field = BaseFieldOverride::createFromBaseFieldDefinition($base_field_definitions[$field_name], $bundle);
      $result[$field_name] = $field;
    }
  }
  return $result;
}

/**
 * Implements hook_entity_view_display_alter().
 *
 * There is no way to handle this in the entity type's view builder.
 */
function civicrm_entity_entity_view_display_alter(EntityViewDisplayInterface $display, array $context) {
  $entity_type = \Drupal::entityTypeManager()->getDefinition($context['entity_type']);
  assert($entity_type !== NULL);
  if ($entity_type->get('civicrm_entity') && $entity_type->hasKey('bundle')) {
    $entity_display_repository = \Drupal::service('entity_display.repository');
    assert($entity_display_repository instanceof EntityDisplayRepositoryInterface);
    $entity_view_mode_ids = array_keys($entity_display_repository->getViewModeOptions($entity_type->id()));
    $view_mode = !empty($context['view_mode']) && in_array($context['view_mode'], $entity_view_mode_ids) ? $context['view_mode'] : $entity_display_repository::DEFAULT_DISPLAY_MODE;
    $root_display = $entity_display_repository->getViewDisplay(
      $entity_type->id(),
      $entity_type->id(),
      $view_mode
    );
    $display->set('content', $root_display->get('content'));
    $display->set('hidden', $root_display->get('hidden'));

    if ($root_display instanceof LayoutBuilderEntityViewDisplay) {
      $layout_builder_settings = $root_display->getThirdPartySettings('layout_builder');
      foreach ($layout_builder_settings as $setting_key => $setting) {
        $display->setThirdPartySetting('layout_builder', $setting_key, $setting);
      }
    }
    $ds_settings = $root_display->getThirdPartySettings('ds');
    if (!empty($ds_settings) && is_array($ds_settings)) {
      foreach ($ds_settings as $setting_key => $setting) {
        $display->setThirdPartySetting('ds', $setting_key, $setting);
      }
    }
  }
}

/**
 * Implements hook_entity_view_alter().
 */
function civicrm_entity_entity_view_alter(array &$build, EntityInterface $entity, EntityDisplayInterface $display) {
  $entity_type = $entity->getEntityType();
  if ($entity_type->get('civicrm_entity') && $entity_type->hasKey('bundle') && \Drupal::moduleHandler()->moduleExists('field_group')) {
    $entity_display_repository = \Drupal::service('entity_display.repository');
    $entity_view_mode_ids = array_keys($entity_display_repository->getViewModeOptions($entity_type->id()));

    $context = [
      'entity_type' => $display->getTargetEntityTypeId(),
      'bundle' => $entity_type->id(),
      'entity' => $entity,
      'display_context' => 'view',
      'mode' => in_array($display->getMode(), $entity_view_mode_ids) ? $display->getMode() : $entity_display_repository::DEFAULT_DISPLAY_MODE,
    ];

    field_group_attach_groups($build, $context);
  }
}

/**
 * Implements hook_form_alter().
 */
function civicrm_entity_form_alter(array &$form, FormStateInterface $form_state, $form_id) {
  $form_object = $form_state->getFormObject();
  if ($form_object instanceof CivicrmEntityForm) {

    /**
     * @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $form_display
     */
    $storage = $form_state->getStorage();
    if (!empty($storage['form_display'])) {
      $form_display = $storage['form_display'];
      $entity = $form_object->getEntity();

      if ($entity->getEntityType()->hasKey('bundle') && \Drupal::moduleHandler()->moduleExists('field_group')) {
        $context = [
          'entity_type' => $entity->getEntityTypeId(),
          'bundle' => $entity->getEntityTypeId(),
          'entity' => $entity,
          'context' => 'form',
          'display_context' => 'form',
          'mode' => $form_display->getMode(),
        ];

        field_group_attach_groups($form, $context);
      }
    }
  }
}

/**
 * Implements hook_module_implements_alter().
 */
function civicrm_entity_module_implements_alter(&$implementations, $hook) {
  switch ($hook) {
    case 'form_alter':
      $group = $implementations['civicrm_entity'];
      unset($implementations['civicrm_entity']);
      $implementations['civicrm_entity'] = $group;
      break;
  }
}

/**
 * Implements callback_allowed_values_function().
 *
 * Provides the pseudoconstant values for CiviCRM entity fields.
 *
 * @param \Drupal\Core\Field\FieldStorageDefinitionInterface $definition
 *   The field storage definition.
 * @param \Drupal\Core\Entity\FieldableEntityInterface|null $entity
 *   The entity.
 * @param bool $cacheable
 *   If the options are cacheable.
 *
 * @return array
 *   The array of field options.
 */
function civicrm_entity_pseudoconstant_options(FieldStorageDefinitionInterface $definition, FieldableEntityInterface $entity = NULL, &$cacheable = NULL) {
  /** @var \Drupal\civicrm_entity\CiviCrmApiInterface $civicrm_api */
  $civicrm_api = \Drupal::service('civicrm_entity.api');
  $entity_type = \Drupal::entityTypeManager()->getDefinition($definition->getTargetEntityTypeId());
  $options = $civicrm_api->getOptions($entity_type->get('civicrm_entity'), $definition->getName());
  return $options;
}

/**
 * Implements hook_preprocess().
 */
function template_preprocess_civicrm_entity(&$variables) {
  // Add fields as content to template.
  $variables += ['content' => []];
  foreach (Element::children($variables['elements']) as $key) {
    $variables['content'][$key] = $variables['elements'][$key];
  }

  // Add the view_mode to the template.
  $variables['view_mode'] = $variables['elements']['#view_mode'];

  // Add the bundle to the template.
  $variables['entity_type'] = _civicrm_entity_get_entity_type_from_elements($variables['elements']);
}

/**
 * Implements hook_theme_suggestions_HOOK_alter().
 */
function civicrm_entity_theme_suggestions_civicrm_entity_alter(array &$suggestions, array $variables) {
  $view_mode = $variables['elements']['#view_mode'];
  $hook = $variables['theme_hook_original'];

  // Add a suggestion based on the entity type.
  if ($entity_type = _civicrm_entity_get_entity_type_from_elements($variables['elements'])) {
    $suggestions[] = $hook . '__' . $entity_type;

    // Add a suggestion based on the view mode.
    $suggestions[] = $hook . '__' . $entity_type . '__' . $view_mode;
  }
}

/**
 * Helper to find the entity type from $variables['elements'].
 */
function _civicrm_entity_get_entity_type_from_elements($elements) {
  if (isset($elements['#entity_type'])) {
    return $elements['#entity_type'];
  }

  // Find the CivicrmEntity from elements if #entity_type is not set.
  foreach ($elements as $element) {
    if ($element instanceof CivicrmEntity) {
      /** @var \Drupal\civicrm_entity\Entity\CivicrmEntity $element */
      return $element->getEntityTypeId();
    }
  }

  return NULL;
}

/**
 * For stashing deleted entities until we need them later.
 *
 * @todo Convert hooks to a service and keep this in a member variable
 *
 * @param string $objectName
 *   The CiviCRM entity type.
 * @param int $id
 *   The id.
 * @param \Drupal\Core\Entity\EntityInterface|null|string $entity
 *   The entity.
 *
 * @return void|\Drupal\Core\Entity\EntityInterface
 *   The cached entity object.
 */
function _civicrm_entity_stash($objectName, $id, $entity = NULL) {
  $cache =& drupal_static(__FUNCTION__, []);
  if (empty($entity)) {
    return $cache[$objectName][$id] ?? NULL;
  }
  elseif ($entity === 'clear') {
    unset($cache[$objectName][$id]);
  }
  else {
    $cache[$objectName][$id] = $entity;
  }
}

/**
 * Implements hook_civicrm_pre().
 */
function civicrm_entity_civicrm_pre($op, $objectName, $id, &$params) {
  if (\Drupal::config('civicrm_entity.settings')->get('disable_hooks')) {
    return;
  }

  $operations = ['create', 'edit', 'delete', 'restore'];
  if (!in_array($op, $operations)) {
    return;
  }

  $entityType = SupportedEntities::getEntityType($objectName);

  // Check valid entity type.
  if (!$entityType) {
    return;
  }

  /** @var \Drupal\civicrm_entity\CiviEntityStorage $storage */
  $storage = \Drupal::entityTypeManager()->getStorage($entityType);

  if ($op == 'create') {
    /** @var \Drupal\civicrm_entity\Entity\CivicrmEntity $entity */
    $entity = $storage->create($params);
  }
  elseif (empty($id)) {
    // Sometimes 'delete' is called with an $id of NULL, but we can't really do
    // anything with that in this context, so return.
    return;
  }
  else {
    // Special handling for EntityTag objects.
    if ($objectName == 'EntityTag') {
      if (isset($params['entity_id']) && isset($params['entity_table'])) {
        $id = $storage->getEntityTagEntityId($params['entity_id'], $params['entity_table']);
      }
      else {
        $id = $storage->getEntityTagEntityId($params[0][0], $params[1]);
      }
    }
    /** @var \Drupal\civicrm_entity\Entity\CivicrmEntity $entity */
    $entity = $storage->load($id);
  }
  if (!$entity) {
    return;
  }
  if ($entity->id()) {
    $entity->original = $storage->loadUnchanged($entity->id());
  }

  switch ($op) {
    case 'create':
      $storage->civiPreSave($entity);
      break;

    case 'delete':
      $storage->civiPreDelete($entity);
      _civicrm_entity_stash($objectName, $id, $entity);
      break;

    case 'restore':
      $storage->civiPreSave($entity);
      break;

    case 'edit':
      $storage->civiPreSave($entity);
      break;
  }
}

/**
 * Implements hook_civicrm_post().
 */
function civicrm_entity_civicrm_post($op, $objectName, $objectId, &$objectRef) {
  if (\Drupal::config('civicrm_entity.settings')->get('disable_hooks')) {
    return;
  }

  $operations = ['create', 'edit', 'delete', 'restore'];
  if (!in_array($op, $operations)) {
    return;
  }

  $entityType = SupportedEntities::getEntityType($objectName);

  // Check valid entity type.
  if (!$entityType) {
    return;
  }

  /** @var \Drupal\civicrm_entity\CiviEntityStorage $storage */
  $storage = \Drupal::entityTypeManager()->getStorage($entityType);

  // Fix because $objectId is not set for participant payments, possibly other
  // entity types.
  if (!$objectId) {
    // If we cannot determine the id, bail.
    if (empty($objectRef->id)) {
      return;
    }
    $objectId = $objectRef->id;
  }

  if ($op == 'delete') {
    /** @var \Drupal\civicrm_entity\Entity\CivicrmEntity $entity */
    $entity = _civicrm_entity_stash($objectName, $objectId);
  }
  else {
    // Special handling for EntityTag objects.
    if ($entityType == 'civicrm_entity_tag' && is_array($objectRef)) {
      foreach ($objectRef[0] as $entityTag) {
        $object = new CRM_Core_BAO_EntityTag();
        $object->entity_id = $entityTag;
        $object->entity_table = 'civicrm_contact';
        $object->tag_id = $objectId;
        if ($object->find(TRUE)) {
          /** @var \Drupal\civicrm_entity\Entity\CivicrmEntity $entity */
          $entity = $storage->load($object->id);
          $entity->original = $storage->loadUnchanged($entity->id());
          _civicrm_entity_post_invoke($op, $storage, $entity);
        }
      }
      return;
    }
    /** @var \Drupal\civicrm_entity\Entity\CivicrmEntity $entity */
    $entity = $storage->load($objectId);
    if ($entity) {
      $entity->original = $storage->loadUnchanged($entity->id());
    }
  }
  if ($entity) {
    _civicrm_entity_post_invoke($op, $storage, $entity);
  }
  _civicrm_entity_stash($objectName, $objectId, 'clear');
}

/**
 * Invokes the post save hooks for a CiviCRM entity.
 *
 * @param string $op
 *   The operation being performed.
 * @param \Drupal\civicrm_entity\CiviEntityStorage $storage
 *   The entity storage.
 * @param \Drupal\Core\Entity\EntityInterface $entity
 *   The entity.
 */
function _civicrm_entity_post_invoke($op, CiviEntityStorage $storage, EntityInterface $entity) {
  switch ($op) {
    case 'create':
      $storage->civiPostSave($entity, FALSE);
      break;

    case 'delete':
      $storage->civiPostDelete($entity);
      break;

    case 'restore':
      $storage->civiPostSave($entity, TRUE);
      break;

    case 'edit':
      $storage->civiPostSave($entity, TRUE);
      break;
  }
}

/**
 * Implements hook_views_query_alter().
 */
function civicrm_entity_views_query_alter(ViewExecutable $view, QueryPluginBase $query) {
  // Provide fully qualified table name in all Views queries.
  // If CiviCRM tables in a separate database.
  $civicrm_connection_name = drupal_valid_test_ua() ? 'civicrm_test' : 'civicrm';
  $civicrm_database_info = Database::getConnectionInfo($civicrm_connection_name);
  if (isset($civicrm_database_info['default']) && method_exists($query, "getTableQueue")) {
    $civicrm_connection = Database::getConnection('default', $civicrm_connection_name);
    $table_queue =& $query->getTableQueue();
    foreach ($table_queue as $alias => &$table_info) {
      if (!empty($table_info['table']) && ((strpos($table_info['table'], 'civicrm_') === 0 && strpos($table_info['table'], '.') === FALSE && strpos($table_info['table'], '__') === FALSE) || strpos($table_info['table'], 'civicrm_value_') === 0)) {
        $table_info['table'] = $civicrm_connection->getFullQualifiedTableName($table_info['table']);
      }
      if (!empty($table_info['join']->table) && ((strpos($table_info['join']->table, 'civicrm_') === 0 && strpos($table_info['join']->table, '.') === FALSE && strpos($table_info['join']->table, '__') === FALSE) || strpos($table_info['join']->table, 'civicrm_value_') === 0)) {
        $table_info['join']->table = $civicrm_connection->getFullQualifiedTableName($table_info['join']->table);
      }
    }
  }

  \Drupal::service('civicrm')->initialize();
  $multilingual = \CRM_Core_I18n::isMultilingual();

  if ($multilingual) {
    // @codingStandardsIgnoreStart
    global $dbLocale;
    // @codingStandardsIgnoreEnd
    $columns = CRM_Core_I18n_SchemaStructure::columns();
    $affectedColumns = [];
    foreach ($columns as $table => $hash) {
      foreach (array_keys($hash) as $column) {
        $affectedColumns[] = "{$table}.{$column}";
      }
    }
    $class = get_class($query);
    if ($class == 'Drupal\search_api\Plugin\views\query\SearchApiQuery' && method_exists($query, "getWhere")) {
      $where = $query->getWhere();
    }
    elseif (isset($query->where)) {
      $where = $query->where;
    }
    if (!empty($where)) {
      foreach ($where as &$condition_group) {
        foreach ($condition_group['conditions'] as &$condition) {
          if (!is_object($condition['field'])) {
            foreach ($affectedColumns as $aff_column) {
              if (strpos($aff_column, $condition['field']) !== FALSE) {
                $condition['field'] = str_replace($aff_column, $aff_column . $dbLocale, $condition['field']);
              }
            }
          }
        }
      }
    }

    if (!empty($query->fields)) {
      foreach ($query->fields as &$field) {
        if (array_key_exists($field['table'], $columns) && array_key_exists($field['field'], $columns[$field['table']])) {
          $field['field'] .= $dbLocale;
        }
      }
    }
  }
}

/**
 * Implements hook_theme_registry_alter().
 */
function civicrm_entity_theme_registry_alter(&$theme_registry) {
  $theme_registry['civicrm_entity']['preprocess functions'][] = 'field_group_build_entity_groups';
}

/**
 * Implements hook_rebuild().
 *
 * This resets the field storage and entity type definitions for civicrm_entity
 * according to the active definitions to avoid mismatches since the definitions
 * are not necessary to be updated.
 */
function civicrm_entity_rebuild() {
  /** @var \Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface $entity_last_installed_repository */
  $entity_last_installed_repository = \Drupal::service('entity.last_installed_schema.repository');
  /** @var \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager */
  $entity_field_manager = \Drupal::service('entity_field.manager');
  /** @var \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager */
  $entity_type_manager = \Drupal::service('entity_type.manager');

  $supported_entities = SupportedEntities::getInfo();

  foreach (array_keys($supported_entities) as $entity_type_id) {
    // Reset field storage definitions.
    $field_storage_definitions = $entity_field_manager->getFieldStorageDefinitions($entity_type_id);
    $entity_last_installed_repository->setLastInstalledFieldStorageDefinitions($entity_type_id, $field_storage_definitions);

    // Reset entity type definition.
    $definition = $entity_type_manager->getDefinition($entity_type_id);
    $entity_last_installed_repository->setLastInstalledDefinition($definition);
  }
}

/**
 * Implements hook_rules_action_info_alter().
 */
function civicrm_entity_rules_action_info_alter(&$rules_actions) {
  $definitions = \Drupal::service('plugin.manager.typed_data_filter')->getDefinitions();
  $filters = "";
  foreach ($definitions as $key) {
    if ($key['provider'] == 'civicrm_entity') {
      $filters .= ($filters == '' ? '' : ', ') . $key['id'];
    }
  }
  if (array_key_exists('format', $rules_actions['civicrm_entity_user_create']['context_definitions'])) {
    // Drupal 9 use 'context_definitions' instead of 'context'.
    $rules_actions['civicrm_entity_user_create']['context_definitions']['format']->setDescription(t('Format of the username. Use <a href="@url">Twig style</a> tokens for using the available data.<br>Civicrm Entity filter available : @filters.',
      [
        '@url' => 'https://www.drupal.org/docs/8/modules/typed-data-api-enhancements/typeddata-tokens',
        '@filters' => $filters,
      ]));
  }
  else {
    $rules_actions['civicrm_entity_user_create']['context']['format']->setDescription(t('Format of the username. Use <a href="@url">Twig style</a> tokens for using the available data.<br>Civicrm Entity filter available : @filters.',
      [
        '@url' => 'https://www.drupal.org/docs/8/modules/typed-data-api-enhancements/typeddata-tokens',
        '@filters' => $filters,
      ]));
  }
}

/**
 * Implements hook_search_api_datasource_info_alter().
 */
function civicrm_entity_search_api_datasource_info_alter(array &$infos) {
  foreach ($infos as $entity_type => &$info) {
    if (strpos($entity_type, 'entity:civicrm_') !== FALSE) {
      unset($info['deriver']);
      $info['class'] = DatasourceCivicrmEntity::class;
    }
  }
}

/**
 * Implements hook_civicrm_merge().
 */
function civicrm_entity_civicrm_merge($mode, &$sqls, $mainId = NULL, $otherId = NULL, $tables = NULL) {
  if ($mode == 'sqls' && !empty($mainId) && !empty($otherId)) {
    // Get List if civicrm contact entity reference field.
    $entityRefFields = \Drupal::entityTypeManager()->getStorage('field_storage_config')
      ->loadByProperties([
        'type' => 'entity_reference',
        'settings' => ['target_type' => 'civicrm_contact'],
      ]);

    // Iterate fields and prepare the array.
    foreach ($entityRefFields as $entityRefField) {
      // Get Field name.
      $fieldName = $entityRefField->getName();
      // Get Type, Node etc..
      $entityRefType = $entityRefField->getTargetEntityTypeId();
      $options[$entityRefType][] = $fieldName;
    }

    foreach ($options as $type => $fields) {
      foreach ($fields as $field) {
        try {
          // $otherId is duplicate contact ID
          $ids = \Drupal::entityQuery($type)
            ->condition($field, $otherId, '=')
            ->accessCheck(FALSE)
            ->execute();
          if (!empty($ids)) {
            $entityRecords = Drupal::entityTypeManager()->getStorage($type)
              ->loadMultiple($ids);
            foreach ($entityRecords as $entityRecord) {
              // Update new contact.
              // Target Contact.
              try {
                $entityRecord->set($field, $mainId);
                $entityRecord->save();
              }
              catch (\Exception $e) {
                \Drupal::logger('civicrm_entity')->error($e->getMessage());
              }
            }
          }
        }
        catch (\Exception $e) {
          \Drupal::logger('civicrm_entity')->error($e->getMessage());
        }
      }
    }
  }
}

/**
 * Implements hook_query_TAG_alter().
 */
function civicrm_entity_query_pathauto_bulk_update_alter(AlterableInterface $query) {
  $tables = &$query->getTables();

  if (strpos($tables['base_table']['table'], 'civicrm_') !== FALSE) {
    $civicrm_connection_name = drupal_valid_test_ua() ? 'civicrm_test' : 'civicrm';
    $civicrm_database_info = Database::getConnectionInfo($civicrm_connection_name);
    if (isset($civicrm_database_info['default'])) {
      $connection = Database::getConnection('default', $civicrm_connection_name);
      $tables['base_table']['table'] = $connection->getFullQualifiedTableName($tables['base_table']['table']);
    }
  }
}

/**
 * Implements hook_query_TAG_alter().
 */
function civicrm_entity_query_pathauto_bulk_delete_alter(AlterableInterface $query) {
  $tables = &$query->getTables();

  if (strpos($tables['base_table']['table'], 'civicrm_') !== FALSE) {
    $civicrm_connection_name = drupal_valid_test_ua() ? 'civicrm_test' : 'civicrm';
    $civicrm_database_info = Database::getConnectionInfo($civicrm_connection_name);
    if (isset($civicrm_database_info['default'])) {
      $connection = Database::getConnection('default', $civicrm_connection_name);
      $tables['base_table']['table'] = $connection->getFullQualifiedTableName($tables['base_table']['table']);
    }
  }
}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc