ckeditor_mentions-8.x-2.x-dev/src/MentionsType/MentionsTypeBase.php
src/MentionsType/MentionsTypeBase.php
<?php
namespace Drupal\ckeditor_mentions\MentionsType;
use Drupal\ckeditor_mentions\Events\CKEditorEvents;
use Drupal\ckeditor_mentions\Events\CKEditorMentionSuggestionsEvent;
use Drupal\ckeditor_mentions\Exception\MatchIsMissingException;
use Drupal\Component\Plugin\PluginBase;
use Drupal\Component\Utility\NestedArray;
use Drupal\Component\Uuid\UuidInterface;
use Drupal\Core\Database\Connection;
use Drupal\Core\Database\Query\AlterableInterface;
use Drupal\Core\Database\Query\SelectInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
/**
* Provides a base implementation for a MentionType plugin.
*/
abstract class MentionsTypeBase extends PluginBase implements MentionsTypeInterface, ContainerFactoryPluginInterface {
/**
* The default dropdown limit.
*/
const DEFAULT_DROPDOWN_LIMIT = 10;
/**
* {@inheritDoc}
*/
public function __construct(
array $configuration,
$plugin_id,
$plugin_definition,
protected EntityTypeManagerInterface $entityManager,
protected Connection $database,
protected EventDispatcherInterface $eventDispatcher,
protected UuidInterface $uuid,
) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->configuration = $configuration + $this->defaultConfiguration();
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('entity_type.manager'),
$container->get('database'),
$container->get('event_dispatcher'),
$container->get('uuid')
);
}
/**
* {@inheritDoc}
*/
public function buildTokens(array $entities): array {
$result = [];
foreach ($entities as $id => $entity) {
if ($entity instanceof EntityInterface) {
$result[$id]['entity_type'] = $entity->getEntityTypeId();
$result[$id]['entity_id'] = $entity->id();
$result[$id]['entity_uuid'] = $entity->uuid();
$result[$id]['label'] = $entity->label();
$result[$id]['mention_uuid'] = $this->uuid->generate();
$result[$id]['url'] = $entity->toUrl()->toString();
}
}
return $result;
}
/**
* Get match value.
*
* @return string
* Match value.
*/
public function getMatch() {
return $this->configuration['match'];
}
/**
* Add additional conditions to the query.
*
* @param \Drupal\Core\Database\Query\AlterableInterface $query
* Query to post process.
*/
protected function postProcessQuery(AlterableInterface $query) {
if (!empty($this->configuration['filterByBundle'])) {
$query->condition('type', $this->configuration['filterByBundle'], 'IN');
}
// Apply dropdown limit to prevent performance issues with large datasets.
if (!empty($this->configuration['dropdownLimit'])) {
$query->range(0, (int) $this->configuration['dropdownLimit']);
}
$query->addTag('ckeditor_mentions_' . $this->getPluginId());
$query->addMetaData('plugin', $this);
}
/**
* Build the query.
*
* @return \Drupal\Core\Database\Query\AlterableInterface
* The query.
*/
protected function buildQuery(): AlterableInterface {
if (!isset($this->configuration['match'])) {
throw new MatchIsMissingException();
}
$query = $this->getQuery();
$this->postProcessQuery($query);
return $query;
}
/**
* Get the query for plugin.
*
* @return \Drupal\Core\Database\Query\AlterableInterface
* Query.
*/
abstract protected function getQuery(): AlterableInterface;
/**
* {@inheritDoc}
*/
public function buildResponse(): array {
$query = $this->buildQuery();
$result = $query instanceof SelectInterface
? $query->execute()->fetchCol()
: $query->execute();
if (empty($result)) {
return $result;
}
$entities = $this->entityManager
->getStorage($this->getPluginDefinition()['entity_type'])
->loadMultiple($result);
$tokens = $this->buildTokens($entities);
return $this->dispatchSuggestionsEvent($tokens);
}
/**
* Dispatch suggestion event.
*
* @param array $suggestions
* Suggestions.
*
* @return array
* Suggestions.
*/
protected function dispatchSuggestionsEvent(array $suggestions): array {
$suggestion_event = new CKEditorMentionSuggestionsEvent($this->getMatch(), $suggestions);
$this->eventDispatcher->dispatch($suggestion_event, CKEditorEvents::SUGGESTION);
return $suggestion_event->getSuggestions();
}
/**
* {@inheritdoc}
*/
public function getConfiguration(): array {
return $this->configuration;
}
/**
* {@inheritdoc}
*/
public function setConfiguration(array $configuration) {
$this->configuration = NestedArray::mergeDeep($this->defaultConfiguration(), $configuration);
}
/**
* {@inheritDoc}
*/
public function defaultConfiguration(): array {
return [
'match' => '',
'filterByBundle' => [],
'dropdownLimit' => self::DEFAULT_DROPDOWN_LIMIT,
];
}
/**
* Check if the mentions type is bundable.
*
* @return bool
* True if the mentions type is bundable, false otherwise.
*/
public function isBundable(): bool {
return $this->entityManager->getDefinition($this->getPluginDefinition()['entity_type'])->hasKey('bundle');
}
}
