Criando um Serviço de Exportação de Arquivos em XML, XLSX, CSV e PDF no Laravel 11

Bruno Oliveira
5 min readJun 14, 2024

--

Neste artigo, vamos mostrar como criar um serviço de exportação de arquivos nos formatos XML, XLSX, CSV e PDF utilizando o framework Laravel. Utilizaremos as melhores práticas e pacotes mais atuais para garantir uma solução robusta e eficiente.

Estrutura do Projeto

Para manter nosso código organizado e flexível, usaremos o padrão Strategy. Este padrão nos permite definir uma família de algoritmos, encapsulá-los e torná-los intercambiáveis. Vamos começar criando a interface ExportStrategy e suas implementações para cada formato de exportação.

Passo 1: Instalar Dependências

Vamos instalar os pacotes necessários para lidar com os diferentes formatos de exportação:

composer require maatwebsite/excel
composer require barryvdh/laravel-dompdf
composer require spatie/array-to-xml

Passo 2: Publicar o Arquivo de Configuração do Maatwebsite Excel

Primeiro, precisamos publicar o arquivo de configuração do pacote Maatwebsite Excel:

php artisan vendor:publish --provider="Maatwebsite\Excel\ExcelServiceProvider" --tag=config

Passo 3: Configurar o Delimitador CSV

Abra o arquivo config/excel.php e configure o delimitador CSV para ponto e vírgula (;):

config/excel.php

<?php

return [

'exports' => [

'csv' => [
'delimiter' => ';', // Configurando o delimitador para ponto e vírgula
'enclosure' => '"',
'line_ending' => "\r\n",
'use_bom' => true,
'include_separator_line' => false,
'excel_compatibility' => false,
'output_encoding' => '',
'test_auto_detect' => true,
],

// Outras configurações...
],

// Outras configurações...

];

Passo 4: Implementar a Interface ExportStrategy

Vamos criar a interface ExportStrategy que define o método export.

app/Services/Export/Contracts/ExportStrategy.php

<?php

namespace App\Services\Export\Contracts;

interface ExportStrategy
{
public function export(array $data, string $filename): string;
}

Passo 5: Implementar as Classes de Exportação

app/Services/Export/ExportToXlsx.php

<?php

namespace App\Services\Export;

use App\Exports\GenericExport;
use App\Services\Export\Contracts\ExportStrategy;
use Illuminate\Support\Facades\Storage;
use Maatwebsite\Excel\Facades\Excel;

class ExportToXlsx implements ExportStrategy
{
public function export(array $data, string $filename = 'export.xlsx'): string
{
Excel::store(new GenericExport($data), $filename, 'public', \Maatwebsite\Excel\Excel::XLSX);
return Storage::url($filename);
}
}

app/Services/Export/ExportToCsv.php

<?php

namespace App\Services\Export;

use App\Exports\GenericExport;
use App\Services\Export\Contracts\ExportStrategy;
use Illuminate\Support\Facades\Storage;
use Maatwebsite\Excel\Facades\Excel;

class ExportToCsv implements ExportStrategy
{
public function export(array $data, string $filename = 'export.csv'): string
{
Excel::store(new GenericExport($data), $filename, 'public', \Maatwebsite\Excel\Excel::CSV);
return Storage::url($filename);
}
}

app/Services/Export/ExportToPdf.php

<?php

namespace App\Services\Export;

use App\Services\Export\Contracts\ExportStrategy;
use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Support\Facades\Storage;

class ExportToPdf implements ExportStrategy
{
public function export(array $data, string $filename = 'export.pdf'): string
{
$pdf = Pdf::loadView('exports.pdf', compact('data'));

Storage::put("public/{$filename}", $pdf->output());

return Storage::url($filename);
}
}

app/Services/Export/ExportToXml.php

<?php

namespace App\Services\Export;

use App\Services\Export\Contracts\ExportStrategy;
use Illuminate\Support\Facades\Storage;
use Spatie\ArrayToXml\ArrayToXml;

class ExportToXml implements ExportStrategy
{
public function export(array $data, string $filename = 'export.xml'): string
{
$xml = ArrayToXml::convert(['item' => $data]);

if (! Storage::put("public/{$filename}", $xml)) {
throw new \Exception("Failed to save XML file");
}

return Storage::url($filename);
}
}

Passo 6: Criar a Classe de Exportação Genérica

Vamos criar uma classe genérica que implementa a interface FromArray do pacote Maatwebsite Excel.

app/Exports/GenericExport.php

<?php

namespace App\Exports;

use Maatwebsite\Excel\Concerns\{ FromArray, WithHeadings };

class GenericExport implements FromArray, WithHeadings
{
public function __construct(protected array $data, protected array $headers = [])
{
}

public function headings(): array
{
return $this->headers;
}

public function array(): array
{
return $this->data;
}
}

Passo 7: Criar o Service Provider Personalizado

Vamos criar um Service Provider para registrar nossas estratégias de exportação.

app/Providers/ExportServiceProvider.php

<?php

namespace App\Providers;

use App\Services\Export\Contracts\ExportStrategy;
use Illuminate\Support\ServiceProvider;
use App\Services\Export\{
ExportToCsv,
ExportToPdf,
ExportToXlsx,
ExportToXml
};

