Black Friday: coupon FRIDAY24 for 40% off Yearly/Lifetime membership! Read more here

Laravel-Excel 3.0: Export Custom Array into Excel

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:

laravel excel 3.0 export

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

Like our articles?

Become a Premium Member for $129/year or $29/month
What else you will get:
  • 67 courses (1172 lessons, total 43 h 18 min)
  • 90 long-form tutorials (one new every week)
  • access to project repositories
  • access to private Discord

Recent New Courses