Recently popular package Laravel-Excel released a new version 3.0, which was a pretty radical change from previous versions. I needed to do a simple Excel export and noticed that their documentation covers only export from Laravel Collections but not from some custom structure. So I will show you a "workaround".
First, this is how documentation describes the basic workflow:
namespace App\Exports; use Maatwebsite\Excel\Concerns\FromCollection; class InvoicesExport implements FromCollection { public function collection() { return Invoice::all(); } }
You need to create a separate class for export (similar how Laravel Notifications work) and you can define a collection to export.
There are also other ways to export the data:
From Eloquent query:
class InvoicesExport implements FromQuery { use Exportable; public function query() { return Invoice::query(); } }
Or, from View HTML table:
class InvoicesExport implements FromView { public function view(): View { return view('exports.invoices', [ 'invoices' => Invoice::all() ]); } }
But still, the problem is that all examples are based on Eloquent. What if I need Excel from some custom structure like array?
Imagine that I have this array:
[ [ 'name' => 'Povilas', 'surname' => 'Korop', 'email' => 'povilas@laraveldaily.com', 'twitter' => '@povilaskorop' ], [ 'name' => 'Taylor', 'surname' => 'Otwell', 'email' => 'taylor@laravel.com', 'twitter' => '@taylorotwell' ] ]
How do I export that into Excel, so that keys would be columns, and values would be rows?
There are two ways.
Option 1. Turn your Array into a Collection and add Headings
This is how the Export class would look:
namespace App\Exports; use Maatwebsite\Excel\Concerns\FromCollection; use Maatwebsite\Excel\Concerns\Exportable; use Maatwebsite\Excel\Concerns\WithHeadings; class CollectionExport implements FromCollection, WithHeadings { use Exportable; public function collection() { return collect([ [ 'name' => 'Povilas', 'surname' => 'Korop', 'email' => 'povilas@laraveldaily.com', 'twitter' => '@povilaskorop' ], [ 'name' => 'Taylor', 'surname' => 'Otwell', 'email' => 'taylor@laravel.com', 'twitter' => '@taylorotwell' ] ]); } public function headings(): array { return [ 'Name', 'Surname', 'Email', 'Twitter', ]; } }
You need to implement collection() method by using Laravel's collect() method and passing array to it. Also, you need to implement headings() to add a header row.
Finally, in Controller you will have this row at the end of the method:
return Excel::download(new CollectionExport(), 'export.xlsx');
Then you would have this as downloaded result:
Option 2. Pass Array into View
Alternatively, you can build this resources/views/exports/xml.blade.php:
<table>
<thead>
<tr>
@foreach($data[0] as $key => $value)
<th>{{ ucfirst($key) }}</th>
@endforeach
</tr>
</thead>
<tbody>
@foreach($data as $row)
<tr>
@foreach ($row as $value)
<td>{{ $value }}</td>
@endforeach
</tr>
@endforeach
</tbody>
</table>
And then have this in your Export class:
namespace App\Exports; use Illuminate\Contracts\View\View; use Maatwebsite\Excel\Concerns\FromView; class BladeExport implements FromView { public function view(): View { return view('exports.xml', [ 'data' => [ [ 'name' => 'Povilas', 'surname' => 'Korop', 'email' => 'povilas@laraveldaily.com', 'twitter' => '@povilaskorop' ], [ 'name' => 'Taylor', 'surname' => 'Otwell', 'email' => 'taylor@laravel.com', 'twitter' => '@taylorotwell' ] ] ]); } }
Controller stays the same, just different class name:
return Excel::download(new BladeExport(), 'export.xlsx');
Wait, but how to pass data into Export class?
Both of our examples have one flaw - the data is formed in the class itself. Actually, it shouldn't even know about the data, it should accept it as a parameter. But how do we do that, if view() or collection() methods have no parameters?
We will pass it through __construct() method into a private variable. You could call it a dependency injection, although there are much better examples of dependency injection, look it up on Google.
class BladeExport implements FromView { private $data; public function __construct($data) { $this->data = $data; } public function view(): View { return view('exports.xml', [ 'data' => $this->data ]); } }
So we're accepting $data as a parameter now. Then, in our Controller we can have this:
$data = [ [ 'name' => 'Povilas', 'surname' => 'Korop', 'email' => 'povilas@laraveldaily.com', 'twitter' => '@povilaskorop' ], [ 'name' => 'Taylor', 'surname' => 'Otwell', 'email' => 'taylor@laravel.com', 'twitter' => '@taylorotwell' ] ]; return Excel::download(new BladeExport($data), 'export.xlsx');
I hope that's helpful. Check out other examples in official documentation of the package.
No comments or questions yet...