crm_core-8.x-3.x-dev/modules/crm_core_contact/src/Plugin/Action/MergeContactsAction.php

modules/crm_core_contact/src/Plugin/Action/MergeContactsAction.php
<?php

namespace Drupal\crm_core_contact\Plugin\Action;

use Drupal\Core\Access\AccessResult;
use Drupal\Core\Action\ConfigurableActionBase;
use Drupal\Core\Entity\EntityFieldManager;
use Drupal\Core\Entity\EntityTypeManager;
use Drupal\Core\Extension\ModuleHandler;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Render\Renderer;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\StringTranslation\TranslationManager;
use Drupal\crm_core_activity\Entity\Activity;
use Drupal\crm_core_contact\Entity\Contact;
use Drupal\path_alias\PathAliasStorage;
use Drupal\relation\Entity\Relation;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Merges 2 or more contacts.
 *
 * @Action(
 *   id = "merge_contacts_action",
 *   label = @Translation("Merge contacts"),
 *   type = "crm_core_contact"
 * )
 */
class MergeContactsAction extends ConfigurableActionBase implements ContainerFactoryPluginInterface {

  /**
   * The path alias storage.
   *
   * @var \Drupal\path_alias\PathAliasStorage
   */
  protected $pathAliasStorage;

  /**
   * The module handler.
   *
   * @var \Drupal\Core\Mail\MailManagerInterface
   */
  protected $moduleHandler;

  /**
   * The translation manager.
   *
   * @var \Drupal\Core\StringTranslation\TranslationManager
   */
  protected $translationManager;

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManager
   */
  protected $entityTypeManager;

  /**
   * The entity field manager.
   *
   * @var \Drupal\Core\Entity\EntityFieldManager
   */
  protected $entityFieldManager;

  /**
   * The renderer service.
   *
   * @var \Drupal\Core\Render\Renderer
   */
  protected $renderer;

  /**
   * The Messenger service.
   *
   * @var \Drupal\Core\Messenger\MessengerInterface
   */
  protected $messenger;

  /**
   * Constructs a EmailAction object.
   *
   * @param array $configuration
   *   A configuration array containing information about the plugin instance.
   * @param string $plugin_id
   *   The plugin ID for the plugin instance.
   * @param mixed $plugin_definition
   *   The plugin implementation definition.
   * @param \Drupal\path_alias\PathAliasStorage $path_alias_storage
   *   The path alias storage.
   * @param \Drupal\Core\Extension\ModuleHandler $module_handler
   *   The module handler.
   * @param \Drupal\Core\StringTranslation\TranslationManager $translation_manager
   *   The translation manager.
   * @param \Drupal\Core\Entity\EntityTypeManager $entity_type_manager
   *   The entity type manager.
   * @param \Drupal\Core\Entity\EntityFieldManager $entity_field_manager
   *   The entity field manager.
   * @param \Drupal\Core\Render\Renderer $renderer
   *   The renderer service.
   * @param \Drupal\Core\Messenger\MessengerInterface $messenger
   *   The Messenger service.
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, PathAliasStorage $path_alias_storage, ModuleHandler $module_handler, TranslationManager $translation_manager, EntityTypeManager $entity_type_manager, EntityFieldManager $entity_field_manager, Renderer $renderer, MessengerInterface $messenger) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->pathAliasStorage = $path_alias_storage;
    $this->moduleHandler = $module_handler;
    $this->translationManager = $translation_manager;
    $this->entityTypeManager = $entity_type_manager;
    $this->entityFieldManager = $entity_field_manager;
    $this->renderer = $renderer;
    $this->messenger = $messenger;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static($configuration, $plugin_id, $plugin_definition,
      $container->get('path.alias_storage'),
      $container->get('module_handler'),
      $container->get('string_translation'),
      $container->get('entity_type.manager'),
      $container->get('entity_field.manager'),
      $container->get('renderer'),
      $container->get('messenger')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) {
    return $return_as_object ? AccessResult::allowed() : AccessResult::allowed()->isAllowed();
  }

  /**
   * {@inheritdoc}
   */
  public function executeMultiple(array $objects) {

    $crm_core_activity_storage = $this->entityTypeManager->getStorage('crm_core_activity');
    $crm_core_activity_query = $crm_core_activity_storage->getQuery();

    $relation_storage = $this->entityTypeManager->getStorage('relation');
    $relation_query = $relation_storage->getQuery();

    $primary_contact = reset($objects);
    foreach ($objects as $cid => $contact) {
      if ($contact->id() == $this->configuration['data']['contact_id']) {
        $primary_contact = $contact;
        unset($objects[$cid]);
        break;
      }
    }
    unset($this->configuration['data']['contact_id']);
    $wrappers = [];
    foreach ($objects as $contact) {
      $wrappers[$contact->id()] = $contact;
    }
    // Updating contact fields from other selected+    contacts.
    foreach ($this->configuration['data'] as $field_name => $contact_id) {
      if ($primary_contact->id() != $contact_id) {
        $primary_contact->set($field_name, $wrappers[key($contact_id)]->get($field_name)->getValue());
      }
    }
    $primary_contact->save();
    foreach (array_keys($wrappers) as $contact_id) {
      // Creating path aliases for contacts that will be deleted.
      $this->pathAliasStorage->save('/crm-core/contact/' . $primary_contact->id(), '/crm-core/contact/' . $contact_id);
      if ($this->moduleHandler->moduleExists('crm_core_activity')) {
        // Replacing participant in existing activities.
        $activities = $crm_core_activity_query
          ->condition('activity_participants.target_id', $contact_id)
          ->condition('activity_participants.target_type', 'crm_core_contact')
          ->accessCheck(FALSE)
          ->execute();
        if (is_array($activities)) {
          foreach (Activity::loadMultiple($activities) as $activity) {
            foreach ($activity->activity_participants as $delta => $participant) {
              if ($participant->target_id == $contact_id) {
                $activity->get('activity_participants')[$delta]->setValue($primary_contact);
              }
            }
            $activity->save();
          }
        }
      }
      if ($this->moduleHandler->moduleExists('relation')) {
        // Replacing existing relations for contacts been deleted with new ones.
        $relations = $relation_query
          ->condition('endpoints.entity_type', 'crm_core_contact', '=')
          ->condition('endpoints.entity_id', $contact_id, '=')
          ->accessCheck(FALSE)
          ->execute();
        foreach ($relations as $relation_info) {
          $endpoints = [
            [
              'entity_type' => 'crm_core_contact',
              'entity_id' => $primary_contact->id(),
            ],
          ];
          $relation = Relation::load($relation_info);
          foreach ($relation->endpoints as $endpoint) {
            if ($endpoint->entity_id != $contact_id) {
              $endpoints[] = [
                'entity_type' => $endpoint->entity_type,
                'entity_id' => $endpoint->entity_id,
              ];
            }
          }
          $new_relation = Relation::create([
            'relation_type' => $relation->relation_type->target_id,
            'endpoints' => $endpoints,
          ]);
          $new_relation->save();
        }
      }
    }
    $count = count($wrappers);
    $singular = '%contacts contact merged to %dest.';
    $plural = '%contacts contacts merged to %dest.';
    $contacts_label = array_map(function ($contact) {
      return $contact->label();
    }, $wrappers);
    $message = $this->translationManager->formatPlural($count, $singular, $plural, [
      '%contacts' => implode(', ', $contacts_label),
      '%dest' => $primary_contact->label(),
    ]);
    $this->entityTypeManager->getStorage('crm_core_contact')->delete($wrappers);
    $this->messenger->addMessage($message);
  }

