Як відобразити більше 10 елементів у автоматичному заповненні віджета посилання?


10

Це питання про модуль посилання. Оскільки за допомогою модуля Link ви можете вводити і зовнішні, і внутрішні посилання, ми сильно покладаємось на нього.

На жаль, кількість елементів, які відображатимуться з поля автозаповнення, обмежена 10. У нас є безліч вузлів з майже однаковими заголовками, і тому виходить, що вузол, який ми шукаємо, не відображається в полі автозаповнення, коли є більше 10 відповідних назв.

Межа введена жорстко core/lib/Drupal/Core/Entity/EntityAutocompleteMatcher.php. Чи є елегантний спосіб збільшити це невелике число за допомогою спеціального модуля? Чи повинен я продовжувати class EntityAutocompleteMatcher? Де я повинен розмістити своє розширення та як забезпечити його виконання з-за віджета посилання?

Відповіді:



10

Якщо ви можете жити з перевищенням усіх обмежень автозаповнення, ви можете змінити основну службу в Drupal 8;

Служба, яку потрібно перекрити, знаходиться тут у core.services.yml:

  entity.autocomplete_matcher:
    class: Drupal\Core\Entity\EntityAutocompleteMatcher
    arguments: ['@plugin.manager.entity_reference_selection']

У свій спеціальний модуль додайте клас, який реалізує ServiceModifierInterface

namespace Drupal\mymodule;

use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DependencyInjection\ServiceModifierInterface;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;

class MyModuleServiceProvider implements ServiceModifierInterface {

  /**
   * Modifies existing service definitions.
   *
   * @param ContainerBuilder $container
   *   The ContainerBuilder whose service definitions can be altered.
   */
  public function alter(ContainerBuilder $container) {

    for ($id = 'entity.autocomplete_matcher'; $container->hasAlias($id); $id = (string) $container->getAlias($id));
    $definition = $container->getDefinition($id);
    $definition->setClass('Drupal\mymodule\Entity\EntityAutocompleteMatcherCustom');
    $container->setDefinition($id, $definition);
  }

}

Потім скопіюйте EntityAutocompleteMatcher.php у свій модуль за адресою /src/Entity/EntityAutocompleteMatcherCustom.php

Потім оновіть жорстко закодовані 10 на 50 або будь-який обмеження, який ви хочете:

namespace Drupal\mymodule\Entity;

use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\Tags;
use Drupal\Core\Entity\EntityReferenceSelection\SelectionPluginManagerInterface;
use Drupal\Core\Entity\EntityAutocompleteMatcher;

/**
 * Matcher class to get autocompletion results for entity reference.
 */
class EntityAutocompleteMatcherCustom extends EntityAutocompleteMatcher {

  /*
   * {@inheritdoc]
   */
  public function getMatches($target_type, $selection_handler, $selection_settings, $string = '') {

    $matches = array();

    $options = array(
      'target_type' => $target_type,
      'handler' => $selection_handler,
      'handler_settings' => $selection_settings,
    );
    $handler = $this->selectionManager->getInstance($options);

    if (isset($string)) {
      // Get an array of matching entities.
      $match_operator = !empty($selection_settings['match_operator']) ? $selection_settings['match_operator'] : 'CONTAINS';
      // Changing limit from 10 to 50.
      $entity_labels = $handler->getReferenceableEntities($string, $match_operator, 50);

      // Loop through the entities and convert them into autocomplete output.
      foreach ($entity_labels as $values) {
        foreach ($values as $entity_id => $label) {
          $key = "$label ($entity_id)";
          // Strip things like starting/trailing white spaces, line breaks and
          // tags.
          $key = preg_replace('/\s\s+/', ' ', str_replace("\n", '', trim(Html::decodeEntities(strip_tags($key)))));
          // Names containing commas or quotes must be wrapped in quotes.
          $key = Tags::encode($key);
          $matches[] = array('value' => $key, 'label' => $label);
        }
      }
    }

    return $matches;
  }

}

Очевидно, що переосмислення основних сервісів має певні ризики, але здорово, що ви можете це зробити.

Які ризики перекриття базової послуги?

1) Ви можете втратити переваги оновлень під час оновлення ядра. Якщо в сервісі є критичне виправлення безпеки, і ваша змінена копія має отвір безпеки, ви не отримаєте користі від оновлення коду спільнотою.

2) Інші модулі, які ви встановлюєте, можуть залежати від оригінальної послуги з її оригінальним набором функцій. Тож скажімо, що в іншому модулі є якийсь код, який порушиться, якщо кількість записів автозаповнення буде більшою або меншою за 10, ви про це не дізнаєтесь, поки це не вплине на вас.

3) Це ускладнює підтримку вашої кодової бази. Ви повинні пам’ятати, що ви використовуєте не основний Drupal, а розширену версію. Іншим розробникам, які приєднаються до вашого проекту після того, як ви підете, можливо, важко з'ясувати, чому служба поводиться нестандартно.

Це хакерське ядро?