class ExportServiceProvider extends ServiceProvider
{
public $bindings = [
ExportStrategy::class => ExportToCsv::class,
ExportStrategy::class => ExportToPdf::class,
ExportStrategy::class => ExportToXlsx::class,
ExportStrategy::class => ExportToXml::class,
];

public function register(): void
{
//
}

public function boot(): void
{
//
}
}

Passo 8: Registrar o Service Provider

Abra o arquivo bootstrap/providers.php e adicione o ExportServiceProvider à lista de providers.

bootstrap/providers.php

<?php

return [
// Outros providers
App\Providers\ExportServiceProvider::class,
];

Passo 9: Criar o Serviço de Exportação

app/Services/ExportService.php

<?php

namespace App\Services;

use App\Services\Export\Contracts\ExportStrategy;

class ExportService
{
public function __construct(protected ExportStrategy $strategy)
{
}

public function setStrategy(ExportStrategy $strategy)
{
$this->strategy = $strategy;
}

public function export(array $data, string $filename): string
{
if (!$this->strategy) {
throw new \Exception("Formato de exportação não definido");
}

return $this->strategy->export($data, $filename);
}
}

Passo 10: Criar o Controller

app/Http/Controllers/ExportController.php

<?php

namespace App\Http\Controllers;

use App\Services\ExportService;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Log;

class ExportController extends Controller
{
public function __construct(protected ExportService $exportService)
{
}

public function export(Request $request)
{
$data = [
['Nome' => 'João', 'Idade' => 25, 'Email' => 'joao@example.com'],
['Nome' => 'Maria', 'Idade' => 30, 'Email' => 'maria@example.com'],
['Nome' => 'José', 'Idade' => 35, 'Email' => 'jose@example.com'],
];

$format = $request->input('format', 'xlsx');
$strategies = config('export.strategies');

try {
if (!array_key_exists($format, $strategies)) {
throw new \InvalidArgumentException('Formato não suportado', Response::HTTP_BAD_REQUEST);
}

$strategy = $strategies[$format];
$this->exportService->setStrategy(new $strategy());

$filename = sprintf('%s.%s', 'export', $format);
$url = $this->exportService->export($data, $filename);
return response()->json(['url' => $url]);
} catch (\InvalidArgumentException $e) {
Log::error('Invalid Argument Exception', [
'code' => $e->getCode(),
'message' => $e->getMessage(),
'trace' => $e->getTrace(),
]);

return response()->json(['error' => $e->getMessage()], $e->getCode());
} catch (\Throwable $e) {
Log::error('Internal Server Error', [
'code' => $e->getCode(),
'message' => $e->getMessage(),
'trace' => $e->getTrace(),
]);

return response()->json(['error' => 'Internal Server Error'], Response::HTTP_INTERNAL_SERVER_ERROR);
}
}
}

Passo 11: Configurar a Rota

routes/web.php

<?php

use App\Http\Controllers\ExportController;

Route::get('export', [ExportController::class, 'export']);

Passo 12: Criar a View para PDF

resources/views/exports/pdf.blade.php

<!DOCTYPE html>
<html>
<head>
<title>Exportação PDF</title>
<style>
table {
width: 100%;
border-collapse: collapse;
}
table, th, td {
border: 1px solid black;
}
th, td {
padding: 8px;
text-align: left;
}
</style>
</head>
<body>
<h1>Export PDF</h1>
<table>
<thead>
<tr>
@if(isset($headers) && is_array($headers))
@foreach($headers as $header)
<th>{{ $header }}</th>
@endforeach
@else
@foreach(array_keys($data[0]) as $header)
<th>{{ $header }}</th>
@endforeach
@endif
</tr>
</thead>
<tbody>
@foreach($data as $row)
<tr>
@foreach($row as $cell)
<td>{{ $cell }}</td>
@endforeach
</tr>
@endforeach
</tbody>
</table>
</body>
</html>

Passo 13: Criar Link Simbólico para o Storage

Para garantir que os arquivos exportados sejam acessíveis publicamente, precisamos criar um link simbólico do diretório de storage público. Execute o comando abaixo no terminal:

php artisan storage:link

Este comando cria um link simbólico do diretório storage/app/public para o diretório public/storage, permitindo que os arquivos armazenados em storage/app/public sejam acessíveis a partir da web.

Conclusão

Seguindo essas etapas, você criou um serviço de exportação de arquivos em diferentes formatos no Laravel utilizando o padrão Strategy. Esta abordagem permite adicionar novos formatos de exportação de forma fácil e organizada, mantendo o código limpo e sustentável. Com o arquivo de configuração config/excel.php, configuramos o delimitador CSV para ponto e vírgula, centralizando a configuração e simplificando o código das classes de exportação. Além disso, criamos um link simbólico para garantir que os arquivos exportados sejam acessíveis publicamente. Você pode ver o código completo no GitHub em https://github.com/bholiveiradev/laravel-export-service

--

--

Bruno Oliveira
Bruno Oliveira

Written by Bruno Oliveira

0 Followers

Desenvolvedor Full Stack com experiência em todo o ciclo de desenvolvimento, especializado em PHP (Laravel, Codeigniter), Vue.js e arquitetura de software.

No responses yet