Làm cách nào để hiển thị hơn 10 mục trong tiện ích liên kết tự động hoàn thành?


10

Đây là một câu hỏi về mô-đun Liên kết. Vì với mô-đun Liên kết, bạn có thể nhập cả hai liên kết bên ngoài hoặc bên trong, chúng tôi hoàn toàn tin tưởng vào nó.

Thật không may, số lượng mục được hiển thị từ trường tự động hoàn thành của nó bị giới hạn là 10. Chúng tôi có rất nhiều nút có tiêu đề gần giống nhau và do đó, nút mà chúng tôi đang tìm kiếm không được hiển thị trong trường tự động hoàn thành khi có hơn 10 tiêu đề phù hợp.

Giới hạn là mã hóa cứng trong core/lib/Drupal/Core/Entity/EntityAutocompleteMatcher.php. Có một cách thanh lịch để tăng số lượng nhỏ này từ trong một mô-đun tùy chỉnh? Tôi có phải gia hạn class EntityAutocompleteMatcherkhông? Tôi sẽ phải đặt tiện ích mở rộng của mình ở đâu và làm thế nào để đảm bảo tiện ích được thực thi từ trong tiện ích liên kết?

Câu trả lời:



10

Nếu bạn có thể sống với việc ghi đè tất cả các giới hạn tự động hoàn thành, bạn có thể ghi đè một dịch vụ cốt lõi trong Drupal 8;

Dịch vụ bạn cần ghi đè có ở đây trong core.service.yml:

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

Trong mô-đun tùy chỉnh của bạn, thêm một lớp thực hiện 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);
  }

}

Sau đó sao chép EntityAutocompleteMatcher.php vào mô-đun của bạn tại /src/Entity/EntityAutocompleteMatcherCustom.php

Sau đó cập nhật 10 mã hóa cứng thành 50 hoặc bất kỳ giới hạn nào bạn muốn:

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;
  }

}

Rõ ràng việc ghi đè các dịch vụ cốt lõi có một số rủi ro, nhưng thật tuyệt khi bạn có thể làm điều này.

Những rủi ro của việc ghi đè một dịch vụ cốt lõi là gì?

1) Bạn có thể mất lợi ích của các cập nhật khi bạn cập nhật cốt lõi. Nếu có một sửa chữa bảo mật quan trọng trong dịch vụ và bản sao bị thay đổi của bạn có lỗ hổng bảo mật, bạn sẽ không được hưởng lợi từ cộng đồng cập nhật mã đó.

2) Các mô-đun khác mà bạn cài đặt có thể có các phụ thuộc vào dịch vụ ban đầu với bộ tính năng ban đầu. Vì vậy, giả sử có một số mã trong một mô-đun khác sẽ bị hỏng nếu số lượng mục nhập tự động hoàn thành lớn hơn hoặc ít hơn 10, bạn sẽ không biết về nó, cho đến khi nó ảnh hưởng đến bạn.

3) Nó làm cho cơ sở mã hóa của bạn khó bảo trì hơn. Bạn phải nhớ rằng bạn không sử dụng lõi Drupal, mà là phiên bản mở rộng. Các nhà phát triển khác tham gia dự án của bạn sau khi bạn rời đi có thể gặp khó khăn trong việc tìm hiểu lý do tại sao một dịch vụ hoạt động theo cách không chuẩn.

Đây có phải là hack cốt lõi?

Phụ thuộc vào cách bạn nhìn vào nó. Nó không đi vào mô-đun lõi và thay đổi mã. Nó thậm chí không tạo ra một bản vá và áp dụng nó và theo dõi nó với một trình quản lý gói như nhà soạn nhạc. Đây là một tùy chỉnh một lần duy nhất thay đổi hành vi cốt lõi của trang web, tương tự như móc ALTER. Nó độc lập hơn là một hack lõi, bởi vì nó nằm trong mô-đun tùy chỉnh của riêng bạn trên trang web của bạn. Vì vậy, các cập nhật cốt lõi cho dịch vụ gốc sẽ không bị ảnh hưởng, giống như khi bạn vá hoặc hack mã dịch vụ gốc.

Nhưng nó có một số rủi ro tương tự như hack lõi, như đã đề cập ở trên.

