Drupal 8: Generando enlaces a ficheros de entidades ‘file’

Drupal 8: Generando enlaces a ficheros de entidades ‘file’

  • Autor: fjavimartin

  • Fecha de Creación: 21/04/2019

  • Categorías:

    • Drupal,
    • Drupal 8,
    • Php,
    • Code snippets,
    • Entity,
    • File

En esta entrada de blog dedicada a drupal modificaremos el formulario que hicimos en la anterior entrega para que los ficheros que subamos se guarden en el sistema de ficheros privado. Además, añadiremos una tabla en la que se mostrará una lista de enlaces a todos los ficheros que hemos subido desde nuestro módulo independientemente del alojamiento que hayamos escogido para ellos (público o privado).

1. Modificación del formulario

El primer paso será modificar el formulario para que todos los ficheros que subamos se guarden en en el sistema de ficheros privado. Una vez realizado este cambio será drupal el encargado de realizar la gestión de la descarga del fichero en lugar del servidor web:

$form['files'] =  [
      '#type' => 'managed_file',
      '#title' => $this->t('Upload file'),
      '#upload_location' => 'private://drupal_miseries',
      '#upload_validators' => [
        'file_validate_extensions' => ['csv'],
      ],
      '#required' => TRUE,
      '#weight' => 1,
    ];

Para esta modificación no hemos necesitado mucha cantidad de código. Tan solo modificamos el valor de la propiedad #upload_location y añadimos una uri donde indicamos la ubicación en la que se guardarán los ficheros que subamos a partir de ahora.

2. Elemento de formulario ‘table’

Uno de los elementos nuevos para los formularios que incorpora drupal 8 es table. Este elemento nos permitirá añadir una tabla a nuestros formularios. Nos permitirá añadir en cada celda simples cadenas o complejos elementos renderizables.

Entre las propiedades más destacadas están las siguientes:

- #header: Array con los títulos de cada una de las columnas.

- #rows: Array donde cada fila contendrá los valores para cada una de las columnas.

- #empty: Texto a mostrar cuando no haya ningún elemento en la tabla.

- #responsive: Indicaremos si la tabla contendrá la librería drupal.resonsibe_table haciendo que su comportamiento sea responsive. Por defecto estará a TRUE.

- #sticky: Indicaremos si la cabecera de la tabla estará siempre visible incluyendo la librería drupal.tableheader. Por defecto estará a FALSE.

- #size: Indicaremos el tamaño de los elementos de entrada en número de caracteres.

El código con el que incluiremos este elemento en nuestro formulario será el siguiente:

$header = [
      'filename' => $this->t('File name'),
    ];
$form['files_table'] = [
      '#type' => 'table',
      '#header' => $header,
      '#empty' => $this->t('Sorry, no uploaded files.'),
      '#caption' => $this->t('File List'),
      '#weight' => 3,
    ];

Mediante la variable $header declaramos la clave interna para cada una de las columnas de la tabla junto a la cadena que finalmente se mostrará en la cabecera de la columna.

Falta algo, verdad? Continuar leyendo y no seáis impacientes.

3. Obteniendo los ficheros subidos desde nuestro módulo

Añadiremos una función a nuestro formulario que nos devolverá un array con todos los ficheros que hayamos subido desde nuestro módulo. Para cada una de las entradas del array utilizaremos como clave el id de la entidad file y cada uno de los nombres de los ficheros irá en la clave [‘filename’] que previamente hemos declarado en el header de la tabla.

protected function getFiles() {
    $storage_files = $this->entityTypeManager->getStorage('file');
    $files = $storage_files->loadMultiple();
    $list_files = array();
    
    foreach ($files as $id => $file) {
      $fileusage = $this->fileUsage->listUsage($file);
      if ( array_key_exists('drupal_miseries', $fileusage) ) {
        $uri = $file->get('uri')->value;
        $name = $file->get('filename')->value;
        $url_file = file_create_url($uri);
        
        $url = Url::fromUri($url_file);
        $link = Link::fromTextAndUrl($name, $url);
        
        $list_files[$id]['filename'] = $link->toRenderable();
      }
    }
    
    return $list_files;
  }

La primera parte de la función es fácil, obtenemos un gestor de almacenamiento para acceder a las entidades file. Recorreremos este array para determinar cuáles de los ficheros han sido subidos desde nuestro módulo.

El servicio file.usage nos permitirá determinar que módulo está usando que fichero. Solamente implementará tres métodos: add/delete/listUsage que nos permitirán marcar/eliminar un fichero como si lo estuviera utilizando un determinado módulo o consultar quién está utilizando un fichero. Esta última función nos devolverá un array como el siguiente:

Array
(
    [drupal_miseries] => Array
        (
            [user] => Array
                (
                    [1] => 1
                )

        )

)

En el primer nivel del array encontramos el módulo que está utilizando el fichero que hemos pasado por parámetro, el segundo será el tipo de objeto que lo usa y el tercero será un contador con el número de veces que este fichero ha sido accedido.

Una vez tenemos esta información determinaremos mediante la función array_key_exists si este fichero está siendo usado por nuestro módulo y entonces obtendremos de la entidad file la uri para su acceso y el nombre real del fichero. Decimos el nombre real porque para el caso que dos ficheros con el mismo nombre sean subidos al mismo directorio será drupal el que modifique el nombre final con un contador de tal manera que no podrá haber dos ficheros con el mismo nombre en el mismo directorio.

