Archivo de Excel creado con Laravel, PHP y PhpSpreadsheet

Laravel: crear archivo de Excel

En este post veremos cómo crear un archivo de Excel usando Laravel. Verás que es realmente sencillo.

Te pondré un ejemplo simple y a partir del mismo podrás crear hojas de cálculo usando los modelos de Laravel que se conectan a la base de datos o trayendo el contenido desde cualquier lugar.

Vamos a usar PhpSpreadsheet del cual ya existe un post con PHP puro, pero ahora veremos cómo usar PhpSpreadsheet con Laravel.

Instalando PhpSpreadsheet en Laravel

Laravel utiliza composer como gestor de dependencias, así que no importa si tienes un proyecto nuevo o existente, la dependencia se instala con:

composer require phpoffice/phpspreadsheet

Quiero mencionar que a mí me arrojó un error, si en tu caso la instalación fue correcta desde el inicio entonces pasa al siguiente apartado.

A mí me apareció lo que aparece abajo, documentado ya en el siguiente enlace: https://github.com/PHPOffice/PhpSpreadsheet/issues/2790:

Problem 1
– phpoffice/phpspreadsheet[1.24.0, …, 1.24.1] require psr/simple-cache ^1.0 || ^2.0 -> found psr/simple-cache[1.0.0, 1.0.1, 2.0.0, 2.x-dev] but the package is fixed to 3.0.0 (lock file version) by a partial update and that version does not match. Make sure you list it as an argument for the update command.
– Root composer.json requires phpoffice/phpspreadsheet ^1.24 -> satisfiable by phpoffice/phpspreadsheet[1.24.0, 1.24.1].

Use the option –with-all-dependencies (-W) to allow upgrades, downgrades and removals for packages currently locked to specific versions.

Installation failed, reverting ./composer.json and ./composer.lock to their original content.

Entonces hice un:

composer require phpoffice/phpspreadsheet --with-all-dependencies

Y con eso funcionó. Obviamente si a ti te sale otro error hay que buscar la solución en Google y listo.

Ejemplo de Excel con Laravel

Voy a mostrarte algo sencillo, pues lo “complejo” es usar la librería desde Laravel, una vez que tengas una muestra entonces podrás hacer varias cosas partiendo desde lo más simple.

Comenzamos “importando” las clases:

<?php
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\IOFactory;

En este caso solo voy a guardar un arreglo dentro de un archivo de Excel que se descargará automáticamente al visitar una ruta de Laravel.

Más adelante puedes mover el código a un controlador o cosas similares:

<?php
Route::get("/excel", function () {
    $documento = new Spreadsheet();
    $documento
        ->getProperties()
        ->setCreator("Aquí va el creador, como cadena")
        ->setLastModifiedBy('Parzibyte') // última vez modificado por
        ->setTitle('Mi primer documento creado con PhpSpreadSheet')
        ->setSubject('El asunto')
        ->setDescription('Este documento fue generado para parzibyte.me')
        ->setKeywords('etiquetas o palabras clave separadas por espacios')
        ->setCategory('La categoría');
    $hoja = $documento->getActiveSheet();
    $hoja->setTitle("Productos");
    $encabezado = ["Código", "Descripción",];

    $hoja->fromArray($encabezado, null, 'A1');
    $fila = 2;
    $productos = [
        [
            "codigo" => "123",
            "descripcion" => "Nintendo 3DS"
        ],
        [
            "codigo" => "456",
            "descripcion" => "Alcohol isopropílico"
        ],
        [
            "codigo" => "1",
            "descripcion" => "Mouse"
        ],
    ];
    foreach ($productos as $producto) {
        $columna = 1;
        $hoja->setCellValueByColumnAndRow($columna, $fila, $producto["codigo"]);
        $columna++;
        $hoja->setCellValueByColumnAndRow($columna, $fila, $producto["descripcion"]);
        $fila++;
    }

    $nombreDelDocumento = "Productos.xlsx";
    header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
    header('Content-Disposition: attachment;filename="' . $nombreDelDocumento . '"');
    header('Cache-Control: max-age=0');
    $writer = IOFactory::createWriter($documento, 'Xlsx');
    $writer->save('php://output');
});

