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.

Like our articles?
Check out our Laravel online courses!

11 COMMENTS

  1. Very smart notices and hints as we had expected with your Laravel’s articles. However, there is any mention for very large models. i.e suppose a model with more than 2 million records!

  2. Hi, how are you? If you want to add color to the xls cells using xml.blade.php?

    this does not work: NAME or NAME

    any ideas?

  3. How to get values from a dependent table instead of id?

    table BUGS
    ‘id’ = 1
    ‘user_id’ = 2
    ‘message’ = text
    ‘created_at’ = 20.10.2018
    ‘updated_at’ = 20.10.2018

    table USERS
    id’ = 1
    ‘name’ = Ivan
    ‘created_at’ = 20.10.2018
    ‘updated_at’ = 20.10.2018

    export BUGS table, must be:
    ‘id’ = 1
    ‘user_id’ = Ivan
    ‘message’ = text
    ‘created_at’ = 20.10.2018
    ‘updated_at’ = 20.10.2018

    thank….

    • Solved this question.
      Change collection function map ()

      public function collection()
      {
      $bugs = Bug::all();

      return $array = $bugs->map(function ($b, $key) {

      return [
      ‘id’ => $b->id,
      ‘user_id’ => $b->user->name,
      ‘created_at’ => $b->created_at,
      ‘updated_at’ => $b->updated_at,
      ];
      });

LEAVE A REPLY

Please enter your comment!
Please enter your name here