3.4.0. Funcionalidades auxiliares - diezMalena/api_FCTFiller GitHub Wiki

En esta sección de la Wiki se desarrollan todas las funcionalidades que son de uso universal en la aplicación y que no están asociadas a ninguna sección del desarrollo.

Cliente

Modales de visualización, edición y otros

Todas las acciones que implican la visualización o introducción de información se realizan mediante invocación de una ventana modal, derivando estas funcionalidades a otros componentes, pero manteniendo al usuario en la vista general, para que no pierda el foco.

La idea de los modales está dirigida a reducir la cantidad de código que se elabora: cada parte tiene un solo modal, que se construye de forma distinta y hace llamadas a métodos diferentes según las variables de inicio que reciban.

Esto se consigue gracias a los EventEmitter, que nos permiten comunicar componentes. Incrustando un EventEmitter en el servicio correspondiente, podemos accionar el envío de datos:

@Output() trigger: EventEmitter<any> = new EventEmitter();

Estos datos se envían desde el componente emisor de la siguiente forma:

this.servicio.trigger.emit([datos]);

que se recogerán en el componente receptor mediante subscripción:

this.servicio.trigger.subscribe({
    next: (data: Array<any>) => {
        // En esta región de código se recogen los datos
    },
});

El modal puede recibir un número indeterminado de variables. Típicamente, recibirá una variable boolean o number que indicará el modo del modal (creación, visualización, edición...); y tantas variables como sean necesarias para mostrar la información pertinente.

Diálogo de confirmación

El diálogo de confirmación se desarrolló para su uso en todo el cliente con el siguiente planteamiento: cada vez que el usuario realice una acción delicada o que implique la pérdida de cierto progreso, tendrá la oportunidad de confirmar o rechazar dicha acción. También se puede utilizar para dar la opción al usuario de realizar acciones adicionales, como crear un convenio tras el registro o descargar un anexo que acaba de ser generado.

El componente ConfirmDialogComponent está localizado en shared, ya que es compartido a toda la aplicación. Contiene un título, un mensaje y dos botones. Estos botones, "Sí" y "No", llaman a un método que cierra el diálogo y envían true y false, respectivamente:

close(respuesta: boolean) {
  this.dialogRef.close({ respuesta });
}

Este diálogo de confirmación se gestiona mediante la siguiente función del servicio DialogService:

async confirmacion(title: string, message: string) {
  let dialogRef = this.dialog.open(ConfirmDialogComponent, {
    data: { title, message },
    width: '400px',
  });
  return new Promise((resolve, reject) => {
    dialogRef.afterClosed().subscribe((res) => {
      resolve(res.respuesta);
    });
  })
    .then((respuesta) => {
      return respuesta;
    })
    .catch((err) => {
      return;
    });
}

Esta función asíncrona invoca un diálogo con título y mensaje que devuelve la respuesta del usuario (true o false). Esto nos permite hacer un await en su invocación, de forma que la ejecución del código no continúa hasta que el usuario contesta "Sí" o "No". Para invocar adecuadamente el modal, se debe seguir la siguiente estructura:

public async hacerAlgo() {
  let hacerlo = await this.dialogService.confirmacion(
    'Hacer algo',
    `¿Está seguro de que desea hacer algo?`
  );
  if (hacerlo) {
    // Hacer lo que se quiera
  }
}

Como último detalle, dado que el diálogo puede invocarse desde ventanas modales, hubo que asignarle un z-index mayor que el de cualquier modal, por lo que en _componentes.scss se añadió:

.cdk-overlay-container {
  z-index: 2000;
}

Suscripción a cambios en formularios

La función onChanges() en el componente del formulario, junto con la variable bandera modified, nos permite controlar si el usuario ha realizado cambios en el formulario. Esta función se inicializa en el onInit() del componente y está asociada al formulario.

onChanges(): void {
  this.datosEmpresa.valueChanges.subscribe((val) => {
    if (!this.modified) {
      this.modified = true;
    }
  });
}

Con esta variable bandera, podemos activar o desactivar el botón de submit, así como invocar el diálogo de confirmación.

Servicio auxiliar de fechas

El servicio de cliente DatesService tiene como objeto encapsular la gestión de fechas de la aplicación, principalmente la conversión entre los tipos Date y string. En sus métodos, utiliza la librería de Angular DatePipe. Consta de los siguientes métodos:

  • dateToString(fecha: Date): string. Convierte una fecha en string con formato 'yyyy-mm-dd'
  • stringToDate(fecha: string): Date. Convierte una fecha string en formato 'yyyy-MM-dd' en Date.
  • get now(): string. Devuelve la fecha de hoy en string.
  • calcFechaFin(fecha: Date | string): Date. Calcula la fecha de final del convenio, sumando cuatro años a la fecha que se le pase. Puede recibir un Date o un string, y devuelve siempre un Date

Servidor - API

Montar Zip

  • Hay varias funciones que montan Zip, vamos a hablar de ellas:

montarZipConCondicion

  • Esta función recibe los parametros que contienen , la ruta donde estan los archivos , el objeto zip y la ruta donde se depositará el zip
  • Primero se crea el zip y se abre
if ($zip->open(public_path($rutaZip), ZipArchive::CREATE)) {
} 
  • Se interceptan los archivos de la carpeta de la que se va a formar el zip
$files = File::files(public_path($rutaArchivo));
  • Se hace un foreach para recorrer los archivos
foreach ($files as $value) {
}
  • Se va interceptando el nombre de cada archivo en la variable $relativeNameZipFile
$relativeNameZipFile = basename($value);
  • Gracias a que interceptamos el nombre, comprobamos si este archivo existe en la base de datos
$existeAnexo = Anexo::where('ruta_anexo', 'like', "%$relativeNameZipFile%")->where('habilitado', '=', 1)->first();
if ($existeAnexo) {
 }
  • Si existe, lo añadimos al zip
$zip->addFile($value, $relativeNameZipFile);
  • Cuando esto termina, se cierra el zip
$zip->close();
  • Finalmente se retorna el Zip
return $rutaZip;

montarZip

  • Es igual que montarZipConCondicion , pero sin comprobar que el archivo existe en las carpetas, sirve por ejemplo, cuando se genera el Anexo 2 o 4, que se acaban de crear y por obligación existen

Existe Carpeta

  • Esta función comprueba si una carpeta existe, si esta no existe, la crea, lo unico que necesita recibir por parametro, es la ruta de la carpeta de la cual vamos a hacer la comprobación.
    public static function existeCarpeta($ruta)
    {
        if (!is_dir($ruta)) {
            mkdir($ruta, 0777, true);
        }
    }

Obtener curso académico

Función que devuelve el curso académico más próximo a la fecha actual. Si no existe en la base de datos un curso académico para el año actual, obtiene el más reciente.

public static function obtenerCursoAcademico() {[...]}

Obtener curso académico por año

Obtiene el id del curso académico según el año pasado por parámetro.

public static function obtenerCursoAcademicoPorAnio($anio) {[...]}

Guardar fichero

Función que guarda un fichero en base64 en la carpeta y con el nombre indicados por parámetros. Devuelve la ruta del fichero en caso de que se haya guardado correctamente, si no, devuelve false.

public static function guardarFichero($path, $nombreFichero, $fichero) {[...]}

Borrar fichero

Borra el fichero según la ruta indicada en el parámetro $path

public static function borrarFichero($path) {[...]}

Obtener URL del servidor

Devuelve la URL del server de ejecución actual de PHP

public static function obtenerURLServidor() {[...]}
⚠️ **GitHub.com Fallback** ⚠️