El array que se corresponderá con una entidad file se parecerá a lo siguiente:

stdClass Object
(
    [__CLASS__] => Drupal\file\Entity\File
    [values] => Array
        (
            [fid] => Array
                (
                    [x-default] => 288
                )

            [uuid] => Array
                (
                    [x-default] => dbe1952f-f1bc-4803-a413-96259cb5e038
                )

            [langcode] => Array
                (
                    [x-default] => Array
                        (
                            [0] => Array
                                (
                                    [value] => es
                                )

                        )

                )

            [uid] => Array
                (
                    [x-default] => 1
                )

            [filename] => Array
                (
                    [x-default] => test_workers_1.csv
                )

            [uri] => Array
                (
                    [x-default] => public://drupal_miseries/test_workers_1_0.csv
                )

            [filemime] => Array
                (
                    [x-default] => text/csv
                )

            [filesize] => Array
                (
                    [x-default] => 163
                )

            [status] => Array
                (
                    [x-default] => 1
                )

            [created] => Array
                (
                    [x-default] => 1552477843
                )

            [changed] => Array
                (
                    [x-default] => 1552477845
                )

        )

    [fields] => Array
        (
        )

    [fieldDefinitions] => 
    [languages] => 
    [langcodeKey] => langcode
    [defaultLangcodeKey] => default_langcode
    [activeLangcode] => x-default
    [defaultLangcode] => es
    [translations] => Array
        (
            [x-default] => Array
                (
                    [status] => 1
                )

        )

    [translationInitialize] => 
    [newRevision] => 
    [isDefaultRevision] => 1
    [entityKeys] => Array
        (
            [bundle] => file
            [id] => 288
            [label] => test_workers_1.csv
            [langcode] => es
            [uuid] => dbe1952f-f1bc-4803-a413-96259cb5e038
        )

    [translatableEntityKeys] => Array
        (
            [langcode] => Array
                (
                    [x-default] => es
                )

        )

    [validated] => 
    [validationRequired] => 
    [loadedRevisionId] => 
    [entityTypeId] => file
    [enforceIsNew] => 
    [typedData] => 
    [cacheContexts] => Array
        (
        )

    [cacheTags] => Array
        (
        )

    [cacheMaxAge] => -1
    [_serviceIds] => Array
        (
        )

)

Con la uri de nuestro fichero obtendremos la ruta completa para descargarlo con la función file_create_url que se parecerá a lo siguiente en función de si el fichero está alojado en el sistema de ficheros público o privado:

https://misitio/drupal8/system/files/drupal_miseries/test_workers_2.csv
https://misitio/drupal8/sites/default/files/drupal_miseries/test_workers_1_0.csv

Para el primer caso será un fichero que estará alojado en el sistema de ficheros privado y será drupal quién gestione la descarga del mismo. El segundo caso será un fichero alojado en el sistema de fichero público y será el servidor web quién se encargue de su gestión.

Por último generamos el objeto Url y Link que finalmente estará contenido en la celda de la tabla:

$url = Url::fromUri($url_file);
$link = Link::fromTextAndUrl($name, $url);
        
$list_files[$id]['filename'] = $link->toRenderable();

Para generar el enlace utilizaremos el nombre del fichero y el objeto Url, pero en el array que finalmente devolveremos guardaremos el array renderizable de nuestro enlace. En este array solamente podremos devolver texto plano o un array renderizable con el contenido deseado, en cualquier otro caso no se mostrará nada en la tabla.

4. Añadiendo listado ficheros a la tabla

Para añadir el array que nos devolverá la función anterior a nuestra tabla tenemos varias opciones, podremos añadirlo mediante la propiedad #rows o podremos añadir los resultados directamente al elemento de formulario como podemos ver en el siguiente fragmento de código:

foreach ($this->getFiles() as $key => $value) {
      $form['files_table'][$key] = $value;
    }

En nuestro caso utilizaremos este último método.

Conclusiones

Con esta última entrega completamos la serie de artículos dedicada a los ficheros en drupal con la inclusión de un elemento table en nuestro formulario que nos permitirá acceder a todos los ficheros que hayamos subidos desde nuestro módulo.

Entre los enlaces que aparecen en las referencias encontraréis el enlace al git que contiene la definición completa del formulario que he utilizado en esta entrada de blog.

Disfrutar!!!!!!!

Referencias

https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Render%21Element%21Table.php/class/Table/8.2.x

https://www.drupal.org/node/1876710

https://api.drupal.org/api/drupal/core%21modules%21file%21src%21Entity%21File.php/class/File/8.2.x

https://api.drupal.org/api/drupal/core%21modules%21file%21file.services.yml/service/file.usage/8.5.x

https://api.drupal.org/api/drupal/core%21modules%21file%21src%21FileUsage%21DatabaseFileUsageBackend.php/function/DatabaseFileUsageBackend%3A%3AlistUsage/8.5.x

https://www.e-quipos.es/blog/drupal-8-ficheros-en-drupal

https://www.e-quipos.es/blog/drupal-8-creaci%C3%B3n-de-usuarios-mediante-c%C3%B3digo

https://git.drupalcode.org/sandbox/javier.martin-2911003/blob/develop/drupal_miseries/src/Form/ImportUsers.php

 

Todos los Derechos Reservados © 2016

Funciona con Drupal