Pasar al contenido principal

Cargando...

Función para descargar archivos en Drupal 8 (y 9)

Función para descargar archivos en Drupal 8 (y 9)

Función para descargar archivos en Drupal 8 (y 9)

2 minutos

En muchos de vuestros proyectos se os pedirá ofrecer la descarga de ficheros situados en una carpeta determinada. 

No cabe duda, de que existen numerosas formas de hacerlo, e incluso muchas de ellas son válidas. Personalmente me he encontrado con algunos proyectos que incluso ponen el enlace directamente en el twig del nodo dónde se quiere descargar el archivo.

No es una solución muy mantenible pero si que funciona.

En mi caso, suelo crear una ruta a una función de un controlador que me permite pasar una variable y renderizar el link de descarga siempre que lo necesito.

La ruta

En el archivo routing.yml añade lo siguiente:

example.download.file:
  path: '/download/file/{filename}'
  defaults:
    _controller: '\Drupal\[module_name]\Controller\DownloadController::downloadFile'
  requirements:
    _permission: 'access content'

Recuerda que deberás cambiar [module_name] por el nombre de tu módulo.

El controlador

Dentro de la carpeta src/Controller crearemos un archivo DownloadController.php con el siguiente contenido:

<?php

namespace Drupal\[module_name]\Controller;

use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\HttpFoundation\BinaryFileResponse;

/**
 * Gestiona la descarga de ficheros.
 */
class DownloadController extends ControllerBase {

  /**
   * Download file.
   *
   * @param string $filename
   *   The filename.
   */
  public function downloadFile($filename) {

    $uri_prefix = 'public://downloads/';

    $uri = $uri_prefix . $filename;

    $headers = [
      'Content-Type' => 'text/csv',
      'Content-Description' => 'File Download',
      'Content-Disposition' => 'attachment; filename=' . $filename
    ];

    return new BinaryFileResponse($uri, 200, $headers, true );

  }

}

En este ejemplo le estoy indicando que el archivo que se va a descargar es un csv, pero puede que necesites otro tipo de "Content-Type" por lo que puedes ver un listado completo aquí.

Renderizar el link

Ahora podemos hacer uso de la función Url::fromRoute para renderizar el link dónde lo necesitemos.

Como ejemplo vamos a ver como renderizarlo dentro de un bloque; para lo que crearemos el archivo src\Plugin\Block\ExampleDownloadFiles.php con el siguiente contenido:

<?php

namespace Drupal\[module_name]\Plugin\Block;

use Drupal\Core\Block\BlockBase;
use Drupal\Core\Url;

/**
 * @Block(
 *   id = "example_download_files",
 *   admin_label = @Translation("Example Download Files"),
 *   category = @Translation("Example")
 * )
 */
class ExampleDownloadFiles extends BlockBase {

  /**
   * {@inheritdoc}
   */
  public function build() {
    $build = [];


    $items = [
      'Foo' => 'foo.csv',
      'Bar' => 'bar.csv',
      'Herp' => 'herp.csv',
      'Derp' => 'derp.csv'
    ];


    foreach ($items as $item => $filename) {
      $url = Url::fromRoute('example.download.file', ['filename' => $filename]);
      $links[$item] = [
        '#title' => $this->t($item),
        '#type' => 'link',
        '#url' => $url
      ];
    }

    $file_download_list = [
      '#theme' => 'item_list',
      '#items' => $links
    ];

    $build['file_downloads'] = [
      '#type' => 'container',
      'file_downloads_prefix' => ['#type' => 'html_tag', '#tag' => 'p', '#value' => $this->t('Download the csv:')],
      'file_downloads_list' => $file_download_list,

    ];

    return $build;

  }

Artículos Relacionados

Añadir nuevo comentario

Este campo no se mostrará públicamente.