ckeditor_mentions-8.x-2.x-dev/src/MentionEventDispatcher.php

src/MentionEventDispatcher.php
<?php

namespace Drupal\ckeditor_mentions;

use Drupal\ckeditor_mentions\Events\CKEditorMentionsEvent;
use Drupal\ckeditor_mentions\MentionsType\MentionsTypeManagerInterface;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityRepositoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\FieldableEntityInterface;
use Masterminds\HTML5;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;

/**
 * Class MentionService.
 *
 * @package Drupal\ckeditor_mentions
 * @internal
 */
class MentionEventDispatcher {

  public function __construct(
    protected EventDispatcherInterface $eventDispatcher,
    protected EntityTypeManagerInterface $entityTypeManager,
    protected MentionsTypeManagerInterface $mentionsTypeManager,
    protected EntityRepositoryInterface $entityRepository,
    protected CacheBackendInterface $cache,
  ) {}

  /**
   * Triggers the Mention Event.
   *
   * @param \Drupal\Core\Entity\EntityInterface $entity
   *   Trigger the mention event.
   * @param string $event_name
   *   The name of the event.
   */
  public function dispatchMentionEvent(EntityInterface $entity, string $event_name): void {
    foreach ($this->getMentionsFromEntity($entity) as $mentioned_entity) {
      $event = new CKEditorMentionsEvent($entity, $mentioned_entity['entity'], $mentioned_entity['plugin']);
      $this->eventDispatcher->dispatch($event, $event_name);
    }
  }

  /**
   * Reads all the fields from an entity and return all the users mentioned.
   *
   * The array returned has this format:
   *
   * [entity_id] => [
   *    'uuid' => $uuid,
   *   'id' => $id,
   *   'field_name' => [
   *     'delta' => [
   *       0 => 0,
   *       1 => 1,
   *       2 => 2,
   *     ]
   *   ]
   * ];
   *
   * The first key is the user id, the next key is the field_name where the
   * user was mentioned and finally the deltas of the fields.
   *
   * @param \Drupal\Core\Entity\EntityInterface $entity
   *   The entity from which will get the mentions.
   *
   * @return array
   *   The users mentioned.
   */
  public function getMentionsFromEntity(EntityInterface $entity): array {
    $mentioned_entities = [];
    // Check if some of the fields is using the CKEditor editor.
    if (!$entity instanceof FieldableEntityInterface) {
      return $mentioned_entities;
    }

    foreach (_editor_get_formatted_text_fields($entity) as $field_name) {
      $items = $entity->get($field_name);
      $main_property = $items->getFieldDefinition()->getFieldStorageDefinition()->getMainPropertyName();
      /** @var \Drupal\Core\Field\FieldItemInterface $item */
      foreach ($items as $delta => $item) {
        $format_id = $item->get('format')->getValue();
        if (!$format_id || !$this->isFormatMentionable($format_id)) {
          continue;
        }

        foreach ($this->getMentionedEntities($item->get($main_property)->getValue()) as $mentioned_entity_information) {
          $mentioned_item = [
            'field_info' => [
              $field_name => [
                'delta' => [
                  $delta => $delta,
                ],
              ],
            ],
          ];
          $mentioned_item += $mentioned_entity_information;
          $mentioned_entities[] = $mentioned_item;
        }
      }
    }
    return $mentioned_entities;
  }

  /**
   * Checks if a given text format supports CKEditor mentions.
   *
   * @param string $format_id
   *   The text format ID to check.
   *
   * @return bool
   *   TRUE if the format supports mentions, FALSE otherwise.
   */
  public function isFormatMentionable(string $format_id): bool {
    // Load the editor only if its status is not yet cached, and cache it.
    $cid = "ckeditor_mentions:mentionable_formats:$format_id";
    if ($cache = $this->cache->get($cid)) {
      $is_mentionable = $cache->data;
    }
    else {
      // Editor entities use the "format" property as the "id"
      // in "entity_keys", i.e., the format ID and the editor ID always
      // match, so we can load the editor by the format ID.
      $editor_storage = $this->entityTypeManager->getStorage('editor');
      /** @var \Drupal\editor\EditorInterface|null $editor */
      $editor = $editor_storage->load($format_id);
      $is_mentionable = FALSE;
      if ($editor?->getEditor() === 'ckeditor5') {
        $mention_types = $editor->getSettings()['plugins']['ckeditor_mentions_mentions']['plugins'] ?? [];
        foreach ($mention_types as $mention_type) {
          if ($mention_type['enable'] ?? FALSE) {
            $is_mentionable = TRUE;
            break;
          }
        }
      }
      $this->cache->set($cid, $is_mentionable, tags: $editor_storage->getEntityType()->getListCacheTags());
    }
    return $is_mentionable;
  }

  /**
   * Returns an with information about mentioned entities.
   *
   * @param string $field_value
   *   The field text $field_text.
   *
   * @return array
   *   Array with information about mentioned entities.
   */
  public function getMentionedEntities(string $field_value): array {
    $mentioned_entities = [];
    $plugins = [];

    if (empty($field_value)) {
      return $mentioned_entities;
    }

    // Instantiate the HTML5 parser, but without the HTML5 namespace being
    // added to the DOM document.
    $html5 = new HTML5(['disable_html_ns' => TRUE]);
    $dom = $html5->loadHTML($field_value);

    $anchors = $dom->getElementsByTagName('a');
    foreach ($anchors as $anchor) {
      /** @var @todo BC LAYER, with data-entity-id **/
      $plugin = NULL;
      $entity_uuid = $anchor->getAttribute('data-entity-uuid');
      $plugin_id = $anchor->getAttribute('data-plugin');

      if (empty($entity_uuid) || empty($plugin_id)) {
        continue;
      }

      /** @var \Drupal\ckeditor_mentions\MentionsType\MentionsTypeBase $plugin */
      $plugin = $plugins[$plugin_id] ??= $this->mentionsTypeManager->createInstance($plugin_id);

      $mentioned_entities[] = [
        'plugin' => $plugin,
        'entity' => $this->entityRepository->loadEntityByUuid($plugin->getPluginDefinition()['entity_type'], $entity_uuid),
      ];
    }

    return $mentioned_entities;
  }

}

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

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