web-dev-qa-db-ja.com

リンクウィジェットのオートコンプリートに10を超えるアイテムを表示するにはどうすればよいですか?

これはリンクモジュールに関する質問です。 Linkモジュールを使用すると、外部リンクと内部リンクの両方を入力できるため、これに強く依存しています。

残念ながら、オートコンプリートフィールドから表示されるアイテムの数は10に制限されています。ほぼ同じタイトルのノードが多数あるため、検索しているノードがある場合、オートコンプリートフィールドに表示されません。 10以上の一致するタイトル。

制限はcore/lib/Drupal/Core/Entity/EntityAutocompleteMatcher.phpにハードコードされています。カスタムモジュール内からこの小さな数を増やすエレガントな方法はありますか? class EntityAutocompleteMatcherを拡張する必要がありますか?拡張機能をどこに配置し、リンクウィジェット内から確実に実行されるようにする必要がありますか?

10
leymannx
3
Richard

すべてのオートコンプリートの制限を上書きしても問題がなければ、 コアサービスを上書き in 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ではなく、拡張バージョンを使用していることを覚えておく必要があります。あなたが去った後にあなたのプロジェクトに参加する他の開発者は、サービスが非標準的な方法で動作している理由を理解するのに苦労するかもしれません。

これはハッキングのコアですか?

見方次第です。コアモジュールとコードの変更は行いません。パッチを作成して適用し、composerなどのパッケージマネージャーで追跡することすらありません。これは、サイトのコア動作を変更する1回限りのカスタマイズであり、ALTERフックに似ています。それはあなたのサイトのあなた自身のカスタムモジュール内にあるので、それはコアハックより自己完結型です。そのため、元のサービスコードにパッチを適用したりハッキングした場合と同じように、元のサービスへのコアアップデートは影響を受けません。

ただし、前述のように、コアをハッキングするのと同じリスクがいくつかあります。

元の質問では、問題はノードのタイトルが十分に一意ではないことでした。ドロップダウンの制限をグローバルに変更する以外のより良い解決策は、一意性の問題を解決することです。

私が提案するのは、新しいフィールドfield_display_titleを追加してページで使用することです。必要な場合は、短いタイトルが必要なリストページに表示するために別のフィールドfield_teaser_titleを使用してください。次に、エンティティ参照選択ドロップダウンにプルされる実際のタイトルは、編集者にとって便利で、各ページに同じタイトルが付いている場合は「私の記事(ページ1)」のように一意にすることができます。その後、コアサービスをオーバーライドする必要はありません。

Drupalで問題が発生した場合は、カスタムコードの量が最も少ないソリューションを見つけてください。これにより、サイトがより安定し、保守が容易になり、時間を節約できます。

10
oknate

EntityAutocompleteMatcherをオーバーライドすると、サイト上のすべてのオートコンプリートフォーム要素に影響すると思います。そのため、より詳細なアプローチであるため、代わりに新しいエンティティ選択プラグインを作成します。プラグインはフィールドごとに有効にできます。以下はそのようなプラグインの例です。 https://drupal.stackexchange.com/a/220136/4

あなたの場合、実装はさらに簡単です:

ファイル:modules/example/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);
  }

}

DefaultSelectionの代わりに NodeSelection を基本クラスとして使用すると、参照されたノードをそのステータスでフィルタリングできます。他のエンティティタイプを参照することに注意してください サポートされていません まだです。

エンティティ参照リンクウィジェットとは異なり、ユーザーインターフェースを介して選択プラグインを指定することはできないため、プログラムで hook_field_widget_WIDGET_TYPE_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';
}

プラグインIDにセミコロンが含まれていることが重要です。

7
ya.teck

結果の数を変更する別の簡単な方法は、クエリの範囲値を変更することです。

/**
 * 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);
}
4
Weri

@Weri、あなたの提案を実装し、一日の大部分を別の問題の修正に費やしただけで、私はそれを避けるでしょう。

提案するクエリ変更は、段落をノードにリンクするときのエンティティ参照にも影響します。私が目覚めていたノードには、変更を追加する前に80以上の段落項目がありました。追加すると、ノードを保存できませんでした。変更を削除/コメントアウトすると、問題が修正されました。

更新

$ query-> range()をルートチェックでラップすると、問題が解決します。たとえば、

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

FWIW、フィールドのフォーム表示を「オートコンプリート」ではなく「選択リスト」に設定するだけです。

次に、あまり便利ではない形式ですべてのオプションを取得しますが、ハックは必要ありません。

0
ognockocaten