Primero creamos el documento con sus propiedades, luego obtenemos la referencia a la hoja y colocamos el encabezado usando fromArray.

Lo hago de esta forma para mostrarte que se puede usar fromArray o con setCellValueByColumnAndRow como se indica en el ciclo que escribe los productos.

Obviamente hay más métodos y cosas que puedes hacer en las celdas y hojas del libro de Excel creado con Laravel, y también puedes guardarlo en el almacenamiento o incluso enviarlo por correo.

Yo lo estoy mandando en el navegador para que se descargue al usuario. Y al abrirlo (visitando /excel en el navegador) se ve lo siguiente:

Archivo de Excel creado con Laravel, PHP y PhpSpreadsheet
Archivo de Excel creado con Laravel, PHP y PhpSpreadsheet

Conclusión

El archivo web.php quedó así completamente:

<?php

use Illuminate\Support\Facades\Route;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\IOFactory;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', function () {
    return view('welcome');
});


Route::get("/excel", function () {
    $documento = new Spreadsheet();
    $documento
        ->getProperties()
        ->setCreator("Aquí va el creador, como cadena")
        ->setLastModifiedBy('Parzibyte') // última vez modificado por
        ->setTitle('Mi primer documento creado con PhpSpreadSheet')
        ->setSubject('El asunto')
        ->setDescription('Este documento fue generado para parzibyte.me')
        ->setKeywords('etiquetas o palabras clave separadas por espacios')
        ->setCategory('La categoría');
    $hoja = $documento->getActiveSheet();
    $hoja->setTitle("Productos");
    $encabezado = ["Código", "Descripción",];

    $hoja->fromArray($encabezado, null, 'A1');
    $fila = 2;
    $productos = [
        [
            "codigo" => "123",
            "descripcion" => "Nintendo 3DS"
        ],
        [
            "codigo" => "456",
            "descripcion" => "Alcohol isopropílico"
        ],
        [
            "codigo" => "1",
            "descripcion" => "Mouse"
        ],
    ];
    foreach ($productos as $producto) {
        $columna = 1;
        $hoja->setCellValueByColumnAndRow($columna, $fila, $producto["codigo"]);
        $columna++;
        $hoja->setCellValueByColumnAndRow($columna, $fila, $producto["descripcion"]);
        $fila++;
    }

    $nombreDelDocumento = "Productos.xlsx";
    header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
    header('Content-Disposition: attachment;filename="' . $nombreDelDocumento . '"');
    header('Cache-Control: max-age=0');
    $writer = IOFactory::createWriter($documento, 'Xlsx');
    $writer->save('php://output');
});

Y si quieres ver otro ejemplo más complejo con consultas, condicionales y cosas de esas aquí lo dejo:

<?php

$tipoReporte = $request->input("tipoReporte");
$columnas = ["cancion_solicitadas.id_cancion", "cancions.nombre", "cancions.interprete"];
$estacionesLocales = [];
$estacionesCompetencia = [];
$idsEstacionesLocales = [];
$idsEstacionesCompetencia = [];
$canales = [];
$conGenero = $request->has("incluirGenero");
$fechaInicio = $request->input("fechaInicio");
$fechaFin = $request->input("fechaFin");
$conBusqueda = $request->has("busqueda");

if ($request->has("estacionesLocalesSeleccionadas")) {
    $idsEstacionesLocales = $request->input("estacionesLocalesSeleccionadas");
    $estacionesLocales = Estacion::whereIn("id", $request->input("estacionesLocalesSeleccionadas"))->get();
}
if ($request->has("estacionesCompetenciaSeleccionadas")) {
    $idsEstacionesCompetencia = $request->input("estacionesCompetenciaSeleccionadas");
    $estacionesCompetencia = Estacion::whereIn("id", $request->input("estacionesCompetenciaSeleccionadas"))->get();
}
$idsEstacionesSeleccionadas = array_merge($idsEstacionesLocales, $idsEstacionesCompetencia);
if ($request->has("tipoPeticion")) {
    $canales = $request->input("tipoPeticion");
}
$builder = CancionSolicitada::join("cancions", "cancions.id", "=", "cancion_solicitadas.id_cancion")
    ->where("cancion_solicitadas.fecha", ">=", $fechaInicio)
    ->where("cancion_solicitadas.fecha", "<=", $fechaFin)
    ->groupBy("cancions.nombre")
    ->groupBy("cancions.interprete")
    ->groupBy("cancion_solicitadas.id_cancion");
