링크 위젯 자동 완성에 10 개 이상의 항목을 표시하는 방법은 무엇입니까?


10

이것은 링크 모듈에 관한 질문입니다. 링크 모듈을 사용하면 외부 또는 내부 링크를 모두 입력 할 수 있으므로이 모듈에 크게 의존합니다.

불행히도 자동 완성 필드에 표시 할 항목 수는 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이 아니라 확장 버전을 사용하고 있음을 기억해야합니다. 떠난 후 프로젝트에 참여하는 다른 개발자는 왜 서비스가 비표준 방식으로 작동하는지 파악하기가 어려울 수 있습니다.

이것이 해킹 핵심입니까?

당신이 그것을 어떻게 보는가에 달려 있습니다. 핵심 모듈로 들어 가지 않고 코드를 변경하지 않습니다. 패치를 작성하여 적용하지 않고 composer와 같은 패키지 관리자로 추적하지도 않습니다. ALTER 후크와 유사하게 사이트 핵심 동작을 변경하는 일회성 사용자 정의에 가깝습니다. 핵심 해킹은 사이트의 자체 사용자 정의 모듈 내에 있기 때문에 자체적으로 포함되어 있습니다. 따라서 원래 서비스 코드를 패치하거나 해킹 한 것과 같은 방식으로 원래 서비스에 대한 핵심 업데이트는 영향을받지 않습니다.

그러나 위에서 언급했듯이 해킹 코어와 동일한 위험이 있습니다.

원래 질문에서 문제는 노드 제목이 고유하지 않다는 것입니다. 드롭 다운에서 전체적으로 한계를 변경하는 것 이외의 더 나은 솔루션은 고유성 문제를 해결하는 것입니다.

내가 제안하는 것은 새로운 field_display_title 필드를 추가하고 페이지에서 사용하고, 필요한 경우 더 짧은 제목이 필요한 목록 페이지에 표시하기 위해 field_teaser_title 다른 필드를 사용하는 것입니다. 그런 다음 엔터티 참조 선택 드롭 다운으로 가져 오는 실제 제목은 편집자에게 유용 할 수 있으며 문제가 각 페이지의 제목이 동일한 경우 "내 기사 (페이지 1)"와 같이 고유 할 수 있습니다. 그런 다음 핵심 서비스를 재정의 할 필요가 없습니다.

Drupal에 문제가 발생하면 최소한의 사용자 정의 코드가 필요한 솔루션을 찾으십시오. 이를 통해 사이트를보다 안정적이고 유지 관리하기 쉽고 시간을 절약 할 수 있습니다.


3
기본적으로 핵심 서비스를 재정의하면 ALTER 후크 구현과 동일한 의미가 있습니다. 위험이 발생하지만 매우 적으며 적절한 코드 문서를 사용하여 완화 할 수 있습니다.
ya.teck

1
이러한 오버라이드, 후크, 패치의 수가 많으면 프로젝트 유지 관리 성이 떨어질 수 있습니다.
ya.teck

이것은 [service decorator] ( blueoakinteractive.com/blog/service-decorators-drupal-8 ) 의 완벽한 유스 케이스처럼 보입니다 .
Beau

7

EntityAutocompleteMatcher 를 재정의 하면 사이트의 모든 자동 완성 양식 요소에 영향을 미칩니다. 좀 더 세분화 된 접근 방식이기 때문에 새로운 엔티티 선택 플러그인을 대신 만들 것입니다. 플러그인은 필드별로 활성화 될 수 있습니다. 다음은 그러한 플러그인의 예입니다. https://drupal.stackexchange.com/a/220136/433

귀하의 경우 구현이 훨씬 간단합니다.

파일 : 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에는 세미콜론이 포함되어 있어야합니다.


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, 난 당신의 제안을 구현하고 다른 문제를 해결하기 위해 하루의 가장 좋은 시간을 보냈다는 것을 피하고 싶습니다.

제안한 쿼리 변경은 단락을 노드에 연결할 때 항목 참조에도 영향을줍니다. 내가 깨우고 있던 노드에는 alter를 추가하기 전에 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에서는 필드 양식 표시를 "자동 완성"대신 "목록 선택"으로 설정할 수 있습니다.

그러면 덜 편리한 형식이지만 모든 해킹이 필요하지는 않지만 모든 옵션을 사용할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.