Controllers (controladores) são a melhor forma de criar uma página personalizada através de código em Drupal 8.

Neste artigo, vamos guiar-te através da criação do teu primeiro controller simples. Criaremos um exemplo de controller que mostra uma imagem aleatória de um cão, a partir da Dog API.

Criar um módulo

Tal como a maioria das funcionalidades do Drupal, esta precisa ser alojadada dentro de um módulo costumizável. Vamos criar um simples.

Protip: Se tiveres o Drupal Console instalado, só precisas de executar o drupal generate:module e ele vai pedir-te a informação necessária e criar o código padrão.

Chamaremos ao módulo “random_doggo”. Dentro de modules/custom, criámos:

  ● random_doggo/random_doggo.info.yml:

  name: 'random_doggo'
type: module
description: 'Provides an example Controller that gets a random

image of a dog'

core: 8.x
package: 'Custom'

Criar o teu controller

O teu controller tem de estar dentro de src/Controller na tua pasta do módulo. Vamos, então, criá-lo aí.

Protip: Tal como anteriormente, se tiveres o Drupal Console, podes também executar o drupal generate:controller para te guiar através da criação do teu código básico do Controller. Isto implica não teres que lidar com a injeção de dependências de serviços, bem como com o encaminhamento.

Então ficamos com um random_doggo/src/Controller/RandomDoggoController.php:

  <?php
namespace Drupal\random_doggo\Controller;


use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\DependencyInjection\ContainerInterface;


/**
 * Class RandomDoggoController.
 */

class RandomDoggoController extends ControllerBase {


  /**
   * GuzzleHttp\ClientInterface definition.
   *
   * @var \GuzzleHttp\ClientInterface
   */

  protected $httpClient;


  /**
   * The base URL for the dog API.
   *
   * @var string
   */

  private $baseUrl = 'https://dog.ceo/api/';


  /**
   * {@inheritdoc}
   */

  public static function create(ContainerInterface $container) {
    $instance = parent::create($container);
    $instance->httpClient = $container->get('http_client');
    return $instance;
  }


}

Criar os métodos do controller

Agora apenas adicionamos dentro disso os métodos que queremos executar para cada página. Cada uma vai devolver uma matriz de renderização da página que vamos mostrar. Vamos criar dois métodos para o nosso exemplo, um para uma imagem aleatória, get() e outro para uma imagem aleatória de um cão de determinada raça, getByBreed($breed).

Então agora o nosso RandomDoggoController.php deve parecer-se com isto:

<?php


namespace Drupal\random_doggo\Controller;


use Drupal\Component\Serialization\Json;
use GuzzleHttp\Exception\ClientException;
use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;


/**
 * Class RandomDoggoController.
 */

class RandomDoggoController extends ControllerBase {


​   /**
   * GuzzleHttp\ClientInterface definition.
   *
   * @var \GuzzleHttp\ClientInterface
   */

  protected $httpClient;


​   /**
   * The base URL for the dog API.
   *
   * @var string
   */

  private $baseUrl = 'https://dog.ceo/api/';


​   /**
   * {@inheritdoc}
   */

  public static function create(ContainerInterface $container) {
    $instance = parent::create($container);
    $instance->httpClient = $container->get('http_client');
    return $instance;
  }


​   /**
   * Gets a random dog.
   *
   * @return array
   * Render array for the random dog template.
   */

  public function get() {
    // Get a random dog!
    $endpoint = 'breeds/image/random';
    $response = $this->httpClient->get($this->baseUrl . $endpoint);
    $data = Json::decode($response->getBody());


​     return [
      '#type' => 'markup',
      '#markup' => "<img src='{$data['message']}'>",
      '#cache' => [
        'max-age' => 0,
      ],
    ];
  }


​   /**
   * Gets a random dog, of a specific breed.
   *
   * @param string $breed
   * The breed of the dog to look for.
   *
   * @return array
   * Render array for the random dog template.
   */

  public function getByBreed($breed) {
    try {


​       // Get a random dog!
      $endpoint = "breed/$breed/images/random";
      $response = $this->httpClient->get($this->baseUrl . $endpoint);
    }
    catch (ClientException $e) {
      // Return a 404 if an error occured.
      throw new NotFoundHttpException();
    }


​     $data = Json::decode($response->getBody());


​     return [
      '#type' => 'markup',
      '#markup' => "<img src='{$data['message']}'>",
      '#cache' => [
        'max-age' => 0,
      ],
    ];
  }


​ }

Criar a nossa rota

Temos os métodos, agora precisamos de dizer ao Drupal quando é que ele os deve executar. Podemos fazê-lo com um ficheiro de encaminhamento. Basicamente, ele dirá ao Drupal “Se visitares esta página então deixa que o nosso método de controller lide com aquilo que é mostrado ao utilizador”.

Colocamos o ficheiro de encaminhamento dentro da nossa pasta do módulo.

Então ficamos com um random_doggo.routing.yml:

random_doggo.random_doggo_controller_get:
  path: '/doggo'
  defaults:
    _controller: '\Drupal\random_doggo\Controller\RandomDoggoCont

roller::get'

    _title: 'Random Doggo!'
  requirements:
    _permission: 'access content'
random_doggo.random_doggo_controller_getByBreed:
  path: '/doggo/{breed}'
  defaults:
  _controller: '\Drupal\random_doggo\Controller\RandomDoggoContro

ller::getByBreed'

  _title: 'Random Doggo by Breed!'
  requirements:
  _permission: 'access content'

Isto diz ao Drupal, quando quer que visitemos o /doggo no nosso website, executaremos o nosso método get() do Controller, e mostrar uma imagem aleatória de um cão. Também ao visitar o /doggo/hound, vamos chamar o nosso método getByBreed() do Controller e ter uma imagem aleatória de um cão de uma determinada raça. O utilizador pode colocar outra raça no URL. A nossa função vai recebê-la como o parâmetro $breed.

Ativar o teu módulo

Muito importante, não te esqueças de ativar o teu módulo. Tanto através do backoffice ou ao executar o drush en random_doggo.

Brincar com os Controllers

Podemos melhorar este exemplo de Controller mais à frente ao adicionar um template personalizável em vez de marcação simples para a matriz de renderização.

Consegues também utilizar um Controller para, literalmente, qualquer coisa no Drupal. Podes vê-lo como uma página personalizável no Drupal onde podes executar o teu próprio código personalizado. Neste exemplo, devolvemos uma matriz de renderização, mas podes também devolver apenas uma resposta HTTP.

Podemos ter um Controller, encaminhado para /unpublish/last-week para despublicar todos os nodes com mais de uma semana, por exemplo. Podemos utilizar permissões no ficheiro de encaminhamento para termos a certeza que só um determinado grupo de utilizador tem acesso ao método do Controller. Por exemplo, no nosso ficheiro de encaminhamento anterior, se em vez de _permission: 'access content', tivéssemos _role: 'editor', então apenas utilizadores com o group de editor é que podem aceder.

Como podes ver, Controllers podem ser muito versáteis e uma grande ferramenta no arsenal dos programadores para ignorar o backoffice do Drupal e utilizar o seu próprio código para criarem uma funcionalidade personalizada.