if ($conGenero) {
    $builder->join("generos", "generos.id", "=", "cancions.id_genero");
    array_push($columnas, "generos.nombre as genero");
    $builder->groupBy("generos.nombre");
}
if ($conBusqueda) {
    $busqueda = $request->input("busqueda");
    $builder->where(function ($query) use ($busqueda) {
        $query->where("cancions.nombre", "LIKE", "%$busqueda%")
            ->orWhere("cancions.interprete", "LIKE", "%$busqueda%");
    });
}
$builder->select($columnas);
$canciones = $builder->get();
$documento = new Spreadsheet();
$documento
    ->getProperties()
    ->setCreator("Aquí va el creador, como cadena")
    ->setLastModifiedBy('Parzibyte') // última vez modificado por
    ->setTitle('Mi primer documento creado con PhpSpreadSheet')
    ->setSubject('El asunto')
    ->setDescription('Este documento fue generado para parzibyte.me')
    ->setKeywords('etiquetas o palabras clave separadas por espacios')
    ->setCategory('La categoría');
$hoja = $documento->getActiveSheet();
$hoja->setTitle("Productos");

$encabezado = ["Canción", "Intérprete"];
if ($conGenero) {
    array_push($encabezado, "Género");
}
foreach ($canales as $canal) {
    array_push($encabezado, "Total " . $canal);
}
foreach ($estacionesLocales as $estacion) {
    array_push($encabezado, $estacion->nombre);
}
foreach ($estacionesCompetencia as $estacion) {
    array_push($encabezado, $estacion->nombre);
}
array_push($encabezado, "Total peticiones");
$hoja->fromArray($encabezado, null, 'A1');
$fila = 2;
foreach ($canciones as $cancion) {
    $columna = 1;
    $hoja->setCellValueByColumnAndRow($columna, $fila, $cancion->nombre);
    $columna++;
    $hoja->setCellValueByColumnAndRow($columna, $fila, $cancion->interprete);
    $columna++;
    if ($conGenero) {
        $hoja->setCellValueByColumnAndRow($columna, $fila, $cancion->genero);
        $columna++;
    }
    foreach ($canales as $canal) {
        $hoja->setCellValueByColumnAndRow($columna, $fila, $cancion->totalPorCanal($fechaInicio, $fechaFin, $canal, $idsEstacionesSeleccionadas));
        $columna++;
    }
    foreach ($estacionesLocales as $estacion) {
        $hoja->setCellValueByColumnAndRow($columna, $fila, $cancion->totalPorEstacion($fechaInicio, $fechaFin, $estacion->id));
        $columna++;
    }
    foreach ($estacionesCompetencia as $estacion) {
        $hoja->setCellValueByColumnAndRow($columna, $fila, $cancion->totalPorEstacion($fechaInicio, $fechaFin, $estacion->id));
        $columna++;
    }
    $hoja->setCellValueByColumnAndRow($columna, $fila, $cancion->totalPeticiones($fechaInicio, $fechaFin, $idsEstacionesSeleccionadas));
    $fila++;
}

$nombreDelDocumento = "Reporte.xlsx";
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename="' . $nombreDelDocumento . '"');
header('Cache-Control: max-age=0');
$writer = IOFactory::createWriter($documento, 'Xlsx');
$writer->save('php://output');

Como te dije, aquí lo que te quería mostrar es cómo unir PhpSpreadsheet y Laravel, ya que en mi blog tengo otros tutoriales de, por ejemplo, cómo exportar una base de datos a Excel, leer una hoja de cálculo o guardarla en el disco duro.

Por aquí te dejo más tutoriales de Laravel y PHP en mi blog.

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.

Dejar un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *