2023-03-15

经常我们自定义select表单可能需要加载大量的entity. 导致性能很低下. 代码如下. 当我的term address有超过1000个时,页面就需要很久了.

$termStorage = \Drupal::entityTypeManager()->getStorage('taxonomy_term');
$options = [];
foreach($termStorage->loadByProperties(['vid' => 'address']) as $entity) {
  $options[$entity->id()] = $entity->label();
}
$form['address'] = [
  '#type' => 'select',
  '#title' => $this->t('Address'),
  '#options' => $options,
  '#required' => TRUE,
];

 

这时我们可以使用select2. 使用select的ajax加载选择项, 下载并启用select2. 我们在里面定义了options来自自定义路由: #autocomplete_route_name = test_code.address_autocomplete. 我们这时只需要定义此路由返回部分数据就行. 因为select2有搜索功能. 我们不需要返回全部

<?php

namespace Drupal\test_code\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormState;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Entity\Element\EntityAutocomplete;

/**
 * Provides a test_code form.
 */
class SelectForm extends FormBase {

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'test_code_select';
  }

  public static function AddressAutocompleteCallback(&$element) {
    $complete_form = [];
    $element = EntityAutocomplete::processEntityAutocomplete($element, new FormState(), $complete_form);
    $element['#autocomplete_route_name'] = 'test_code.address_autocomplete';
    return $element;
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {

    $form['address'] = [
      '#type' => 'select2',
      '#select2' => [
        'minimumInputLength' => 0,
      ],
      '#autocomplete' => true,
      '#target_type' => 'taxonomy_term',
      '#autocomplete_route_callback' => self::class . '::AddressAutocompleteCallback',
      '#autocomplete_route_parameters' => [],
      '#title' => $this->t('Address'),
    ];

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state) {

  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {

  }

}

 

定义路由:

test_code.address_autocomplete:
  path: '/test-code/example'
  defaults:
    _title: 'Example'
    _controller: '\Drupal\test_code\Controller\AutocompleteAddress::build'
  requirements:
    _permission: 'access content'

定义controller只返回50条数据。 可以搜索相关更多的数据

<?php

namespace Drupal\test_code\Controller;

use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;

/**
 * Returns responses for test_code routes.
 */
class AutocompleteAddress extends ControllerBase {

  /**
   * Builds the response.
   */
  public function build(Request $request) {

    $keyword = $request->query->get('q');
    $termStorage = \Drupal::entityTypeManager()->getStorage('taxonomy_term');
    $query = $termStorage->getQuery();
    // 这里的keyword是select2搜索的关键词.
    if ($keyword) {
      $query->condition('name', "%{$keyword}%", 'LIKE');
    }
    $query->range(0, 50);
    $ids = $query->execute();
    $results = [];
    if ($ids) {
      foreach($termStorage->loadMultiple($ids) as $entity) {
        $results[] = (object)[
          'id' => $entity->id(),
          'text' => $entity->label()
        ];
      }
    }

    return new JsonResponse([
      'results' => $results
    ]);
  }

}

 

标签: Drupal9 性能