  /**
   * {@inheritdoc}
   */
  public function execute($object = NULL) {
    $this->executeMultiple([$object]);
  }

  /**
   * {@inheritdoc}
   */
  public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
    $primary_contact = array_filter($form_state->getValue('table')['contact_id']);
    if (empty($primary_contact)) {
      $form_state->setError($form['table']['contact_id'], $this->t('You must select primary contact in table header!'));
    }
    if (count($primary_contact) > 1) {
      $form_state->setError($form['table']['contact_id'], $this->t('Supplied more than one primary contact!'));
    }
  }

  /**
   * {@inheritdoc}
   */
  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
    $form = [];
    $selected_contacts = Contact::loadMultiple($form_state->getValue('selection'));
    $selected_contacts_ids = array_map(function ($contact) {
      return $contact->id();
    }, $selected_contacts);
    // Lets check contacts type, it should be unique.
    $contact_types = array_map(function ($contact) {
      return $contact->type->target_id;
    }, $selected_contacts);
    // All selected contacts have same type.
    if (count(array_unique($contact_types)) != 1) {
      $this->messenger->addMessage($this->t('You should select contacts of one type to be able to merge them!'), 'error');
      $form_state->setRedirect('entity.crm_core_contact.collection');
    }
    else {
      $form['table'] = [
        '#type' => 'table',
        '#tree' => TRUE,
        '#selected' => $selected_contacts_ids,
      ];
      // Creating header.
      $header['field_name'] = ['#markup' => $this->t('Field name\\Contact')];
      foreach ($selected_contacts as $contact) {
        $header[$contact->contact_id->value] = [
          '#type' => 'radio',
          '#title' => $contact->label(),
        ];
      }
      $form['table']['contact_id'] = $header;
      $field_instances = $this->entityFieldManager->getFieldDefinitions('crm_core_contact', reset($contact_types));
      unset($field_instances['contact_id']);
      foreach ($field_instances as $field_name => $field_instance) {
        $form['table'][$field_name] = [];
        $form['table'][$field_name]['field_name'] = ['#markup' => $field_instance->getLabel()];
        foreach ($selected_contacts as $contact) {
          $field_value = ['#markup' => ''];
          $contact_field_value = $contact->get($field_name);
          if (isset($contact_field_value)) {
            $field_value_render = $contact_field_value->view('full');
            $field_value_rendered = $this->renderer->render($field_value_render);
            // Some fields can provide empty markup.
            if (!empty($field_value_rendered)) {
              $field_value = [
                '#type' => 'radio',
                '#title' => $field_value_rendered,
              ];
            }
          }
          $form['table'][$field_name][$contact->contact_id->value] = $field_value;
        }
      }
    }

    $form['#attached']['library'][] = 'crm_core_contact/drupal.crm_core_contact.merge-contacts';

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
    $data = ['contact_id' => array_shift(array_keys(array_filter($form_state->getValue('table')['contact_id'])))];
    unset($form_state->getValue('table')['contact_id']);
    foreach ($form_state->getValue('table') as $field_name => $selection) {
      $data[$field_name] = array_shift(array_keys(array_filter($selection)));
    }
    $this->configuration['data'] = array_filter($data);
  }

}

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

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