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:
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.