Pasar al contenido principal
Campo "entity_autocomplete" personalizado. Drupal 8

Campo "entity_autocomplete" personalizado. Drupal 8

Campo "entity_autocomplete" personalizado. Drupal 8

4 minutos

Las funcionalidades que por defecto podemos implementar con el tipo de campo "entity_autocomplete" son muy variadas, como podéis comprobar en la documentación de Drupal al respecto (ir a la documentación).

Pero lo mejor es que, como desarrolladores, podemos realizar personalizaciones en la visualización de esos datos de una manera más o menos sencilla.

Se podría decir que sólo necesitamos un controlador que devuelva los resultados tal y como los queremos, y una ruta que apunte a ese controlador... veamos como.

Generando la ruta

En nuestro módulo, en el archivo routing.yml vamos a agregar una ruta que apunte a la función del controlador que nos devolverá los resultados que queremos mostrar en nuestro campo.

# Este nombre de ruta lo usaremos al generar nuestro campo en el formulario.
my_module.autocomplete.articles:
  path: '/admin/my_module/autocomplete/articles'
  defaults:
    _controller: '\Drupal\my_module\Controller\ArticleAutoCompleteController::handleAutocomplete'
    _format: json
  requirements:
    _permission: 'access content'

El Controlador

El siguiente paso es crear el archivo que realizará la funcionalidad en sí misma. Este archivo lo crearemos en la carpeta src/Controller. 

Para este ejemplo nombraremos al archivo como ArticleAutoCompleteController.php

<?php

namespace Drupal\my_module\Controller;

/**
 * @file
 * ArticleAutoCompleteController.php
 */

use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\Element\EntityAutocomplete;
use Drupal\Component\Utility\Xss;

use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;

/**
 * Clase ArticleAutoCompleteController.
 */
class ArticleAutoCompleteController extends ControllerBase {

  /**
   * The node storage.
   *
   * @var \Drupal\node\NodeStorage
   */
  protected $nodeStorage;

  /**
   * {@inheritdoc}
   */
  public function __construct(EntityTypeManagerInterface $entity_type_manager) {
    $this->nodeStroage = $entity_type_manager->getStorage('node');
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    // Instantiates this form class.
    return new static(
      $container->get('entity_type.manager')
    );
  }

  /**
   * Este es el método que se llama desde el controlador.
   */
  public function handleAutocomplete(Request $request) {
    $results = [];
    $input = $request->query->get('q');

    // Compruebo si existe el parámetro.
    if (!$input) {
      return new JsonResponse($results);
    }

    $input = Xss::filter($input);

    $query = $this->nodeStroage->getQuery()
      ->condition('type', 'article')
      ->condition('title', $input, 'CONTAINS')
      ->groupBy('nid')
      ->sort('created', 'DESC')
      ->range(0, 10);

    $ids = $query->execute();
    $nodes = $ids ? $this->nodeStroage->loadMultiple($ids) : [];

    foreach ($nodes as $node) {
      switch ($node->isPublished()) {
        case TRUE:
          $availability = 'Publicado';
          break;

        case FALSE:
        default:
          $availability = 'Sin publicar';
          break;
      }

      /* Contruímos el título que vamos a mostrar */
      $label = [
        $node->getTitle(),
        '<small>(' . $node->id() . ')</small>',
        $availability,
      ];

      $results[] = [
        'value' => EntityAutocomplete::getEntityLabels([$node]),
        'label' => implode(' ', $label),
      ];
    }

    return new JsonResponse($results);
  }
}

Con estos dos pasos ya tenemos creado nuestro campo de autocompletado personalizado. Sólo nos falta usarlo en nuestro código...

Usando el "entity_autocomplete"

Para obtener un campo de autocompletado y, gracias al código anterior, bastará con hacer uso del Form Api de la siguiente manera:

/* El valor de #autocomplete_route_name será el nombre que hemos dado a la ruta
 * en el archivo routing.yml */
$form['article'] = [
  '#type' => 'textfield',
  '#title' => $this->t('My Autocomplete'),
  '#autocomplete_route_name' => 'my_module.autocomplete.articles',
];

Tal y como se comenta en el fragmento de código, el valor del atributo #autocomplete_route_name deberá ser el mismo valor que hemos dado como nombre de la ruta que apunta al controlador.

Para una mejor comprensión aquí os pongo un ejemplo completo de formulario que hace uso de esta funcionalidad:

<?php

namespace Drupal\my_module\Form;

/**
 * @file
 * SampleForm.php
 */

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

use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Clase SampleForm.
 */
class SampleForm extends FormBase {

  /**
   * The node storage.
   *
   * @var \Drupal\node\NodeStorage
   */
  protected $nodeStorage;

  /**
   * {@inheritdoc}
   */
  public function __construct(EntityTypeManagerInterface $entity_type_manager) {
    $this->nodeStorage = $entity_type_manager->getStorage('node');
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('entity_type.manager')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    $form['article'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Select an article'),
      '#autocomplete_route_name' => 'my_module.autocomplete.articles',
    ];

    $form['actions'] = [
      '#type' => 'actions',
    ];

    $form['actions']['submit'] = [
      '#type' => 'submit',
      '#value' => $this->t('Save'),
    ];

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    // Obtengo el id del nodo.
    $article_id = EntityAutocomplete::extractEntityIdFromAutocompleteInput($form_state->getValue('article'));

    // Realizo otras operaciones.
  }

}

 

Artículos relacionados

Comentarios

Añadir nuevo comentario

Este campo no se mostrará públicamente.