Trong câu hỏi ban đầu, vấn đề là các tiêu đề nút không đủ độc đáo. Giải pháp tốt hơn, ngoài việc thay đổi giới hạn trên toàn cầu khi thả xuống sẽ giải quyết được vấn đề duy nhất.

Những gì tôi muốn đề xuất là thêm một trường field_display_title mới và sử dụng trường đó trên trang và nếu bạn cần nó, một trường khác field_teaser_title để hiển thị trên các trang danh sách nơi bạn cần một tiêu đề ngắn hơn. Sau đó, tiêu đề thực tế được kéo vào tham chiếu thực thể chọn thả xuống có thể hữu ích cho các biên tập viên của bạn và là duy nhất, chẳng hạn như "Bài viết của tôi (trang 1)" nếu vấn đề là mỗi trang có cùng tiêu đề. Sau đó, bạn không phải ghi đè một dịch vụ cốt lõi.

Khi bạn gặp phải một vấn đề với Drupal, hãy thử tìm giải pháp yêu cầu số lượng mã tùy chỉnh ít nhất. Điều này làm cho trang web của bạn ổn định hơn, dễ bảo trì hơn và tiết kiệm thời gian của bạn.


3
Về cơ bản ghi đè một dịch vụ cốt lõi có ý nghĩa tương tự như thực hiện các móc ALTER. Các rủi ro xảy ra nhưng chúng khá nhỏ và có thể được giảm thiểu bằng tài liệu mã phù hợp.
ya.teck

1
Bởi vì một số lượng lớn các phần ghi đè, móc, bản vá có thể làm giảm khả năng bảo trì dự án.
ya.teck

Đây dường như là một trường hợp sử dụng hoàn hảo cho [trang trí dịch vụ] ( blueoakinteractive.com/blog/service-decorators-drupal-8 ).
Beau

7

Tôi cho rằng việc ghi đè EntityAutocompleteMatcher sẽ ảnh hưởng đến tất cả các thành phần biểu mẫu tự động hoàn thành trên trang web của bạn. Vì vậy, tôi sẽ tạo một plugin lựa chọn thực thể mới thay vì đó là cách tiếp cận chi tiết hơn. Các plugin có thể được kích hoạt trên mỗi lĩnh vực. Dưới đây là một ví dụ về một plugin như vậy. https://drupal.stackexchange.com/a/220136/433

Trong trường hợp của bạn, việc thực hiện sẽ còn tầm thường hơn:

Tệp: mô-đun / 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);
  }

}

Sử dụng NodeSelection làm lớp cơ sở thay vì DefaultSelection sẽ cho phép bạn lọc các nút được tham chiếu theo trạng thái của chúng. Lưu ý rằng việc tham chiếu các loại thực thể khác chưa được hỗ trợ .

Không giống như tiện ích liên kết tham chiếu thực thể không cho phép chỉ định plugin lựa chọn thông qua giao diện người dùng, do đó bạn cần thiết lập chương trình bằng cách sử dụng 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';
}

Điều quan trọng là ID plugin chứa dấu chấm phẩy.


4

Một cách dễ dàng khác để sửa đổi số lượng kết quả là thay đổi giá trị phạm vi trong truy vấn:

/**
 * 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, tôi sẽ tránh làm điều đó, chỉ cần thực hiện đề xuất của bạn và dành phần tốt nhất trong một ngày để cố gắng khắc phục vấn đề khác.

Các thay đổi truy vấn mà bạn đề xuất cũng ảnh hưởng đến toàn bộ tham chiếu khi liên kết các đoạn với các nút. Một nút tôi đang sử dụng đã có hơn 80 mục đoạn trước khi tôi thêm các thay đổi. Sau khi thêm tôi không thể lưu nút. Loại bỏ / Nhận xét các thay đổi đã khắc phục vấn đề.

Cập nhật

Việc gói $ query-> phạm vi () trong kiểm tra tuyến sẽ khắc phục sự cố cho tôi, ví dụ,

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

0

FWIW, bạn chỉ có thể đặt hiển thị biểu mẫu của trường thành "Chọn danh sách" thay vì "Tự động hoàn thành".

Sau đó, bạn sẽ nhận được tất cả các tùy chọn, mặc dù ở định dạng ít thuận tiện hơn, nhưng không yêu cầu hack.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.