Залежить від того, як ти на це дивишся. Це не входить в основний модуль і змінюється код. Навіть не створити патч, а застосувати його та відстежити його за допомогою менеджера пакунків, наприклад композитора. Це більше разова настройка, яка змінює поведінку основних сайтів, аналогічну гачку ALTER. Це більш автономне, що ядро ​​зламає, оскільки воно знаходиться у вашому власному користувальницькому модулі на вашому сайті. Таким чином, основні оновлення оригінальної послуги не впливатимуть так само, як якщо б ви виправили або зламали оригінальний код послуги.

Але це має деякі ті ж ризики, що і злом ядра, як згадувалося вище.

У первісному питанні проблема полягала у тому, що назви вузлів недостатньо унікальні. Кращим рішенням, крім зміни ліміту на глобальному рівні падіння, було б вирішити проблему унікальності.

Що я б запропонував, це додати нове поле field_display_title і використовувати його на сторінці, а якщо вам це потрібно, інше поле field_teaser_title для відображення на сторінках списку, де вам потрібно коротший заголовок. Тоді фактичний заголовок, який потрапляє у спадне меню вибору посилання на юридичну особу, може бути корисним вашим редакторам та бути унікальним, наприклад "Моя стаття (сторінка 1)", якщо випуск кожної сторінки має однаковий заголовок. Тоді вам не доведеться перекривати основну службу.

Якщо ви зіткнулися з проблемою з Drupal, спробуйте знайти рішення, яке вимагає найменшої кількості користувацького коду. Це робить ваш сайт більш стабільним, простішим в обслуговуванні та економить ваш час.


3
В основному переосмислення основного сервісу має ті самі наслідки, що й застосування гаків ALTER. Ризики мають місце, але вони незначні і можуть бути зменшені за допомогою належної документації з кодом.
ya.teck

1
Тому велика кількість таких перекриттів, гачків, патчів може зменшити рентабельність проекту.
ya.teck

Мені це здається ідеальним випадком використання для [декоратора послуг] ( blueoakinteractive.com/blog/service-decorators-drupal-8 ).
Beau

7

Я припускаю, що переважання EntityAutocompleteMatcher вплине на всі елементи автозаповнення форми на вашому сайті. Так що я створив би новий плагін вибору сутності, тому що це більш детальний підхід. Плагін можна включити для кожного поля. Ось приклад такого плагіна. https://drupal.stackexchange.com/a/220136/433

У вашому випадку реалізація була б ще більш тривіальною:

Файл: модулі / приклад / src / Plugin / EntityReferenceSelection / ExampleSelection.php

namespace Drupal\example\Plugin\EntityReferenceSelection;

use Drupal\node\Plugin\EntityReferenceSelection\NodeSelection;

/**
 * Entity reference selection.
 *
 * @EntityReferenceSelection(
 *   id = "example:node",
 *   label = @Translation("Example node"),
 *   group = "example",
 * )
 */
class ExampleSelection extends NodeSelection {

  /**
   * {@inheritdoc}
   */
  public function getReferenceableEntities($match = NULL, $match_operator = 'CONTAINS', $limit = 0) {
   return parent::getReferenceableEntities($match, $match_operator, 25);
  }

}

Використання NodeSelection як базового класу замість DefaultSelection дозволить вам фільтрувати посилання на їх стан за станом. Зауважте, що посилання на інші типи об'єктів ще не підтримується .

На відміну від віджета посилань на посилання на об'єкт не дозволяє вказувати плагін вибору через користувальницький інтерфейс, тому вам потрібно встановити його програмно, використовуючи приворот____________DY_ETYPE_form_alter () .

/**
 * Implements hook_field_widget_WIDGET_TYPE_form_alter().
 */
function example_field_widget_link_default_form_alter(&$element, \Drupal\Core\Form\FormStateInterface $form_state, $context) {
  // Replace default selection handler to increase limit of displayed entities.
  $element['uri']['#selection_handler'] = 'example:node';
}

Важливо, щоб ідентифікатор плагіна містив крапку з комою.


4

Інший простий спосіб змінити кількість результатів - це змінити значення діапазону в запиті:

/**
 * Implements hook_query_TAG_alter() for entity reference selection handlers.
 *
 * We like tho show always 30 results instead of the 10 definied in EntityAutocompleteMatcher::getMatches()
 */
function MODULE_query_entity_reference_alter(AlterableInterface $query) {
  $query->range(0, 30);
}

1

@Weri, я б уникну цього, просто реалізувавши вашу пропозицію і витратив найкращу частину дня, намагаючись виправити ще одну проблему.

Запропонована вами зміна запиту також впливає на посилання entiry під час посилання абзаців на вузли. Вузол, на якому я прокидався, мав пункт 80+ абзацу до того, як я додав змін. Після додавання я не зміг зберегти вузол. Видалення / коментування змін змінило проблему.

Оновлення

Встановлення $ query-> range () у перевірку маршруту вирішує проблему для мене, наприклад,

function mymodule_query_entity_reference_alter($query) {
  $routeMatch = \Drupal::routeMatch();
  if ($routeMatch->getRouteName() == 'system.entity_autocomplete') {
    $query->range(0, 20);
  }
}

0

FWIW, ви можете просто встановити для відображення форми поля "Вибір списку" замість "Автозаповнення".

Тоді ви отримаєте всі варіанти, хоча і в менш зручному форматі, але жодних хак не потрібно.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.