D8 Ficheros (Files) e imágenes - pierregermain/MyDrupal GitHub Wiki
- Trabajando con Ficheros en Drupal 8
- Control de permisos sobre archivos
- Presentación de imágenes con estilos
- Efecto de Imágen personalizado
Trabajando con Ficheros en Drupal 8
Ficheros públicos y privados
Tipos:
-
públicos: tiene una ruta que equivale a la carpeta real donde está almacenado (Ej. http://example.com/sites/default/files/fichero.txt)
-
privados: No accesible directamente desde la web. Ruta se genera dinámicamente. (Ej. http://example.com/system/files/informes/informe2015.pdf)
A saber:
- Las rutas se configuran desde el settings.php y se pueden ver desde /admin/config/media/file-system.
- Por defecto sólo está activado la descarga pública de ficheros.
- Para activar la descarga privada se hace desde el settings.php con
$settings['file_private_path'] = '/home/username/private';
. - La idea es que la ruta privada esté fuera del alcance de drupal.
- El acceso privado es menos eficiente que el público.
- para cambiar la ubicación de los ficheros públicos lo hacemos desde el settings.php descomentando
$settings['file_public_path'] = 'sites/default/files';
donde la ruta no lleva barra al principio y es relativa a la instalación de drupal y debe ser accesible desde la web.
URIs
Al trabajar con ficheros expresamos las rutas en formato scheme://target donde:
- scheme puede ser public o private
Ejemplo:
uri | ruta |
---|---|
public://foo/bar/example.txt | /sites/default/files/foo/bar/example.txt |
Tipos de ficheros en Drupal
- Managed (Gestionados): Representados por Entidades y gestionados con Entity API y los hooks de Drupal.
- Unmanaged (No gestionados): No son entidades y sólo se pueden gestionar con funciones nativas de PHP.
Clase para trabajar con Ficheros
Servicio: file_system (clase FileSystem)
Ejemplo:
$file_system = \Drupal::service('file_system');
$uri = 'private://foo/bar/example.txt';
$directory = $file_system->dirname($uri);
//devuelve: 'private://foo/bar'
$scheme = $file_system->uriScheme($uri);
//devuelve: 'private'
$filename = $file_system->basename($uri);
//devuelve: 'example.txt
$file_system = \Drupal::service('file_system');
// crea el directorio foo
$file_system->mkdir('public://foo');
// crea los directorios /bar/baz con permisos 755
$file_system->mkdir('public://bar/baz', 0755, TRUE);
// elimina el directorio foo
$file_system->rmdir('public://foo');
Métodos para trabajar con ficheros
-
Ficheros no gestionados (Unmanaged): (Libro III p. 277)
- file.inc Ahí vienen todos los métodos que se pueden usar. Muchos están deprecated por lo que hay que usar el servicio correspondiente.
Ejemplo:
//localiza todas las plantillas en el módulo forum $directory = \Drupal::root() . "/core/modules/forum"; $files = file_scan_directory($directory, '/\.twig$/');
-
Ficheros gestionados (Managed): (Libro III p. 280)
- File.php
- Los métodos de
file.inc
se pueden aplicar a Ficheros Gestionados usando$file_storage = \Drupal::entityTypeManager()->getStorage('file');
- Podemos usar la interfaz FileInterface
- tablas:
- file_managed: Guarda información cómo fid, uuid, langcode, uid, filename, etc.
- file.usage
Ejemplo: Acceder al user_picture de un usuario
$currentUser = \Drupal::currentUser();
$user_storage = \Drupal::entityTypeManager()->getStorage('user');
$user = $user_storage->load($currentUser->id());
$image_id = $user->get('user_picture')->first()->getValue()['target_id'];
$file_storage = \Drupal::entityTypeManager()->getStorage('file');
$image = $file_storage->load($image_id);
$image_uri = $image->getFileUri();
Hooks
- sólo para ficheros gestionados
Podemos usar los hooks genéricos de entidades (poniendo cómo type "file")
hook_ENTITY_TYPE_load($entities);
hook_ENTITY_TYPE_create($entity);;
hook_ENTITY_TYPE_presave($entity);
hook_ENTITY_TYPE_insert($entity);
hook_ENTITY_TYPE_update($entity);
hook_ENTITY_TYPE_predelete($entity);
hook_ENTITY_TYPE_delete($entity);
Además tenemos los siguientes hooks específicos:
hook_file_download($uri);
hook_file_mimetype_mapping_alter(&$mapping);
hook_file_copy(Drupal\file\FileInterface $file, Drupal\file\FileInterface $source);
hook_file_move(Drupal\file\FileInterface $file, Drupal\file\FileInterface $source);
hook_file_url_alter(&$uri);
hook_file_validate(Drupal\file\FileInterface $file);
Formularios con ficheros:
Elementos
- file: Según la función que usemos podremos elegir que "file" sea managed o no managed.
- managed: file_managed_save_data()
- unmanaged: file_save_upload()
- managed_file: no necesitamos usar la función file_save_upload()
Pasos para crear formulario con ficheros no gestionados (unmanaged):
1. Crear el route
fichero: mymodule.routing.yml
mymodule.unmanaged:
path: '/mymodule/files/unmanaged'
defaults:
_form: '\Drupal\mymodule\Form\Unmanaged'
_title: 'Unmanaged file upload'
requirements:
_permission: 'access content'
2. Crear el Formulario
Fichero: /scr/Form/Unmanaged.php
<?php
namespace Drupal\mymodule\Form;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
class Unmanaged extends FormBase {
public function buildForm(array $form, FormStateInterface $form_state) {
$form['upload'] = [
'#type' => 'file',
'#title' => $this->t('PDF File'),
'#description' => $this->t('Upload a PDF File.'),
];
$form['actions'] = ['#type' => 'actions'];
$form['actions']['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Upload file'),
];
return $form;
}
public function getFormId() {
return 'mymodule_unmanaged';
}
public function submitForm(array &$form,
FormStateInterface $form_state) {
$directory = 'private://unmanaged';
$destination = $directory . '/unmanaged.pdf';
$file_system = \Drupal::service('file_system');
$file_system->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY);
// Get the file from the request
$all_files = \Drupal::request()->files->get('files', array());
$file = file_get_contents($all_files['upload']);
if ($file_system->saveData($file, $destination, FileSystemInterface::EXISTS_REPLACE)) {
\Drupal::messenger()->addStatus(t('File uploaded'));
}
else {
\Drupal::messenger()->addError(t('Error writing file.'));
}
}
}
Pasos para crear Formulario con archivos gestionados
1. Crear el fichero routing
mymodule.managed:
path: '/mymodule/files/managed'
defaults:
_form: '\Drupal\mymodule\Form\Managed'
_title: 'Managed file upload'
requirements:
_permission: 'access content'
2. Crear el Formulario
- Se crea campo tipo 'managed_file'.
- Al subir el fichero por 'managed_file' el fichero queda guardado en la tabla 'file_managed' cómo temporal en estado status = 0.
- Para que el fichero se quede guardado cómo status = 1 hay que añadirlo a la tabla 'file_usage'
- Si queremos subir varios ficheros de golpe podemos usar la propiedad
'#multiple' => TRUE
<?php
namespace Drupal\mymodule\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\file\FileUsage\DatabaseFileUsageBackend;
use Symfony\Component\DependencyInjection\ContainerInterface;
class Managed extends FormBase {
protected $currentUser;
protected $fileUsage;
public function __construct(AccountInterface $current_user,
DatabaseFileUsageBackend $file_usage) {
$this->currentUser = $current_user;
$this->fileUsage = $file_usage;
}
public static function create(ContainerInterface $container) {
return new static(
$container->get('current_user'),
$container->get('file.usage')
);
}
public function buildForm(array $form, FormStateInterface $form_state) {
$form['upload'] = [
'#title' => $this->t('Upload file'),
'#type' => 'managed_file',
'#upload_location' => 'public://managed',
'#upload_validators' => [
'file_validate_extensions' => ['pdf'],
],
'#required' => TRUE,
];
$form['actions'] = ['#type' => 'actions'];
$form['actions']['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Upload file'),
];
return $form;
}
public function getFormId() {
return 'mymodule_managed';
}
public function submitForm(array &$form, FormStateInterface $form_state) {
$file_storage =
\Drupal::entityTypeManager()->getStorage('file');
foreach ($form_state->getValue('upload') as $fid) {
$file = $file_storage->load($fid);
$this->fileUsage->add($file, 'mymodule', 'user', $this->currentUser->id(), 1);
}
}
}
Control de permisos sobre archivos
Pasos:
- Crear el fichero de permisos
'download private file':
title: Download private file
description: Allow users to download private files
- Usar hook_file_download($uri)
- Con hook_file_download($uri) también se pueden añadir cabeceras adicionales al archivo (nombre de archivo, tipo MIME, forzar descarga, etc.)
- En este ejemplo comprobamos:
- Que el fichero esté en la carpeta managed
- Que el usuario tenga permiso "download private file"
- En este ejemplo:
- Devolvemos el fichero con nombre private.pdf
- Le decimos al navegador que no guarde el fichero en la caché
/**
* Implements hook_file_download().
*/
function mymodule_file_download($uri) {
$file_system = \Drupal::service('file_system');
$directory = $file_system->dirname($uri);
if(strpos($directory, 'private://managed') !== FALSE) {
if (\Drupal::currentUser()->hasPermission('download private file')) {
// tiene acceso al archivo
return [
'Content-type' => 'application/pdf',
'Content-disposition' => 'attachment; filename="private.pdf"',
'Cache-Control' => 'private',
];
} else {
return -1; // no tiene acceso
}
} else {
return NULL; //no gestionado por nuestro módulo
}
}
Presentación de imágenes con estilos
En render array
$build['image'] = [
'#theme' => 'image_style',
'#style_name' => 'thumbnail',
'#uri' => $image_uri,
];
donde:
- #theme es la plantilla
- #style_name es el nombre del estilo a ser usado
Atributos disponibles:
- #width y #height
- #title
- #alt
En enlaces
$style = \Drupal::entityTypeManager()->getStorage('image_style')->load('thumbnail');
$url = $style->buildUrl('public://image.png');
En Twig
{% set test_image = {
'#theme':'image_style',
'#style_name': 'thumbnail',
'#uri':'public://images/foo.jpg,
'#alt':'Some text',
'#attributes': { class: 'foo bar' },
} %}
{{ test_image }}
Alternativamente usar https://www.drupal.org/project/twig_tweak:
{{ 'public://images/foo.jpg' | image_style('thumbnail') }}
Efecto de Imágen personalizado
Más info en Libro III p. 290