จะแสดงมากกว่า 10 รายการในการเติมข้อความอัตโนมัติวิดเจ็ตลิงค์ได้อย่างไร?


10

นี่เป็นคำถามเกี่ยวกับโมดูลลิงค์ เนื่องจากด้วยโมดูลลิงก์คุณสามารถป้อนลิงก์ภายนอกหรือภายในทั้งสองเราจึงเชื่อมั่นอย่างยิ่ง

น่าเสียดายที่จำนวนรายการที่จะแสดงจากฟิลด์การเติมข้อความอัตโนมัติของมันถูก จำกัด ไว้ที่ 10 เรามีโหนดจำนวนมากที่มีชื่อเหมือนกันเกือบทั้งหมดดังนั้นจึงเป็นเช่นนั้นว่าโหนดที่เรากำลังค้นหาไม่แสดงในฟิลด์เติมข้อความอัตโนมัติเมื่อมี ชื่อที่ตรงกันมากกว่า 10 รายการ

ขีด จำกัด คือ hardcoded core/lib/Drupal/Core/Entity/EntityAutocompleteMatcher.phpใน มีวิธีที่สง่างามในการเพิ่มจำนวนเล็กน้อยจากภายในโมดูลที่กำหนดเองหรือไม่? ฉันต้องยืดเวลาclass EntityAutocompleteMatcherหรือไม่? ฉันจะต้องวางส่วนขยายของฉันไว้ที่ใดและจะมั่นใจได้อย่างไรว่าส่วนขยายนั้นถูกเรียกใช้จากภายในวิดเจ็ตลิงก์

คำตอบ:


3

ดูเหมือนว่าการแก้ไขที่เหมาะสมสำหรับการนี้ได้รับการเพิ่มรุ่นล่าสุดของแกน 8.8+ ดู# 2863188 Hardcoded จำกัด ขนาดผลในการอ้างอิงกิจการเติมข้อความอัตโนมัติวิดเจ็ต

ป้อนคำอธิบายรูปภาพที่นี่


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

จากนั้นอัปเดต hardcoded 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) มันทำให้ codebase ของคุณยากขึ้น คุณต้องจำไว้ว่าคุณไม่ได้ใช้ core Drupal แต่เป็นเวอร์ชั่นเพิ่มเติม นักพัฒนารายอื่นที่เข้าร่วมโครงการของคุณหลังจากที่คุณออกอาจมีปัญหาในการหาสาเหตุที่ทำให้บริการทำงานในลักษณะที่ไม่ได้มาตรฐาน

นี่คือแฮ็คหลักหรือไม่

ขึ้นอยู่กับว่าคุณจะมองอย่างไร มันจะไม่เข้าสู่โมดูลหลักและการเปลี่ยนรหัส มันไม่ได้แม้แต่จะสร้างแพตช์และใช้มันและติดตามมันด้วยผู้จัดการแพ็คเกจเช่นนักแต่งเพลง มันเป็นมากกว่าการปรับแต่งแบบครั้งเดียวที่จะปรับเปลี่ยนพฤติกรรมของไซต์หลักคล้ายกับ hook ALTER มีแฮ็คหลักในตัวเองมากขึ้นเพราะอยู่ในโมดูลที่คุณกำหนดเองในเว็บไซต์ของคุณ ดังนั้นการอัปเดตหลักของบริการดั้งเดิมจะไม่ได้รับผลกระทบเช่นเดียวกับถ้าคุณแก้ไขหรือแฮ็กรหัสบริการเดิม

แต่มันมีความเสี่ยงเช่นเดียวกับการแฮ็คหลักตามที่กล่าวไว้ข้างต้น

ในคำถามเดิมปัญหาคือชื่อโหนดนั้นไม่ซ้ำกันมากพอ ทางออกที่ดีกว่านอกเหนือจากการเปลี่ยนขีด จำกัด ทั่วโลกเมื่อเลื่อนลงจะเป็นการแก้ปัญหาที่เป็นเอกลักษณ์

สิ่งที่ฉันอยากจะแนะนำคือการเพิ่มฟิลด์ใหม่ field_display_title และใช้มันในหน้าและถ้าคุณต้องการมันอีกฟิลด์ field_teaser_title เพื่อแสดงในหน้ารายการที่คุณต้องการชื่อที่สั้นกว่า จากนั้นชื่อจริงที่ถูกดึงเข้าสู่การอ้างอิงแบบเลือกรายการอ้างอิงนั้นจะมีประโยชน์สำหรับผู้แก้ไขของคุณและไม่ซ้ำกันเช่น "บทความของฉัน (หน้า 1)" หากปัญหาคือแต่ละหน้ามีชื่อเรื่องเดียวกัน จากนั้นคุณไม่จำเป็นต้องยกเลิกบริการหลัก

เมื่อคุณเจอปัญหากับ Drupal ลองค้นหาวิธีแก้ปัญหาที่ต้องใช้รหัสกำหนดเองจำนวนน้อยที่สุด ทำให้ไซต์ของคุณมีเสถียรภาพมากขึ้นง่ายต่อการดูแลรักษาและประหยัดเวลา


3
โดยทั่วไปการเอาชนะบริการหลักมีผลเช่นเดียวกับการใช้ hooks ALTER ความเสี่ยงเกิดขึ้น แต่ค่อนข้างน้อยและสามารถบรรเทาด้วยเอกสารรหัสที่เหมาะสม
ya.teck

1
สาเหตุที่ทำให้มีการแทนที่ที่ดีจำนวนมาก hooks ตะขอแพตช์สามารถลดความสามารถในการบำรุงรักษาของโครงการ
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);
  }

}

การใช้NodeSelectionเป็นคลาสพื้นฐานแทน DefaultSelection จะช่วยให้คุณกรองโหนดที่อ้างอิงตามสถานะ โปรดทราบว่ายังไม่รองรับการอ้างอิงเอนทิตีประเภทอื่น

ซึ่งแตกต่างจากการเชื่อมโยงอ้างอิงเอนทิตีวิดเจ็ตไม่อนุญาตให้มีการระบุตัวเลือกปลั๊กอินผ่านอินเตอร์เฟซที่ใช้งานดังนั้นคุณจะต้องตั้งมันโปรแกรมใช้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 ฉันจะหลีกเลี่ยงการทำเช่นนั้นเพียงแค่ดำเนินการตามข้อเสนอแนะของคุณและใช้เวลาส่วนใหญ่ในการพยายามแก้ไขปัญหาอื่น

การเปลี่ยนแปลงแบบสอบถามที่คุณแนะนำยังมีผลต่อการอ้างอิง entiry เมื่อเชื่อมโยงย่อหน้ากับโหนด โหนดที่ฉัน woking on มีรายการ 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.