Exportar datos a Excel en Laravel: Guía completa con Maatwebsite
Introducción
Trabajar con Excel en aplicaciones web es una necesidad común en muchos proyectos Laravel. Desde reportes financieros hasta listados de usuarios, la capacidad de exportar datos en formato Excel es fundamental para cualquier aplicación empresarial.
El paquete Maatwebsite/Excel se ha convertido en el estándar de la comunidad Laravel para manejar importación y exportación de archivos Excel. Con más de 146 millones de descargas en Packagist, es la solución más confiable y ampliamente utilizada.
En este artículo aprenderás desde la instalación básica hasta técnicas avanzadas de exportación, incluyendo formateo personalizado, exportaciones dinámicas y optimizaciones de rendimiento para grandes volúmenes de datos.
Instalación y configuración de Maatwebsite/Excel
Instalación del paquete
El primer paso es instalar Maatwebsite/Excel a través de Composer:
composer require maatwebsite/excel
Laravel detectará automáticamente el service provider del paquete gracias a la auto-discovery de paquetes. Si necesitas registrarlo manualmente, añade esto a config/app.php:
'providers' => [
Maatwebsite\Excel\ExcelServiceProvider::class,
],
Publicar configuración
Para personalizar opciones de Excel, publica el archivo de configuración:
php artisan vendor:publish --provider="Maatwebsite\Excel\ExcelServiceProvider"
Esto creará config/excel.php donde podrás configurar:
return [
'exports' => [
'chunk_size' => 1000,
'pre_calculate_formulas' => true,
'csv' => [
'use_bom' => false,
],
],
'imports' => [
'read_only' => true,
'heading_row' => true,
],
];
Exportaciones básicas con Eloquent
Crear tu primera exportación
Crea una clase de exportación usando el comando Artisan:
php artisan make:export UsersExport
Esto genera el archivo app/Exports/UsersExport.php. Implementa la interfaz FromQuery para exportar modelos Eloquent:
<?php
namespace App\Exports;
use App\Models\User;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;
class UsersExport implements FromQuery, WithHeadings
{
public function query()
{
return User::query();
}
public function headings(): array
{
return ['ID', 'Nombre', 'Email', 'Creado'];
}
}
Descargar la exportación desde un controlador
En tu controlador, utiliza la clase Export de Maatwebsite:
<?php
namespace App\Http\Controllers;
use App\Exports\UsersExport;
use Maatwebsite\Excel\Facades\Excel;
class UserController extends Controller
{
public function export()
{
return Excel::download(new UsersExport(), 'usuarios.xlsx');
}
}
Añade la ruta en routes/web.php:
Route::get('/users/export', [UserController::class, 'export'])->name('users.export');
Exportaciones avanzadas con formateo
Personalizar estilos y formatos
Para aplicar estilos, implementa la interfaz WithStyles:
<?php
namespace App\Exports;
use App\Models\User;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithStyles;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use PhpOffice\PhpSpreadsheet\Style\Fill;
use PhpOffice\PhpSpreadsheet\Style\Font;
class UsersExport implements FromQuery, WithHeadings, WithStyles
{
public function query()
{
return User::query();
}
public function headings(): array
{
return ['ID', 'Nombre', 'Email', 'Fecha de Creación'];
}
public function styles(Worksheet $sheet)
{
return [
1 => [
'font' => [
'bold' => true,
'color' => ['rgb' => 'FFFFFF'],
'size' => 12,
],
'fill' => [
'fillType' => Fill::FILL_SOLID,
'startColor' => ['rgb' => '4472C4'],
],
'alignment' => [
'horizontal' => 'center',
'vertical' => 'center',
],
],
];
}
}
Mapear propiedades de modelos
A menudo necesitas transformar datos antes de exportarlos. Implementa WithMapping:
<?php
namespace App\Exports;
use App\Models\User;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithMapping;
class UsersExport implements FromQuery, WithHeadings, WithMapping
{
public function query()
{
return User::query();
}
public function headings(): array
{
return ['ID', 'Nombre Completo', 'Email', 'Estado', 'Creado'];
}
public function map($user): array
{
return [
$user->id,
strtoupper($user->name),
$user->email,
$user->is_active ? 'Activo' : 'Inactivo',
$user->created_at->format('d/m/Y'),
];
}
}
Exportaciones dinámicas y filtradas
Exportar datos con filtros
Frecuentemente necesitas exportar datos filtrados. Pasa parámetros al constructor:
<?php
namespace App\Exports;
use App\Models\User;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithMapping;
class UsersExport implements FromQuery, WithHeadings, WithMapping
{
protected $status;
protected $dateFrom;
public function __construct($status = null, $dateFrom = null)
{
$this->status = $status;
$this->dateFrom = $dateFrom;
}
public function query()
{
$query = User::query();
if ($this->status) {
$query->where('status', $this->status);
}
if ($this->dateFrom) {
$query->where('created_at', '>=', $this->dateFrom);
}
return $query;
}
public function headings(): array
{
return ['ID', 'Nombre', 'Email', 'Estado', 'Creado'];
}
public function map($user): array
{
return [
$user->id,
$user->name,
$user->email,
$user->status,
$user->created_at->format('d/m/Y H:i'),
];
}
}
En el controlador:
public function export(Request $request)
{
$export = new UsersExport(
$request->input('status'),
$request->input('date_from')
);
return Excel::download($export, 'usuarios.xlsx');
}
Exportaciones masivas y optimización
Chunking para grandes volúmenes
Maatwebsite/Excel procesa datos en chunks por defecto (1000 registros). Para optimizar la memoria en exportaciones grandes, modifica config/excel.php:
'exports' => [
'chunk_size' => 5000, // Aumenta según tu servidor
],
Exportar múltiples hojas
Crea exportaciones con varias hojas usando WithMultipleSheets:
<?php
namespace App\Exports;
use App\Models\User;
use App\Models\Order;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\WithMultipleSheets;
class ComprehensiveExport implements WithMultipleSheets
{
use Exportable;
public function sheets(): array
{
return [
'Usuarios' => new UsersSheet(),
'Pedidos' => new OrdersSheet(),
];
}
}
Define cada hoja como una clase separada:
<?php
namespace App\Exports\Sheets;
use App\Models\User;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;
class UsersSheet implements FromQuery, WithHeadings
{
public function query()
{
return User::query();
}
public function headings(): array
{
return ['ID', 'Nombre', 'Email'];
}
}
Limitar columnas y filas
Para exportaciones muy grandes, selecciona solo las columnas necesarias:
public function query()
{
return User::query()
->select('id', 'name', 'email', 'status')
->where('deleted_at', null)
->with('profile:id,user_id,phone');
}
Casos de uso avanzados
Exportar con fórmulas y cálculos
Maatwebsite integra PhpSpreadsheet, permitiendo agregar fórmulas:
<?php
namespace App\Exports;
use Maatwebsite\Excel\Concerns\FromArray;
use Maatwebsite\Excel\Concerns\WithHeadings;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
class SalesExport implements FromArray, WithHeadings
{
public function array(): array
{
return [
['Producto', 'Cantidad', 'Precio', 'Total'],
['Laptop', 5, 1000, '=B2*C2'],
['Mouse', 20, 25, '=B3*C3'],
['Teclado', 10, 75, '=B4*C4'],
];
}
public function headings(): array
{
return ['Producto', 'Cantidad', 'Precio', 'Total'];
}
}
Exportar con imágenes
Para incluir imágenes en la exportación, necesitas procesar manualmente:
<?php
namespace App\Exports;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithDrawings;
use PhpOffice\PhpSpreadsheet\Worksheet\Drawing;
class ProductsExport implements FromCollection, WithDrawings
{
public function collection()
{
// Retorna datos de productos
}
public function drawings()
{
$drawing = new Drawing();
$drawing->setName('Logo');
$drawing->setDescription('Mi Logo');
$drawing->setPath(public_path('images/logo.png'));
$drawing->setHeight(100);
$drawing->setCoordinates('A1');
return [$drawing];
}
}
Monitorear progreso de exportación
Para exportaciones muy largas, proporciona feedback al usuario:
<?php
namespace App\Exports;
use App\Models\User;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Events\BeforeExport;
use Maatwebsite\Excel\Events\AfterSheet;
class UsersExport implements FromQuery, WithHeadings, WithEvents
{
private $progress = 0;
public function query()
{
return User::query();
}
public function headings(): array
{
return ['ID', 'Nombre', 'Email'];
}
public function registerEvents(): array
{
return [
BeforeExport::class => function(BeforeExport $event) {
// Lógica antes de iniciar
},
AfterSheet::class => function(AfterSheet $event) {
// Lógica después de completar
},
];
}
}
Buenas prácticas de rendimiento
1. Selecciona solo columnas necesarias
public function query()
{
return User::query()
->select('id', 'name', 'email') // No selecciones todo
->with('profile:id,user_id,phone');
}
2. Usa paginación para datos enormes
public function query()
{
return User::query()
->where('status', 'active')
->limit(50000); // Limita registros
}
3. Cachea exportaciones
public function export()
{
$cacheKey = 'export_users_' . auth()->id();
if (Cache::has($cacheKey)) {
return Cache::get($cacheKey);
}
$export = Excel::download(new UsersExport(), 'usuarios.xlsx');
Cache::put($cacheKey, $export, now()->addHour());
return $export;
}
4. Ejecuta exportaciones en colas
Para exportaciones masivas, procesa en background:
<?php
namespace App\Jobs;
use App\Exports\UsersExport;
use Maatwebsite\Excel\Facades\Excel;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
class ExportUsersJob implements ShouldQueue
{
use Queueable, SerializesModels;
public function handle()
{
Excel::store(new UsersExport(), 'exports/usuarios.xlsx');
// Notifica al usuario que la exportación está lista
}
}
Conclusión
Maatwebsite/Excel es una herramienta poderosa que simplifica dramáticamente el manejo de archivos Excel en Laravel. Desde exportaciones básicas hasta casos de uso complejos con múltiples hojas, formateo avanzado y optimizaciones de rendimiento, el paquete proporciona todas las herramientas necesarias.
La clave para implementaciones exitosas es entender tus necesidades específicas: si exportas pocos registros, una exportación simple es suficiente; pero para datos masivos, implementa chunking, colas y cacheo. Siempre considera el rendimiento y la experiencia del usuario.
Con los ejemplos y técnicas proporcionadas en este artículo, estarás preparado para implementar exportaciones robustas en tus aplicaciones Laravel.
Puntos clave
- Instalación simple:
composer require maatwebsite/excelcon auto-discovery automático - FromQuery es ideal: Exporta directamente desde consultas Eloquent sin cargar todo en memoria
- WithMapping permite transformaciones: Personaliza datos antes de exportar (mayúsculas,