## 1. Project Overview & Quickstart (SpartnerNL/Laravel-Excel)

## 1. Project Overview & Quickstart (SpartnerNL/Laravel-Excel)

## 1. Project Overview & Quickstart (SpartnerNL/Laravel-Excel)

# Technical Documentation: SpartnerNL/Laravel-Excel

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/SpartnerNL/Laravel-Excel)

### Overview (`README.md`)

<br />
<br />
<p align="center">
  
<img width="589" src="https://user-images.githubusercontent.com/7728097/143205384-af3c73a8-0253-45f3-b5ac-28a335dddb87.png" alt="Laravel Excel logo">
</p>
<br />


<h3 align="center">Supercharged Excel exports and imports</h3>

  <p align="center">
  A simple, but elegant <a href="https://laravel.com" target="_blank">Laravel<a/> wrapper around <a href="https://phpspreadsheet.readthedocs.io/" target="_blank">PhpSpreadsheet</a>
exports and imports.
</p>

<h4 align="center">
  <a href="https://docs.laravel-excel.com/3.1/exports/">Quickstart</a>
  <span> · </span>
  <a href="https://docs.laravel-excel.com/3.1/getting-started/">Documentation</a>
  <span> · </span>
  <a href="https://course.laravel-excel.com">Video Course</a>
  <span> · </span>
  <a href="https://github.com/SpartnerNL/Laravel-Nova-Excel">Nova</a>
  <span> · </span>
  <a href="https://medium.com/maatwebsite/laravel-excel/home">Blog</a>
  <span> · </span>
  <a href="https://docs.laravel-excel.com/3.1/getting-started/contributing.html">Contributing</a>
  <span> · </span>
  <a href="https://docs.laravel-excel.com/3.1/getting-started/support.html">Support</a>
</h4>

<p align="center">
  <a href="https://github.com/SpartnerNL/Laravel-Excel/actions">
    <img src="https://github.com/SpartnerNL/Laravel-Excel/actions/workflows/run-tests.yml/badge.svg" alt="Github Actions">
  </a>

  <a href="https://styleci.io/repos/14259390">
    <img src="https://styleci.io/repos/14259390/shield?branch=3.1" alt="StyleCI">
  </a>

   <a href="https://packagist.org/packages/maatwebsite/excel">
      <img src="https://poser.pugx.org/maatwebsite/excel/v/stable.png" alt="Latest Stable Version">
  </a>

  <a href="https://packagist.org/packages/maatwebsite/excel">
      <img src="https://poser.pugx.org/maatwebsite/excel/downloads.png" alt="Total Downloads">
  </a>

  <a href="https://github.com/SpartnerNL/Laravel-Excel/blob/3.1/LICENSE">
    <img src="https://poser.pugx.org/maatwebsite/excel/license.png" alt="License">
  </a>
</p>

## ✨ Features

- **Easily export collections to Excel.** Supercharge your Laravel collections and export them directly to an Excel or CSV document. Exporting has never been so easy.

- **Supercharged exports.** Export queries with automatic chunking for better performance. You provide us the query, we handle the performance. Exporting even larger datasets? No worries, Laravel Excel has your back. You can queue your exports so all of this happens in the background.

- **Supercharged imports.** Import workbooks and worksheets to Eloquent models with chunk reading and batch inserts! Have large files? You can queue every chunk of a file! Your entire import will happen in the background.

- **Export Blade views.** Want to have a custom layout in your spreadsheet? Use a HTML table in a Blade view and export that to Excel.


<br>

## 🎓 Learning Laravel Excel

You can find the full documentation of Laravel Excel [on the website](https://docs.laravel-excel.com).

We welcome suggestions for improving our docs. The documentation repository can be found at [https://github.com/SpartnerNL/laravel-excel-docs](https://github.com/SpartnerNL/laravel-excel-docs).

Some articles and tutorials can be found on our blog: https://medium.com/maatwebsite/laravel-excel/home

## :mailbox_with_mail: License & Postcardware



Laravel Excel is created with love and care by Spartner (formerly known as Maatwebsite) to give back to the Laravel community. It is completely free (MIT license) to use, however the package is licensed as Postcardware. This means that if it makes it to your production environment, we would very much appreciate receiving a postcard from your hometown.

**Spartner**
Markt 2
6231 LS Meerssen
The Netherlands.

More about the license can be found at: [https://docs.laravel-excel.com/3.1/getting-started/license.html](https://docs.laravel-excel.com/3.1/getting-started/license.html)

## Created by Spartner (formerly Maatwebsite)

We are a strategic development partner, creating web-based custom built software from Laravel. In need of a digital solution for your challenge? Give us a call.

https://spartner.software
info@spartner.nl
+31 (0) 10 - 7449312

## :wrench: Supported Versions

Versions will be supported for a limited amount of time.

| Version | Laravel Version | Php Version | Support |
|---- |----|----|----|
| 2.1 | <=5.6 | <=7.0 | Unsupported since 15-5-2018 |
| 3.0 | ^5.5 |  ^7.0 | Unsupported since 31-12-2018 |
| 3.1 | >=5.8 \| <=13.x |  ^7.2 \| ^8.0 | No active support, CVE only |
| 4.0 | >=12 \| <=13.x |  ^8.3 | New features |

---

--- METRICS ---
- Files Extracted: 1
- Estimated Token Budget: ~1160 tokens
- Canonical Reference: https://codewiki.google/github.com/SpartnerNL/Laravel-Excel


## 2. Official Technical Reference & Guides (SpartnerNL/laravel-excel-docs)

## File: 2.1/import/README.md

# Importing a file

To start importing a file, you can use `->load($filename)`. The callback is optional.

    Excel::load('file.xls', function($reader) {

        // reader methods

    });

---

## File: 2.1/getting-started/README.md

# Installation

Require this package in your `composer.json` and update composer. This will download the package and PHPExcel of PHPOffice.

#### Laravel 4

    "maatwebsite/excel": "~1.3"
    
#### Laravel 5

    "maatwebsite/excel": "~2.1.0"

After updating composer, add the ServiceProvider to the providers array in `app/config/app.php`

    Maatwebsite\Excel\ExcelServiceProvider::class,

You can use the facade for shorter code. Add this to your aliasses:

    'Excel' => Maatwebsite\Excel\Facades\Excel::class,

The class is binded to the ioC as `excel`

    $excel = App::make('excel');

---

## File: 2.1/export/README.md

# Simple Excel Export

### Basics

A new file can be created using the `create` method with the filename as first parameter.

    Excel::create('Filename');

To manipulate the creation of the file you can use the callback with `LaravelExcelWriter` parameter

    Excel::create('Filename', function($excel) {

        // Call writer methods here

    });

### Changing properties

There are a couple of properties we can change inside the closure. Most of them are set to the config values by default. See `app/config/packages/maatwebsite/excel/config.php`.

    Excel::create('Filename', function($excel) {

        // Set the title
        $excel->setTitle('Our new awesome title');

        // Chain the setters
        $excel->setCreator('Maatwebsite')
              ->setCompany('Maatwebsite');

        // Call them separately
        $excel->setDescription('A demonstration to change the file properties');

    });

> Go to the reference guide to see a list of available properties.

---

## File: 3.0/getting-started/README.md

# Introduction

:rocket: Laravel Excel is intended at being Laravel-flavoured PhpSpreadsheet: a simple, but elegant wrapper around PhpSpreadsheet with the goal of simplifying
exports. 

:fire: [PhpSpreadsheet](https://phpspreadsheet.readthedocs.io/) is a library written in pure PHP and providing a set of classes that allow you to read from and to write to different spreadsheet file formats, like Excel and LibreOffice Calc.

Laravel Excel features:

* Easily export collections to Excel
* Export queries with automatic chunking for better performance
* Queue exports for better performance
* Easily export Blade views to Excel

---

## File: 3.0/exports/README.md

## :rocket: 5 minute quick start

:muscle: Create an export class in `app/Exports`

You may do this by using the `make:export` command.

```
php artisan make:export UsersExport --model=User
```

If you prefer to create the export manually, you can create the following in `app/Exports`:

```php
<?php

namespace App\Exports;

use App\User;
use Maatwebsite\Excel\Concerns\FromCollection;

class UsersExport implements FromCollection
{
    public function collection()
    {
        return User::all();
    }
}
```

:fire: In your controller you can call this export now:

```php

use App\Exports\UsersExport;
use Maatwebsite\Excel\Facades\Excel;
use App\Http\Controllers\Controller;

class UsersController extends Controller 
{
    public function export() 
    {
        return Excel::download(new UsersExport, 'users.xlsx');
    }
}
```

:page_facing_up: Find your `users.xlsx` in your downloads folder!

---

## File: 3.1/imports/README.md

---
pageClass: no-toc
---

## :rocket: 5 minute quick start

:muscle: Create an import class in `app/Imports`

You may do this by using the `make:import` command.

```
php artisan make:import UsersImport --model=User
```

The file can be found in `app/Imports`:

::: vue
.
├── app
│   ├── `Imports` 
│   │   ├── UsersImport.php
│ 
└── composer.json
:::

If you prefer to create the import manually, you can create the following in `app/Imports`:

```php
<?php

namespace App\Imports;

use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Maatwebsite\Excel\Concerns\ToModel;

class UsersImport implements ToModel
{
    /**
     * @param array $row
     *
     * @return User|null
     */
    public function model(array $row)
    {
        return new User([
           'name'     => $row[0],
           'email'    => $row[1], 
           'password' => Hash::make($row[2]),
        ]);
    }
}
```

:fire: In your controller you can call this import now:

```php

use App\Imports\UsersImport;
use Maatwebsite\Excel\Facades\Excel;
use App\Http\Controllers\Controller;

class UsersController extends Controller 
{
    public function import() 
    {
        Excel::import(new UsersImport, 'users.xlsx');
        
        return redirect('/')->with('success', 'All good!');
    }
}
```

:page_facing_up: Find the imported users in your database!

---

## File: 3.1/getting-started/README.md

---
pageClass: no-toc
---

# Introduction

:rocket: Laravel Excel is intended at being Laravel-flavoured PhpSpreadsheet: a simple, but elegant wrapper around PhpSpreadsheet with the goal of simplifying
exports and imports. 

:fire: [PhpSpreadsheet](https://phpspreadsheet.readthedocs.io/) is a library written in pure PHP and providing a set of classes that allow you to read from and to write to different spreadsheet file formats, like Excel and LibreOffice Calc.

## Laravel Excel Features

* Easily export collections to Excel.
* Export queries with automatic chunking for better performance.
* Queue exports for better performance.
* Easily export Blade views to Excel.
* Easily import to collections.
* Read the Excel file in chunks.
* Handle the import inserts in batches.

---

## File: 3.1/exports/README.md

---
pageClass: no-toc
---

# :rocket: 5 minute quick start

[[toc]]

:muscle: Create an export class in `app/Exports`

You may do this by using the `make:export` command.

```
php artisan make:export UsersExport --model=User
```

The file can be found in `app/Exports`:

::: vue
.
├── app
│   ├── `Exports` 
│   │   ├── UsersExport.php
│ 
└── composer.json
:::

If you prefer to create the export manually, you can create the following in `app/Exports`:

```php
<?php

namespace App\Exports;

use App\Models\User;
use Maatwebsite\Excel\Concerns\FromCollection;

class UsersExport implements FromCollection
{
    public function collection()
    {
        return User::all();
    }
}
```

:fire: In your controller you can call this export now:

```php
<?php

namespace App\Http\Controllers;

use App\Exports\UsersExport;
use Maatwebsite\Excel\Facades\Excel;

class UsersController extends Controller 
{
    public function export() 
    {
        return Excel::download(new UsersExport, 'users.xlsx');
    }
}
```

And finally add a route to be able to access the export:
```php
Route::get('users/export/', [UsersController::class, 'export']);
```


:page_facing_up: Find your `users.xlsx` in your downloads folder!

---

## File: 3.1/architecture/README.md

# Lifecycle

[[toc]]

## Introduction

When using a package in your application, it's good to understand how the package functions behind the scenes. 
Understanding the behind-the-scenes will make you feel more comfortable and confident using the maximum potential of the tool.

The goal of this page is to give you a high-level overview of how Laravel Excel works. 

## Exports Lifecycle Overview

This section will try to give you an overview of how the export works behind the scenes.

### Export Object

Everything starts with the `Export` object. This object **encapsulates** your entire export logic. 
It both configures and handles the export logic.

A simple example of an export object is:

```php
<?php

namespace App\Exports;

use App\User;
use Maatwebsite\Excel\Concerns\FromCollection;

class UsersExport implements FromCollection
{
    public function collection()
    {
        return User::all();
    }
}
```

If you want to read more about export objects, go to the architecture page of [export objects](/3.1/architecture/objects.html).

### Passing on the Export object

Next the Export object will be passed on to the Laravel Excel package. The main entry point for this is the `Maatwebsite/Excel/Excel` class. This class can be called in multiple ways.

#### Facade

The easiest way to work with the `Excel` class is to use the `Maatwebsite\Excel\Facades\Excel` facade. 
If you use [auto-discovery](https://laravel.com/docs/packages#package-discovery), you can use the alias `\Excel` directly instead of using the fully qualified namespace.

#### Dependency injection

You can inject the `Maatwebsite/Excel/Excel` manager class into your class, either via constructor injection 
or method injection in case of a controller.

```php
<?php
use App\Exports\UsersExport;
use Maatwebsite\Excel\Excel;

class ExportController
{
    private $excel;

    public function __construct(Excel $excel)
    {
        $this->excel = $excel;
    }
    
    public function exportViaConstructorInjection()
    {
        return $this->excel->download(new UsersExport, 'users.xlsx');
    }
    
    public function exportViaMethodInjection(Excel $excel)
    {
        return $excel->download(new UsersExport, 'users.xlsx');
    }
}
```

#### Contract

You can also use the `Maatwebsite\Excel\Exporter` interface to decouple more from the concrete Excel manager implementation. The contract offers the same methods as the `Excel` class. 
It will make it easier to e.g. stub out the Exporter in your unit tests. The `Exporter` contract can be either injected via the constructor or a method in a controller.

```php
use App\Exports\UsersExport;
use Maatwebsite\Excel\Exporter;

class ExportsController
{
    private $exporter;

    public function __construct(Exporter $exporter)
    {
        $this->exporter = $exporter;
    }
    
    public function export()
    {
        return $this->exporter->download(new UsersExport, 'users.xlsx');
    }
}
```

#### Container binding

If you want to bind the `Maatwebsite\Excel\Excel` manager to your own class via a container binding, you can use the `excel` container binding.

```php
$this->app->bind(YourCustomExporter::class, function() {
    return new YourCustomExporter($this->app['excel']);
});
```

#### Exportable trait

If you prefer a sprinkle of magic, you can use the `Maatwebsite\Excel\Concerns\Exportable` trait in your `Export` object. This trait will expose a couple of methods that will make it possible to directly export an `Export` object.

```php
namespace App\Exports;

use App\User;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\Exportable;

class UsersExport implements FromCollection
{
    use Exportable;

    public function collection()
    {
        return User::all();
    }
}
```

You can now download the export without the need for the `facade` or `Excel` manager.

```php
return (new UsersExport)->download('users.xlsx');
```

Read more about the exportable trait in the [exportables](/3.1/exports/exportables.html) docs.

### Handling the Export object

#### Writer type detection

After using one of the above methods to pass on the `Export` object to the `Excel` manager, it will try to figure out what export it needs to be generated to. 
This will be either based on the extension of the file, the explicitly passed writer type. You can find the extension to writer type mapping in the `excel.php` config, in the `extension_detector` section. 
In case no writer type can be detected, a `Maatwebsite\Excel\Exceptions\NoTypeDetectedException` exception is thrown and the export process will be stopped.

#### Starting the Writing process

The `Excel` manager will then delegate the handling to the `Maatwebsite\Excel\Writer`. The first action of the `Writer` is to register the event listeners that are registered. 
Next it will create a new `PhpOffice\PhpSpreadsheet\Spreadsheet` instance that we will use to convert our `Export` object to.

The first event raised is the `BeforeExport` event. This is raised just after the `Spreadsheet` instance is created and allows early access to it.

#### Multiple sheets

Next the `Writer` will determine if multiple sheets are configured, by checking for the `Maatwebsite\Excel\Concerns\WithMultipleSheets` concern.

Then it will delegate the further handling of each sheet to the `Maatwebsite\Excel\Sheet` class.

#### Processing the sheets

In the `Sheet` class, the most heavy lifting happens. It first will create a `PhpOffice\PhpSpreadsheet\Worksheet\Worksheet` instance. Then it will raise the `BeforeSheet` event which allows you to hook into the moment just before the sheet handling starts.

Then it will determine what kind of export we are dealing with: `FromQuery`, `FromArray`, `FromCollection` or `FromView`. Based on that it will start the connected export process.

- `FromView` will pass on the rendered `Blade` view to PhpSpreadsheet's `Html` Reader. That Reader will turn the table html into Excel cells. It also handles some inline styles (color and background color) and col/rowspans.
- The **Query** passed with the `FromQuery` will automatically be chunked and each chunk will be appended to the Sheet. The chunking is done to limit the amount of Eloquent objects it needs to keep in memory. It greatly reduces memory usage.
- The entire array of Collection will directly be appended to the Sheet. 

When the `Sheet` starts appending records, it will first call the `map()` method if the `WithMapping` concern is used. This allows the `Export` object to format the data before it is inserted.

Then it will handle column formatting (`WithColumnFormatting` concern) and cell autosizing (`ShouldAutoSize`).

To close off the Sheet processing, it will raise a `AfterSheet` event.

### Passing on to PhpSpreadsheet

After the sheets are processed, the writing process will start. The writing process is started by raising the `BeforeWriting` event; this allows you to hook into the process of writing.
Next we will create a new `PhpSpreadsheet Writer` based on the writer type that was determined. Then it will save it to a temporary file and return that filepath to the `Excel` manager.

### Creating a Response

The `Excel` manager basically has 2 types of responses, it either starts the **download** process or it will **store** the file to disk.

#### Download the file

We will take the temporary file that was returned by the `Writer` and use Laravel's `ResponseFactory` to create a `Symfony\Component\HttpFoundation\BinaryFileResponse`. When returning this response in your controller, it will start a download.

#### Storing the file

The storing of the file will be handled by Laravel's `Filesystem`. By default the file will be stored on your `default` disk, but you can also pass a custom disk via the `Excel::store()` method.

## Imports Lifecycle Overview

This section will try to give you an overview of how the import works behind the scenes.

### Import Object

Everything starts with the `Import` object. This object **encapsulates** your entire import logic. 
It both configures and handles the import logic.

A simple example of an import object is:

```php
namespace App\Imports;

use App\User;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\ToCollection;

class UsersImport implements ToCollection
{
    public function collection(Collection $rows)
    {
        foreach ($rows as $row) 
        {
            User::create([
                'name' => $row[0],
            ]);
        }
    }
}
```

If you want to read more about imports objects, go to the architecture page of [imports objects](/3.1/architecture/objects.html).

### Passing on the Import object

Next the Import object will be passed on to the Laravel Excel package. The main entry point for this is the `Maatwebsite/Excel/Excel` class. This class can be called in the same way as outlined in the Export lifecycle.

#### Contract

You can also use the `Maatwebsite\Excel\Importer` interface to decouple more from the concrete Excel manager implementation. The contract offers the same methods as the `Excel` class. 
It will make it easier to e.g. stub out the Importer in your unit tests. The `Importer` contract can be either injected via the constructor or the method of a controller.

```php
use App\Imports\UsersImport;
use Maatwebsite\Excel\Importer;

class ImportsController
{
    private $importer;

    public function __construct(Importer $importer)
    {
        $this->importer = $importer;
    }
    
    public function import()
    {
        return $this->importer->import(new UsersImport, 'users.xlsx');
    }
}
```

#### Importable trait

If you prefer a sprinkle of magic, you can use the `Maatwebsite\Excel\Concerns\Importable` trait in your `Import` object. This trait will expose a couple of methods that will make it possible to directly import an `Import` object.

```php
namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\ToCollection;
use Maatwebsite\Excel\Concerns\Importable;

class UsersImport implements ToCollection
{
    use Importable;

    ...
}
```

You can now import without the need for the `facade` or `Excel` manager.

```php
(new UsersImport)->import('users.xlsx');
```

Read more about the importable trait in the [importables](/3.1/imports/importables.html) docs.

### Handling the Import object

#### Reader type detection

After using one of the above methods to pass on the `Import` object to the `Excel` manager, it will try to figure out what reader type it is . 
This will be either based on the extension of the file or the explicitly passed reader type. You can find the extension to reader type mapping in the `excel.php` config, in the `extension_detector` section. 
In case no reader type can be detected, a `Maatwebsite\Excel\Exceptions\NoTypeDetectedException` exception is thrown and the import process will be stopped.

#### Starting the Reading process

The `Excel` manager will then delegate the handling to the `Maatwebsite\Excel\Reader`. The first action of the `Reader` is to register the event listeners that are registered. 
It will copy the file from Laravel's `Filesystem` to the local filesystem, so PhpSpreadsheet can read it. 
Next it will create a PhpSpreadsheet `Reader` based on the reader type that was given and load the file into a `PhpOffice\PhpSpreadsheet\Spreadsheet` instance.

Next it will create a new `PhpOffice\PhpSpreadsheet\Spreadsheet` instance that we will use to read our `Import` object from.

The first event that is raised, is the `BeforeImport` event. This is raised just after the `Spreadsheet` instance is loaded and allows early access to it.

#### Multiple sheets

Next we will determine if we are dealing with multiple sheets. This is done based on the `WithMultipleSheets` concern.

#### Processing the sheets

Then each Sheet gets processed. This process gets started off by raising the `BeforeSheet` event. 
Then it will either import it to a Collection, an array or handle each row as an Eloquent model.

- When using `ToModel`, each returned model will be persisted via Eloquent. When using this in combination with `WithBatchInserts`, it will defer the persistence till the batch is complete and then insert them as one batch in the database.
- When using `ToCollection` or `ToArray`, the entire dataset will be passed to the Import method and the user can determine itself how to use it.

The sheet handling is ended by raising the `AfterSheet` event.

## 2. Official Technical Reference & Guides (SpartnerNL/laravel-excel-docs)

## File: README.md

<meta http-equiv="refresh" content="0;url=/4.x/getting-started/" />

---

## File: index.md

---
head:
  - - meta
    - http-equiv: refresh
      content: 0;url=/4.x/getting-started/
---

Redirecting to the [Laravel Excel 4.x documentation](/4.x/getting-started/)…

---

## File: package.json

{
    "private": true,
    "type": "module",
    "engines": {
        "node": ">=20.19.0"
    },
    "scripts": {
        "docs:dev": "vitepress dev",
        "docs:build": "vitepress build",
        "docs:preview": "vitepress preview"
    },
    "devDependencies": {
        "@fontsource-variable/ibm-plex-sans": "^5.3.0",
        "@fontsource/ibm-plex-mono": "^5.3.0",
        "markdown-it-container": "^4.0.0",
        "vitepress": "^1.6.4",
        "vitepress-plugin-llms": "^1.14.0"
    }
}

---

## File: 2.1/index.md

<meta http-equiv="refresh" content="0;url=/2.1/getting-started/" />

---

## File: 2.1/blade/load-view.md

# @Blade to Excel

We can utilise the magic of Laravel's Blade engine to power our Excel export. Sharing a view, loading a view per sheet, creating a html table inside a view, basic CSS styling, ...

# Loading a view for a single sheet

We can load a view for every sheet we create with `->loadView()`.

    Excel::create('New file', function($excel) {

        $excel->sheet('New sheet', function($sheet) {

            $sheet->loadView('folder.view');

        });

    });

# Using different views for different sheets

    Excel::create('New file', function($excel) {

        $excel->sheet('First sheet', function($sheet) {

            $sheet->loadView('view_first');
        });

        $excel->sheet('Second sheet', function($sheet) {

            $sheet->loadView('view_second');
        });

    });

# Sharing a view for all sheets

We can share a view for all sheets with `shareView()`.

    Excel::shareView('folder.view')->create();

# Unsetting a view for a sheet

When we are using a shared view, but we don't want to use a view for the current sheet, we can use `->unsetView()`.

    $sheet->unsetView();

---

## File: 2.1/blade/styling.md

# Styling sheets

### General styling

If you want to change the general styling of your sheet (not cell or range specific), you can use the `->setStyle()` method or any of the other setters which can be found inside the export documentation.

    // Font family
    $sheet->setFontFamily('Comic Sans MS');

    // Set font with ->setStyle()`
    $sheet->setStyle(array(
        'font' => array(
            'name'      =>  'Calibri',
            'size'      =>  12,
            'bold'      =>  true
        )
    ));

### Styling with PHPExcel methods

It's possible to style the sheets and specific cells with help of PHPExcel methods. This package includes a lot of shortcuts (see export documentation), but also always the use of the native methods.

    // Set background color for a specific cell
    $sheet->getStyle('A1')->applyFromArray(array(
        'fill' => array(
            'type'  => PHPExcel_Style_Fill::FILL_SOLID,
            'color' => array('rgb' => 'FF0000')
        )
    ));

### Using HTML tags

Most of the HTML tags are supported.

    <html>

        
        <h1>Big title</h1>

        
        **Bold cell**
        **Bold cell**

        
        *Italic cell*

        
        

    </html>

> Inside the `view.php` config you can change how these tags will be interpreted by Excel by default.

### Using HTML attributes

Some of the basic styling can be done with HTML attributes.

    <html>

        
        Big title

        
        Bold cell

        
        Bold cell

        
        Italic cell

        
        Cell with width of 100

        
        Cell with height of 100

    </html>

### Styling through inline-styles

It's possible to use inline styles inside your view files. Most of the general styles are supported.

    <html>

        
        Cell

    </html>

> Inside the reference guide you can find a list of supported styles.

### Styling through external CSS file

Styling can be done through an external CSS file.

External css file:

    #cell {
        background-color: #000000;
        color: #ffffff;
    }

    .cell {
        background-color: #000000;
        color: #ffffff;
    }

    tr td {
        background-color: #ffffff;
    }

    tr > td {
        border-bottom: 1px solid #000000;
    }

Table:

```html
<html>
    {{ HTML::style('css/table.css') }}

    <!-- Cell styled with class -->
    <td class="cell">Cell</td>

    <!-- Cell styled with ID -->
    <td id="cell">Cell</td>
</html>
```

> Inside the reference guide you can find a list of supported styles.

> It's advised to include `<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />` into the view to fix problems with UTF-8 encoding.

---

## File: 2.1/blade/vars.md

# Passing variables to the view

### As parameter

We can pass variables to the view by using the second parameter inside the `loadView()` method.

	$sheet->loadView('view', array('key' => 'value'));

### With with()

Alternatively you can use the `with()` method which works the same as with Laravel views.

	// Using normal with()
	$sheet->loadView('view')
		  ->with('key', 'value');

	// using dynamic with()
	$sheet->loadView('view')
		  ->withKey('value');

---

## File: 2.1/changelog/version-1.md

# Version 1

### 1.3.5
- PHPExcel 1.8.1 compatibility
- Clean-up ServiceProvider
- Fix short array syntax for PHP5.3

### 1.3.4
- Fix usage of sheet callback when modifying an existing file
- Modifying existing files improvements (support style overriding)
- Add text-indent support to HtmlReader
- Add simple sheet password protection
- Add support for exporting multiple pdf pages
- Add inline cell formatting to Blade

### 1.3.3
- Fix issue with different start row in chunk filter

### 1.3.2
- Custom value binders
- Html reader update

### 1.3.1
- Fix short array syntax

### 1.3.0
- Additional headers with export() 
- Float, integer, string, timestamps problems
- Cell content ending by zeros
- Images in html
- Font family bug
- Setting row number of row with headings

### 1.2.3
- PDF writer
- Include charts config
- Chunk filter with selected sheet
- Compatibility fix with new PHPExcel release
- setDateColumns fix
- Optional dependencies to require-dev
- Several bugfixes

### 1.2.2
- Chunk filter fixes
- Isset() CellCollection fixes
- PHP 5.3 support
- Missing border styles
- Add CSV settings (delimiter, enclosure, lineEnding) to ExcelFile objects

### 1.2.1
- Fix with() method parameters

### 1.2.0
- Filters
- Chunk filter (with chunked importer)
- ExcelFile (method) injections
- NewExcelFile (method) injections
- Edit existing worksheets
- Converting existing worksheet
- Laravel 4.* + 5.0 support

### 1.1.9
- PHP 5.3 fixes

### 1.1.8
- PHP 5.3 support
- fromArray bugfix

### 1.1.7
- Fix heading generation for export with `->fromArray()`
- Bugfix for non-Unix kernels
- Enhanced CSS parser (thanks to `tijsverkoyen/CssToInlineStyles`)
- Support for nested CSS styles
- Support for multiple css attributes per class
- Support for internal and external CSS files
- Support for inline style blocks (`<style>`)

### 1.1.6

- Provides.json fix
- DocBlock fixes
- Define Illuminate dependencies inside composer.json
- Better HTML rowspan handling views
- use new CellCollection() instead of ::make, to support upcoming Laravel version
- Workaround for long integers
- Add support to `wrap-text` in views
- Fix empty dates parsing
- Support local stylesheets in view parsing
- Push tr classes to td-children in views
- Support for dynamically appending rows to an empty (new) sheet
- Fix separator typo in config

### 1.1.5

- Select sheets by index with `Excel::selectSheetsByIndex(0,1)->load(...)`
- Separator typo fix
- Added `->setFileName()` method
- Use `->setTitle()` only for workbook title not for setting the filename anymore
- Made `setAutoSize()` chainable for other sheet methods
- Export config setting to disable pre calculation of formulas during export
- Export config setting to set the autosizing method (approx|exact)
- Auto sizing export from view fix

### 1.1.4

- Fix for importing 0 as null
- New unit tests

### 1.1.3

- Cell writer `->setBorder()` fix

### 1.1.2

- Fix for multiple imports on one pageload
- Multiple new import heading conversions (`Config: excel::import.heading: true|false|slugged|ascii|numeric|hashed|trans|original`)

### 1.1.1

- Retrieve workbook and sheet title during import (`->getTitle()`)

### 1.1.0

- `Limit()`, `skip()` and `take()` support for fetching results
- Set default page margins
- Export Eloquent models directly (`fromModel()`)
- Auto generate the first row (table heading) from the array keys
- Manipulate cells and cell ranges inside a closure
- Set cell backgrounds/fonts/values, ...
- Create/append/prepend new row/rows
- Manipulate row cells (background, fonts, ...)
- Config value default alignment on merge cells
- DocBlock updates to support better use of IDE autocomplete features
- Parse width and height inside views
- Parse images in views
- Optional to ASCII conversion of imported header columns (array indices)
- Config values for default null comparision and start cells for exports
- Changed default CSV enclosure to `"`
- Support for Laravel package installer

### 1.0.9

- Blade to Excel export fix for PHP5.3

### 1.0.8

- File format identifier enhancements

### 1.0.7

- Set workbook properties fix
- Extra units tests

### 1.0.6

- BatchReader fix

### 1.0.5

- Date parsing fix

### 1.0.4

- Fix calling $this in  anonymous function to set locale and cache

### 1.0.3

- Table headings to attribute names undefined offset fix
- Composer.json enhancements
- Documentation fixes

### 1.0.2

- Cell Collection fixes
- Default autosizing bugfixes
- ->load() accepts input encoding parameter
- Documentation fixes

### 1.0.1

- Column width and row height bugfix
- Typo fixes

### 1.0.0

- New documentation
- More logical file structure (dividing into files, separating the different functionality (import / export)
- More optional config settings
- CSV Delimiter fixes
- CSV Encoding
- Import into collections (to support utilisation of ->first(), etc.)
- Better column selecting and result limiting
- Batch upload
- Import dates as Carbon objects by default
- Advanced file import through config coordinates
- Select sheets to import
- Create closure (Excel::create('file', function($excel) { } ))
- More logical syntax for creating new files, syntaxes of creating by array and creating with view should be as identical as possible
- Rewrite of sheet building for views
- Using closures to build sheets for normal sheet creation
- Better support for calling native PHPExcel methods
- Better use of setters
- Config setting to set default store behavior
- Column/row width
- Share views over all sheets + easy views switching per sheet
- External stylesheet with classes/ids parsing for views
- Colspan fix
- Th default styling
- Caching / Cell caching

---

## File: 2.1/changelog/version-2.md

# Version 2

### 2.0.4
- PHPExcel 1.8.1 compatibility
- Clean-up ServiceProvider

### 2.0.3
- Fix usage of sheet callback when modifying an existing file
- Modifying existing files improvements (support style overriding)
- Add text-indent support to HtmlReader
- Add simple sheet password protection
- Add support for exporting multiple pdf pages
- Add inline cell formatting to Blade

### 2.0.2
- Fix issue with different start row in chunk filter

### 2.0.1
- Custom value binders
- Html reader update

### 2.0.0
- Laravel 5 release

---

## File: 2.1/export/array.md

# Creating a sheet from an array

## Array

To create a new file from an array use `->fromArray($source, $nullValue, $startCell, $strictNullComparison, $headingGeneration)` inside the sheet closure.

    Excel::create('Filename', function($excel) {

        $excel->sheet('Sheetname', function($sheet) {

            $sheet->fromArray(array(
                array('data1', 'data2'),
                array('data3', 'data4')
            ));

        });

    })->export('xls');

Alternatively you can use `->with()`.

    $sheet->with(array(
        array('data1', 'data2'),
        array('data3', 'data4')
    ));

If you want to pass variables inside the closure, use `use($data)`

    $data = array(
        array('data1', 'data2'),
        array('data3', 'data4')
    );

    Excel::create('Filename', function($excel) use($data) {

        $excel->sheet('Sheetname', function($sheet) use($data) {

            $sheet->fromArray($data);

        });

    })->export('xls');

### Null comparision

By default 0 is shown as an empty cell. If you want to change this behaviour, you can pass true as 4th parameter:

    // Will show 0 as 0
    $sheet->fromArray($data, null, 'A1', true);

> To change the default behaviour, you can use `excel::export.sheets.strictNullComparison` config setting.

## Eloquent model

It's also possible to pass an Eloquent model and export it by using `->fromModel($model)`. The method accepts the same parameters as fromArray

## Auto heading generation

By default the export will use the keys of your array (or model attribute names) as first row (header column). To change this behaviour you can edit the default config setting (`excel::export.generate_heading_by_indices`) or pass `false` as 5th parameter:

    // Won't auto generate heading columns
    $sheet->fromArray($data, null, 'A1', false, false);

---

## File: 2.1/export/autofilter.md

# Auto filter

To enable the auto filter use `->setAutoFilter($range = false)`.

    // Auto filter for entire sheet
    $sheet->setAutoFilter();

    // Set auto filter for a range
    $sheet->setAutoFilter('A1:E10');

---

## File: 2.1/export/autosize.md

# Auto size

By default the exported file be automatically auto sized. To change this behaviour you can either change the config or use the setters:

    // Set auto size for sheet
    $sheet->setAutoSize(true);

    // Disable auto size for sheet
    $sheet->setAutoSize(false);

    // Disable auto size for columns
    $sheet->setAutoSize(array(
        'A', 'C'
    ));

> The default config setting can be found in: `export.php`.

---

## File: 2.1/export/call.md

# Calling PHPExcel's native methods

It's possible to call all native PHPExcel methods on the `$excel` and `$sheet` objects.

### Calling Workbook methods

Example:

    // Get default style for this workbook
    $excel->getDefaultStyle();

### Calling worksheet methods

Example:

    // Protect cells
    $sheet->protectCells('A1', $password);

> Head over to PHPOffice to learn more about the native methods.

---

## File: 2.1/export/cells.md

# Cell manipulation

    $sheet->cell('A1', function($cell) {

        // manipulate the cell
        $cell->setValue('data1');

    });

    $sheet->cells('A1:A5', function($cells) {

        // manipulate the range of cells

    });

### Set background

To change the background of a range of cells we can use `->setBackground($color, $type, $colorType)`

    // Set black background
    $cells->setBackground('#000000');

### Change fonts

    // Set with font color
    $cells->setFontColor('#ffffff');

    // Set font family
    $cells->setFontFamily('Calibri');

    // Set font size
    $cells->setFontSize(16);

    // Set font weight to bold
    $cells->setFontWeight('bold');

    // Set font
    $cells->setFont(array(
        'family'     => 'Calibri',
        'size'       => '16',
        'bold'       =>  true
    ));

### Set borders

    // Set all borders (top, right, bottom, left)
    $cells->setBorder('solid', 'none', 'none', 'solid');

    // Set borders with array
    $cells->setBorder(array(
        'top'   => array(
            'style' => 'solid'
        ),
    ));

### Set horizontal alignment

    // Set alignment to center
    $cells->setAlignment('center');

### Set vertical alignment

    // Set vertical alignment to middle
     $cells->setValignment('center');

---

## File: 2.1/export/export.md

# Exporting

To download the created file, use `->export($ext)` or `->download($ext)`.

#### Export to Excel5 (xls)

    Excel::create('Filename', function($excel) {

    })->export('xls');

    // or
    ->download('xls');

#### Export to Excel2007 (xlsx)

    ->export('xlsx');

    // or
    ->download('xlsx');

#### Export to CSV

    ->export('csv');

    // or
    ->download('csv');

> You can set the default enclosure and delimiter inside the config

#### Export to PDF

To export files to pdf, you will have to include `"dompdf/dompdf": "~0.6.1"`, `"mpdf/mpdf": "~6.1"` or `"tecnick.com/tcpdf": "~6.0.0"` in your `composer.json` and change the `export.pdf.driver` config setting accordingly.

    ->export('pdf');

---

## File: 2.1/export/format.md

# Column formatting

To tell Excel how it should interpret certain columns, you can use `->setColumnFormat($array)`.

    // Format column as percentage
    $sheet->setColumnFormat(array(
        'C' => '0%'
    ));
    
    // Format a range with e.g. leading zeros
    $sheet->setColumnFormat(array(
        'A2:K2' => '0000'
    ));

    // Set multiple column formats
    $sheet->setColumnFormat(array(
        'B' => '0',
        'D' => '0.00',
        'F' => '@',
        'F' => 'yyyy-mm-dd',
    ));

> Go to the reference guide to see a list of available formats.

---

## File: 2.1/export/freeze.md

# Freeze rows

If you want to freeze a cell, row or column, use:

    // Freeze first row
    $sheet->freezeFirstRow();

    // Freeze the first column
    $sheet->freezeFirstColumn();

    // Freeze the first row and column
    $sheet->freezeFirstRowAndColumn();

    // Set freeze
    $sheet->setFreeze('A2');

---

## File: 2.1/export/index.md

# Simple Excel Export

### Basics

A new file can be created using the `create` method with the filename as first parameter.

    Excel::create('Filename');

To manipulate the creation of the file you can use the callback with `LaravelExcelWriter` parameter

    Excel::create('Filename', function($excel) {

        // Call writer methods here

    });

### Changing properties

There are a couple of properties we can change inside the closure. Most of them are set to the config values by default. See `app/config/packages/maatwebsite/excel/config.php`.

    Excel::create('Filename', function($excel) {

        // Set the title
        $excel->setTitle('Our new awesome title');

        // Chain the setters
        $excel->setCreator('Spartner')
              ->setCompany('Spartner');

        // Call them separately
        $excel->setDescription('A demonstration to change the file properties');

    });

> Go to the reference guide to see a list of available properties.

---

## File: 2.1/export/injection.md

# NewExcelFile injections

Following the Laravel 5.0 philosophy with its new awesome FormRequest injections, we introduce you NewExcelFile injections.

## NewExcelFile class

This NewExcelFile is a wrapper for a new Excel file. Inside the `getFilename()` you can declare the wanted filename.

    class UserListExport extends \Maatwebsite\Excel\Files\NewExcelFile {

        public function getFilename()
        {
            return 'filename';
        }
    }

## Usage

You can inject these NewExcelFiles inside the __constructor or inside the method (when using Laravel 5.0), in e.g. the controller.

    class ExampleController extends Controller {

        public function exportUserList(UserListExport $export)
        {
            // work on the export
            return $export->sheet('sheetName', function($sheet)
            {

            })->export('xls');
        }

    }

## Export Handlers

To decouple your Excel-export code completely from the controller, you can use the export handlers.

    class ExampleController extends Controller {

        public function exportUserList(UserListExport $export)
        {
            // Handle the export
            $export->handleExport();
        }

    }

The `handleExport()` method will dynamically call a handler class which is your class name appended with `Handler`

    class UserListExportHandler implements \Maatwebsite\Excel\Files\ExportHandler {

        public function handle(UserListExport $export)
        {
            // work on the export
            return $export->sheet('sheetName', function($sheet)
            {

            })->export('xls');
        }

    }

---

## File: 2.1/export/merge.md

# Column merging

### Merging cells

To merge a range of cells, use `->mergeCells($range)`.

    $sheet->mergeCells('A1:E1');

### Merging columns and rows

To merge columns and rows, use `->setMergeColumn($array)`.

    $sheet->setMergeColumn(array(
        'columns' => array('A','B','C','D'),
        'rows' => array(
            array(2,3),
            array(5,11),
        )
    ));

---

## File: 2.1/export/rows.md

# Row manipulation

### Manipulate certain row

#### Change cell values

    // Manipulate first row
    $sheet->row(1, array(
         'test1', 'test2'
    ));

    // Manipulate 2nd row
    $sheet->row(2, array(
        'test3', 'test4'
    ));

#### Manipulate row cells

    // Set black background
    $sheet->row(1, function($row) {

        // call cell manipulation methods
        $row->setBackground('#000000');

    });

### Append row

    // Append row after row 2
    $sheet->appendRow(2, array(
        'appended', 'appended'
    ));

    // Append row as very last
    $sheet->appendRow(array(
        'appended', 'appended'
    ));

### Prepend row

    // Add before first row
    $sheet->prependRow(1, array(
        'prepended', 'prepended'
    ));

    // Add as very first
    $sheet->prependRow(array(
        'prepended', 'prepended'
    ));

### Append multiple rows

    // Append multiple rows
    $sheet->rows(array(
        array('test1', 'test2'),
        array('test3', 'test4')
    ));

    // Append multiple rows
    $sheet->rows(array(
        array('test5', 'test6'),
        array('test7', 'test8')
    ));

---

## File: 2.1/export/sheet-styling.md

# Sheet styling

### General styling

If you want to change the general styling of your sheet (not cell or range specific), you can use the `->setStyle()` method.

    // Set font with ->setStyle()`
    $sheet->setStyle(array(
        'font' => array(
            'name'      =>  'Calibri',
            'size'      =>  15,
            'bold'      =>  true
        )
    ));

### Fonts

To change the font for the current sheet use `->setFont($array)`:

    $sheet->setFont(array(
        'family'     => 'Calibri',
        'size'       => '15',
        'bold'       => true
    ));

#### Separate setters

    // Font family
    $sheet->setFontFamily('Comic Sans MS');

    // Font size
    $sheet->setFontSize(15);

    // Font bold
    $sheet->setFontBold(true);

### Borders

You can set borders for the sheet, by using:

    // Sets all borders
    $sheet->setAllBorders('thin');

    // Set border for cells
    $sheet->setBorder('A1', 'thin');

    // Set border for range
    $sheet->setBorder('A1:F10', 'thin');

> Go to the reference guide to see a list of available border styles

---

## File: 2.1/export/sheets.md

# Sheets

### Creating a sheet

To create a new sheet inside our newly created file, use `->sheet('Sheetname')` with callback of `LaravelExcelWorksheet` type parameter.

    Excel::create('Filename', function($excel) {

        $excel->sheet('Sheetname', function($sheet) {

            // Sheet manipulation

        });

    })->export('xls');


### Creating multiple sheets

You can set as many sheets as you like inside the file:

    Excel::create('Filename', function($excel) {

        // Our first sheet
        $excel->sheet('First sheet', function($sheet) {

        });

        // Our second sheet
        $excel->sheet('Second sheet', function($sheet) {

        });

    })->export('xls');

### Changing properties

There are a couple of properties we can change inside the closure. Most of them are set to the config values by default. See `app/config/packages/maatwebsite/excel/config.php`.

    Excel::create('Filename', function($excel) {

        $excel->sheet('Sheetname', function($sheet) {

            $sheet->setOrientation('landscape');

        });

    })->export('xls');

> Go to the reference guide to see a list of available properties.

### Default page margin

It's possible to set the default page margin inside the config file `excel::export.sheets`.
It accepts boolean, single value or array.

To manually set the page margin you can use: `->setPageMargin()`

    // Set top, right, bottom, left
    $sheet->setPageMargin(array(
        0.25, 0.30, 0.25, 0.30
    ));

    // Set all margins
    $sheet->setPageMargin(0.25);
    
### Password protecting a sheet
    
A sheet can be password protected with `$sheet->protect()`:

    // Default protect
    $sheet->protect('password');
    
    // Advanced protect
    $sheet->protect('password', function(\PHPExcel_Worksheet_Protection $protection) {
        $protection->setSort(true);
    });

---

## File: 2.1/export/sizing.md

# Cell size

### Set column width

To set the column width use `->setWidth($cell, $width)`.

    // Set width for a single column
    $sheet->setWidth('A', 5);

    // Set width for multiple cells
    $sheet->setWidth(array(
        'A'     =>  5,
        'B'     =>  10
    ));

### Set row height

To set the row height use `->setHeight($row, $height)`.

    // Set height for a single row
    $sheet->setHeight(1, 50);

    // Set height for multiple rows
    $sheet->setHeight(array(
        1     =>  50,
        2     =>  25
    ));

### Set cell size

To set the cell size use `->setSize($cell, $width, $height)`.

    // Set size for a single cell
    $sheet->setSize('A1', 500, 50);

    $sheet->setSize(array(
        'A1' => array(
            'width'     => 50,
            'height'    => 500
        )
    ));

---

## File: 2.1/export/store.md

# Store on server

To store the created file on the server, use `->store($ext, $path = false, $returnInfo = false)` or `->save()`.

### Normal export to default storage path

By default the file will be stored inside the `storage/exports` folder, which has been defined in the `export.php` config file.

    Excel::create('Filename', function($excel) {

        // Set sheets

    })->store('xls');

### Normal export to custom storage path

If you want to use a custom storage path (e.g. to separate the files per client), you can set the folder as the second parameter.

    ->store('xls', storage_path('excel/exports'));

### Store and export

    ->store('xls')->export('xls');

### Store and return storage info

If you want to return storage information, set the third paramter to true or change the config setting inside `export.php`.

    ->store('xls', false, true);

|Key|Explanation|
|---|-----------|
|**full**| Full path with filename
|**path**| Path without filename
|**file**| Filename
|**title**| File title
|**ext**| File extension

> Make sure your storage folder is **writable**!

---

## File: 2.1/getting-started/config.md

# Config

### Laravel 4

Laravel Excel includes several config settings for import-, export-, view- and CSV-specific settings.
Use the artisan publish command to publish the config file to your project.

    php artisan config:publish maatwebsite/excel

The config files can now be found at `app/config/packages/maatwebsite/excel`

### Laravel 5

To publish the config settings in Laravel 5 use:

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

This will add an `excel.php` config file to your config folder.

---

## File: 2.1/getting-started/contributing.md

# Contribution Guide

### Bug fixes

**ALL** bug fixes should be made to appropriate branch (e.g. `1.1` for 1.1.* bug fixes). Bug fixes should never be sent to the `master` branch.

### Pull Requests

Every pull request should pass the unit tests. If you include new functionality, make sure you include a test. Pull requests will be evaluated and possibly added to the next stable release.

### Feature Requests

If you have an idea for a new feature you would like to see added to Laravel Excel, you may create an issue on GitHub with `[Request]` in the title. The feature request will then be reviewed by @SpartnerNL.

### Coding Guidelines

Laravel, and therefore Spartner's Laravel Excel follows the [PSR-0](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md) and [PSR-1](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md) coding standards. In addition to these standards, below is a list of other coding standards that should be followed:

- Namespace declarations should be on the same line as `<?php`.
- Class opening `{` should be on the same line as the class name.
- Function and control structure opening `{` should be on a separate line.
- Interface and Trait names are suffixed with `Interface` (`FooInterface`) and `Trait` (`FooTrait`) respectively.

---

## File: 2.1/getting-started/index.md

# Installation

Require this package in your `composer.json` and update composer. This will download the package and PHPExcel of PHPOffice.

#### Laravel 4

    "maatwebsite/excel": "~1.3"
    
#### Laravel 5

    "maatwebsite/excel": "~2.1.0"

After updating composer, add the ServiceProvider to the providers array in `app/config/app.php`

    Maatwebsite\Excel\ExcelServiceProvider::class,

You can use the facade for shorter code. Add this to your aliasses:

    'Excel' => Maatwebsite\Excel\Facades\Excel::class,

The class is binded to the ioC as `excel`

    $excel = App::make('excel');

---

## File: 2.1/getting-started/license.md

# License

This package is licensed under LGPL. You are free to use it in personal and commercial projects. The code can be forked and modified, but the original copyright author should always be included!

---

## File: 2.1/getting-started/requirements.md

# Requirements

- PHP version >= 5.3.7
- Laravel >= 4.1
- PHPOffice PHPExcel >= 1.8.0 (included by composer.json)
- PHP extension php_zip enabled (required if you need PHPExcel to handle .xlsx .ods or .gnumeric files)
- PHP extension php_xml enabled
- PHP extension php_gd2 enabled (optional, but required for exact column width autocalculation)

---

## File: 2.1/import/batch.md

# Batch import

### Import a folder

To import an entire folder (only XLS, XLSX and CSV files will be imported), set the folder as the first parameter.

    Excel::batch('app/storage/uploads', function($rows, $file) {

        // Explain the reader how it should interpret each row,
        // for every file inside the batch
        $rows->each(function($row) {

            // Example: dump the firstname
            dd($row->firstname);

        });

    });

### Import multiple files

It's also possible to provide an array of files to import.

    $files = array(
        'file1.xls',
        'file2.xls'
    );

    Excel::batch($files, function($rows, $file) {

    });

### Import a folder and multiple sheets

When your files contain multiple sheets, you should also loop the sheets

    Excel::batch('app/storage/uploads', function($sheets, $file) {

        $sheets->each(function($sheet) {

        });

    });

---

## File: 2.1/import/cache.md

# Caching and Cell caching

### Cell caching

You can enable cell caching inside the config `excel.php`. You can choose between a couple of drivers and change a couple of settings. By default the caching is **enabled** and will use **in memory** caching.

### Remembering results

If you want to remember the results you can use `->remember($minutes)`. Next time you will load the same file (if it's still inside the cache), it will return the cached results.

    // Remember for 10 minutes
    $results = $reader->remember(10)->get();

---

## File: 2.1/import/calculation.md

# Calculate formulas

By default formulas inside the file are being calculated and it's result will be returned. Inside `import.php` config you can change the default behaviour by setting `calculate` to the desired preference.

If you want to enable/disable it for a single import, you can use `->calculate($boolean)`

    // Enable calculation
    $reader->calculate();

    // Disable calculation
    $reader->calculate(false);

---

## File: 2.1/import/chunk.md

# Chunk importer

When dealing with big files, it's better to import the data in big chunks. You can enable this with `filter('chunk')`;
To import it into chunks you can use `chunk($size, $callback)` instead of the normal `get()`. The first parameter is the size of the chunk. The second parameter is a closure which will return the results.

    Excel::filter('chunk')->load('file.csv')->chunk(250, function($results)
    {
            foreach($results as $row)
            {
                // do stuff
            }
    });

## ExcelFile class example:

When working with ExcelFile injections (in the constructor or as method injection), you can enable the chunk filter inside the ExcelFile class

    class UserListImport extends \Maatwebsite\Excel\Files\ExcelFile {

        public function getFile()
        {
            return 'file.csv';
        }

        public function getFilters()
        {
            return [
                'chunk'
            ];
        }

    }

Injected ExcelFile example:

    public function importUserList(UserListImport $import)
    {
        $import->chunk(250, function($results)
        {
            // do stuff
            // or return true if you want to stop importing.
        });
    }

## Queued chunks

We automatically queue every chunk for you, if you have enabled the queue driver in your config. 

If you want to by-pass the behaviour, you can pass `false` as the third parameter of `chunk($size, $callback, $shouldQueue)`.

A non-default job queue may be specified by passing its name as the third parameter of `chunk($size, $callback, $shouldQueue)`.

---

## File: 2.1/import/config.md

# Import by Config

When using advanced Excel files (e.g. without any heading columns), it can be complicated to import these.
`->byConfig()` will help you handle this problem.

Inside `excel::import.sheets` config you can find an example.

    Excel::load('file.xls')->byConfig('excel::import.sheets', function($sheet) {

        // The firstname getter will correspond with a cell coordinate set inside the config
        $firstname = $sheet->firstname;

    });

> **Note:** if you are using multiple sheets. `->byConfig` will loop through all sheets. If these getters are only exist on one sheet, you can always use `->selectSheets()`.

---

## File: 2.1/import/convert.md

# Converting

You can convert from one filetype to another by using `->convert()`

    Excel::load('file.csv', function($file) {

        // modify stuff

    })->convert('xls');

---

## File: 2.1/import/dates.md

# Dates

By default the dates will be parsed as a **[Carbon object](https://github.com/briannesbitt/Carbon)**. You can disable date formatting completly inside `import.php` by setting `dates.enabled` to `false`.

To enable/disable date formatting for a single import, use `->formatDates($boolean, $format)`

    // Format the dates
    $reader->formatDates(true);

    // Disable date formatting
    $reader->formatDates(false);

    // Format dates + set date format
    $reader->formatDates(true, 'Y-m-d');

### Format dates

By default the dates are **not formatted**, but returned as a Carbon object. There are a couple of options to format them.

#### Formatting results after ->get()

Inside your loop you can utilise the Carbon method `->format($dateFormat)`

    $rows->each(function($row) {

        $created_at = $row->created_at->format('Y-m-d');

    });

#### Setting a default date format

Inside the config you can set a default date format. A Carbon object will no longer be returned.

Or you can use `->setDateFormat()`

    $reader->setDateFormat('Y-m-d');

### Setting custom date columns

Cells which are not Excel formatted dates will not be parsed as a date. To force this behaviour (or to use this with CSV imports), you can set these date columns manually: `->setDateColumns()`

    $reader->setDateColumns(array(
        'created_at',
        'deleted_at'
    ))->get();

---

## File: 2.1/import/edit.md

# Editing existing files

You can edit existing Excel files, by loading them and after modification exporting them.

    Excel::load('file.csv', function($file) {

        // modify stuff

    })->export('csv');

---

## File: 2.1/import/extra.md

# Extra

### Disable using first row as collection attributes

By default we will use the first row of a file as table heading (so as attribute names for the collection).
You can change the default behaviour inside `import.php` with `import.heading`.

To disable this for a single import, use `->noHeading()`.

    $reader->noHeading();

### Setting the cell name separator
By default collection attribute names will be set by looking at the first row columns. Spaces will be translated to `_`.

**E.g. Created at -> created_at**

The default behaviour can be changed inside the `import.php` config by changing `'separator'`. Or you can use `->setSeparator($separator)`.

    $reader->setSeparator('-');

### Ignoring empty cells
By default empty cells will not be ignored and presented as null inside the cell collection.

To change the default behaviour, you can change `'ignoreEmpty`' inside `import.php` or use `->ignoreEmpty()`.

    $reader->ignoreEmpty();

### Input encoding

Inside the `import.php` config you can change the input encoding. In most cases **UTF-8** will be the best solution. Hower if you dump your results make sure your HTML page has this exact same meta charset!

Optionally you can pass the input encoding inside the `->load()` method.

    // When utilising a closure, you can pass the input encoding as third parameter.
    Excel::load('filename.csv', function($reader) {

    }, 'UTF-8');

    // or without a closure, you can use it as second parameter.
    Excel::load('filename.csv', 'UTF-8');

### CSV Settings

Inside the `csv.php` config you can change the default settings, like the `delimiter`, the `enclosure` and the `line_ending`.

---

## File: 2.1/import/formatting.md

# Custom formatting values

By default Laravel Excel uses PHPExcel's default value binder to intelligently format a cells value when reading it. You may override this behavior by passing in your own value binder to suit your specific needs. Value binders must implement PHPExcel_Cell_IValueBinder and have a bindValue method. They may also extend PHPExcel_Cell_DefaultValueBinder to return the default behavior.
    
    use PHPExcel_Cell;
    use PHPExcel_Cell_DataType;
    use PHPExcel_Cell_IValueBinder;
    use PHPExcel_Cell_DefaultValueBinder;

    class MyValueBinder extends PHPExcel_Cell_DefaultValueBinder implements PHPExcel_Cell_IValueBinder
    {
        public function bindValue(PHPExcel_Cell $cell, $value = null)
        {
            if (is_numeric($value))
            {
                $cell->setValueExplicit($value, PHPExcel_Cell_DataType::TYPE_NUMERIC);

                return true;
            }
            
            // else return default behavior
            return parent::bindValue($cell, $value);
        }
    }

    $myValueBinder = new MyValueBinder;

    $reader = Excel::setValueBinder($myValueBinder)->load('file.xls');
    // Reader methods

Available PHPExcel_Cell_DataType's are TYPE_STRING, TYPE_FORMULA, TYPE_NUMERIC, TYPE_BOOL, TYPE_NULL, TYPE_INLINE and TYPE_ERROR

To reset the value binder back to default and/or before calling Laravel Excel after setting a custom value binder you need to call the resetValueBinder method.

    Excel::resetValueBinder();

---

## File: 2.1/import/index.md

# Importing a file

To start importing a file, you can use `->load($filename)`. The callback is optional.

    Excel::load('file.xls', function($reader) {

        // reader methods

    });

---

## File: 2.1/import/injection.md

# ExcelFile injections

Following the Laravel 5.0 philosophy with its new awesome FormRequest injections, we introduce you ExcelFile injections.

## ExcelFile class

This class is a wrapper for a file on your server. Inside the `getFile()` method you return the filename and it's location. Inside the `getFilters()` method you can enable filters, like the chunk filter.

    class UserListImport extends \Maatwebsite\Excel\Files\ExcelFile {

        public function getFile()
        {
            return storage_path('exports') . '/file.csv';
        }

        public function getFilters()
        {
            return [
                'chunk'
            ];
        }

    }

If you want to have the `getFile()` dynamic based on user's input, you can easily do:

    public function getFile()
    {
        // Import a user provided file
        $file = Input::file('report');
        $filename = $this->doSomethingLikeUpload($file);

        // Return it's location
        return $filename;
    }

## Usage

You can inject these ExcelFiles inside the __constructor or inside the method (when using Laravel 5.0), in e.g. the controller.

    class ExampleController extends Controller {

        public function importUserList(UserListImport $import)
        {
            // get the results
            $results = $import->get();
        }

    }

## CSV Settings

You can pass through optional CSV settings, like `$delimiter`, `$enclosure` and `$lineEnding` as protected properties of the class.

    class UserListImport extends \Maatwebsite\Excel\Files\ExcelFile {

        protected $delimiter  = ',';
        protected $enclosure  = '"';
        protected $lineEnding = '\r\n';

    }

## Import Handlers

To decouple your Excel-import code completely from the controller, you can use the import handlers.

    class ExampleController extends Controller {

        public function importUserList(UserListImport $import)
        {
            // Handle the import
            $import->handleImport();
        }

    }

The `handleImport()` method will dynamically call a handler class which is your class name appended with `Handler`

    class UserListImportHandler implements \Maatwebsite\Excel\Files\ImportHandler {

        public function handle(UserListImport $import)
        {
            // get the results
            $results = $import->get();
        }

    }

---

## File: 2.1/import/results.md

# Handling imported results

### Getting all sheets and rows

After you have loaded a file, you can `->get()` the results like so:

    Excel::load('file.xls', function($reader) {

    })->get();

or

    Excel::load('file.xls', function($reader) {

        // Getting all results
        $results = $reader->get();

        // ->all() is a wrapper for ->get() and will work the same
        $results = $reader->all();

    });

> The `->get()` and `->all()` methods will return a sheet or row collection, depending on the amount of sheets the file has. You can disable this feature inside the `import.php` config by setting `'force_sheets_collection'` to `true`. When set to true it will always return a sheet collection.

### Table heading as attributes

By default the first row of the Excel file will be used as attributes.

    // Get the firstname
    $row->firstname;

> **Note**: by default these attributes will be converted to a slug. You can change the default inside the config `excel::import.heading`. Available options are: `true|false|slugged|ascii|numeric|hashed|trans|original`

> True and slugged will be converted to ASCII as well when `excel::import.to_ascii` is set to true. You can change the default separator as well inside the config.

### Collections

Sheets, rows and cells are collections, this means after doing a `->get()` you can use all default collection methods.

    // E.g. group the results
    $reader->get()->groupBy('firstname');

### Getting the first sheet or row

To get the first sheet or row, you can utilise `->first()`.

    $reader->first();

> **Note:** depending on the config `'force_sheets_collection'` it will return the first row or sheet.

### Workbook and sheet title

It's possible to retrieve the workbook and sheet title with `->getTitle()`.

    // Get workbook title
    $workbookTitle = $reader->getTitle();

    foreach($reader as $sheet)
    {
        // get sheet title
        $sheetTitle = $sheet->getTitle();
    }

### Limiting the file reading

##### Taking rows

When you only want to return the first x rows of a sheet, you can use `->takeRows()` or `->limitRows()`.

    // You can either use ->takeRows()
    $reader->takeRows(10);

    // Or ->limitRows()
    $reader->limitRows(10);

##### Skipping rows

When you want to skip a certain amount of rows you can use `->skipRows()` or `->limitRows(false, 10)`

    // Skip 10 results
    $reader->skipRows(10);

    // Skip 10 results with limit, but return all other rows
    $reader->limitRows(false, 10);

    // Skip and take
    $reader->skipRows(10)->takeRows(10);

##### Taking columns

When you only want to return the first x columns of a sheet, you can use `->takeColumns()` or `->limitColumns()`.

    // You can either use ->takeColumns()
    $reader->takeColumns(10);

    // Or ->limitColumns()
    $reader->limitColumns(10);

##### Skipping columns

When you want to skip a certain amount of columns you can use `->skipColumns()` or `->limitColumns(false, 10)`

    // Skip 10 results
    $reader->skipColumns(10);

    // Skip 10 results with limit, but return all other columns
    $reader->limitColumns(false, 10);

    // Skip and take
    $reader->skipColumns(10)->takeColumns(10);

### Result mutators

When you want to get an array instead of an object, you can use `->toArray()`.

    $reader->toArray();

When you want an object, you can alternativly (instead of get() or all()) use `->toObject()`.

    $reader->toObject();

### Displaying results

You can dump the results to a readable output by using `->dump()` or `->dd()`.

    // Dump the results
    $reader->dump();

    // Dump results and die
    $reader->dd();

### Iterating the results

You can iterate the results by using `->each()`.

    // Loop through all sheets
    $reader->each(function($sheet) {

        // Loop through all rows
        $sheet->each(function($row) {

        });

    });

> Alternatively you can also `foreach` the results.

---

## File: 2.1/import/select.md

# Selecting sheets and columns

### Selecting one specific sheet
If you want to select a single sheet, you can use `->selectSheets($name)`. Only that sheet will be loaded.

    Excel::selectSheets('sheet1')->load();

### Selecting multiple sheets
If you want to select multiple sheets inside your file, you can pass an array as the parameter;

    Excel::selectSheets('sheet1', 'sheet2')->load();

### Selecting sheets by index

    // First sheet
    Excel::selectSheetsByIndex(0)->load();

    // First and second sheet
    Excel::selectSheetsByIndex(0, 1)->load();

### Selecting columns

If you want to select only a couple of columns, you can use `->select($columns)` or pass an array as the first parameter of `->get($columns)`.

    // Select
    $reader->select(array('firstname', 'lastname'))->get();

    // Or
    $reader->get(array('firstname', 'lastname'));

> All get methods (like all(), first(), dump(), toArray(), ...) accept an array of columns.

---

## File: 2.1/reference-guide/borders.md

# Available border styles

| Style name  | PHPExcel class reference|
| ------------- |-----------------|
|none|PHPExcel_Style_Border::BORDER_NONE
|dashDot|PHPExcel_Style_Border::BORDER_DASHDOT
| dashDotDot|PHPExcel_Style_Border::BORDER_DASHDOTDOT
| dashed |PHPExcel_Style_Border::BORDER_DASHED
| dotted |PHPExcel_Style_Border::BORDER_DOTTED
| double |PHPExcel_Style_Border::BORDER_DOUBLE
| hair |PHPExcel_Style_Border::BORDER_HAIR
| medium |PHPExcel_Style_Border::BORDER_MEDIUM
| mediumDashDot |PHPExcel_Style_Border::BORDER_MEDIUMDASHDOT
| mediumDashDotDot |PHPExcel_Style_Border::BORDER_MEDIUMDASHDOTDOT
| mediumDashed |PHPExcel_Style_Border::BORDER_MEDIUMDASHED
| slantDashDot |PHPExcel_Style_Border::BORDER_SLANTDASHDOT
|  thick|PHPExcel_Style_Border::BORDER_THICK
|  thin|PHPExcel_Style_Border::BORDER_THIN

---

## File: 2.1/reference-guide/closures.md

# Closures

| Method  | Closure class |
| ------------- |-------------|
| create()      | Maatwebsite\Excel\Writers\LaravelExcelWriter |
| load()     | Maatwebsite\Excel\Readers\LaravelExcelReader    |
| batch | Maatwebsite\Excel\Readers\Batch     |
| sheet() | Maatwebsite\Excel\Classes\LaravelExcelWorksheet     |
| cells() | Maatwebsite\Excel\Writers\CellWriter     |
| row() | Maatwebsite\Excel\Writers\CellWriter    |

---

## File: 2.1/reference-guide/css-styles.md

# Available CSS styles

Styles that can be used inside an external CSS file or as inline CSS.

| Style name  | Example Value |
| ------------- |-------------|
| background(-color)      | #000000 |
| color     | #FFFFFF     |
| font-weight | bold     |
| font-style | italic     |
| font-weight | bold     |
| font-size | 20px     |
| font-family | Open Sans     |
| text-decoration | underline     |
| text-align | center    |
| vertical-align | middle     |
| border(-*) | 1px dashed #CCC     |
| width | 100(px)    |
| height | 1100(px) |

---

## File: 2.1/reference-guide/file-properties.md

# Available file properties

Properties that can be set with `$excel->set{$property}()`

| Property name  |
| ------------- |
|creator
|lastModifiedBy
|title
|description
|subject
|keywords
|category
|manager
|company

---

## File: 2.1/reference-guide/formatting.md

# Available column formatting

| Format name  | PHPExcel class reference|
| ------------- |-----------------|
|General|PHPExcel_Style_NumberFormat::FORMAT_GENERAL
|@|PHPExcel_Style_NumberFormat::FORMAT_TEXT
|0|PHPExcel_Style_NumberFormat::FORMAT_NUMBER
|0.00|PHPExcel_Style_NumberFormat::FORMAT_NUMBER_00
|#,##0.00|PHPExcel_Style_NumberFormat::FORMAT_NUMBER_COMMA_SEPARATED1
|#,##0.00_-|PHPExcel_Style_NumberFormat::FORMAT_NUMBER_COMMA_SEPARATED2
|0%|PHPExcel_Style_NumberFormat::FORMAT_PERCENTAGE
|0.00%|PHPExcel_Style_NumberFormat::FORMAT_PERCENTAGE_00
|yyyy-mm-dd|PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDD2
|yy-mm-dd|PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDD
|dd/mm/yy|PHPExcel_Style_NumberFormat::FORMAT_DATE_DDMMYYYY
|d/m/y|PHPExcel_Style_NumberFormat::FORMAT_DATE_DMYSLASH
|d-m-y|PHPExcel_Style_NumberFormat::FORMAT_DATE_DMYMINUS
|d-m|PHPExcel_Style_NumberFormat::FORMAT_DATE_DMMINUS
|m-y|PHPExcel_Style_NumberFormat::FORMAT_DATE_MYMINUS
|mm-dd-yy|PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX14
|d-mmm-yy|PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX15
|d-mmm|PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX16
|mmm-yy|PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX17
|m/d/yy h:mm|PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX22
|d/m/y h:mm|PHPExcel_Style_NumberFormat::FORMAT_DATE_DATETIME
|h:mm AM/PM|PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME1
|h:mm:ss AM/PM|PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME2
|h:mm|PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME3
|h:mm:ss|PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME4
|mm:ss|PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME5
|h:mm:ss|PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME6
|i:s.S|PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME7
|h:mm:ss;@|PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME8
|yy/mm/dd;@|PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDDSLASH
|"$"#,##0.00_-|PHPExcel_Style_NumberFormat::FORMAT_CURRENCY_USD_SIMPLE
|$#,##0_-|PHPExcel_Style_NumberFormat::FORMAT_CURRENCY_USD
|[$EUR ]#,##0.00_-|PHPExcel_Style_NumberFormat::FORMAT_CURRENCY_EUR_SIMPLE

---

## File: 2.1/reference-guide/sheet-properties.md

# Available sheet properties

Properties that can be set with `$sheet->set{$property}()`

| Property name  | Possible value|
| ------------- |-----------------|
|orientation| string
|paperSize| integer
|scale| integer
|fitToPage| boolean/int *
|fitToHeight| boolean/int *
|fitToWidth| boolean/int *
|columnsToRepeatAtLeft| array
|rowsToRepeatAtTop| array
|horizontalCentered| boolean
|verticalCentered| boolean
|printArea| range
|firstPageNumber| integer

* See [PHPExcel's Page Setup: Scaling options](https://github.com/PHPOffice/PHPExcel/blob/develop/Documentation/markdown/Overview/08-Recipes.md#page-setup-scaling-options) for more information

---

## File: 3.0/index.md

<meta http-equiv="refresh" content="0;url=/3.0/getting-started/" />

---

## File: 3.0/exports/collection.md

# Exporting collections

The easiest way to start an export is to create a custom export class. We'll use an invoices export as example.

Create a new class called `InvoicesExport` in `app/Exports`:

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\FromCollection;

class InvoicesExport implements FromCollection
{
    public function collection()
    {
        return Invoice::all();
    }
}
```

In your controller we can now download this export:

```php
public function export() 
{
    return Excel::download(new InvoicesExport, 'invoices.xlsx');
}
```

Or store it on a (e.g. s3) disk:

```php
public function storeExcel() 
{
    return Excel::store(new InvoicesExport, 'invoices.xlsx', 's3');
}
```

:bulb: More about storing exports can be found in the [storing exports on disk page](/3.0/exports/store.html).

### Dependency injection

In case your export needs dependencies, you can inject the export class:

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\FromCollection;

class InvoicesExport implements FromCollection
{
    public function __construct(InvoicesRepository $invoices)
    {
        $this->invoices = $invoices;
    }

    public function collection()
    {
        return $this->invoices->all();
    }
}
```

```php
public function export(Excel $excel, InvoicesExport $export) 
{
    return $excel->download($export, 'invoices.xlsx');
}
```

### Strict null comparisons

If you want your `0` values to be actual `0` values in your excel sheet instead of `null` (empty cells), you can use `WithStrictNullComparison`.

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithStrictNullComparison;

class InvoicesExport implements FromCollection, WithStrictNullComparison
{
    public function __construct(InvoicesRepository $invoices)
    {
        $this->invoices = $invoices;
    }

    public function collection()
    {
        return $this->invoices->all();
    }
}
```

### Collection macros

The package provides some macro to Laravel's collection class to easily download or store a collection.

#### Downloading a collection as Excel

```php
(new Collection([[1, 2, 3], [1, 2, 3]]))->downloadExcel(
    $filePath,
    $writerType = null,
    $headings = false
)
```

#### Storing a collection on disk

```php
(new Collection([[1, 2, 3], [1, 2, 3]]))->storeExcel(
    $filePath,
    $disk = null,
    $writerType = null,
    $headings = false
)
```

---

## File: 3.0/exports/column-formatting.md

# Formatting columns

You can easily format an entire column, by using `WithColumnFormatting`.
In case you want something more custom, it's suggested to use the `AfterSheet` event to directly interact with the underlying `Worksheet` class.

```php
namespace App\Exports;

use PhpOffice\PhpSpreadsheet\Shared\Date;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
use Maatwebsite\Excel\Concerns\WithColumnFormatting;
use Maatwebsite\Excel\Concerns\WithMapping;

class InvoicesExport implements WithColumnFormatting, WithMapping
{
    public function map($invoice): array
    {
        return [
            $invoice->invoice_number,
            Date::dateTimeToExcel($invoice->created_at),
            $invoice->total
        ];
    }
    
    /**
     * @return array
     */
    public function columnFormats(): array
    {
        return [
            'B' => NumberFormat::FORMAT_DATE_DDMMYYYY,
            'C' => NumberFormat::FORMAT_CURRENCY_EUR_INTEGER,
        ];
    }
}
```

### Dates

When working with dates, it's recommended to use `\PhpOffice\PhpSpreadsheet\Shared\Date::dateTimeToExcel()` in your mapping
to ensure correct parsing of dates.

### Auto size

If you want Laravel Excel to perform an automatic width calculation, use the following code. 

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\ShouldAutoSize;

class InvoicesExport implements ShouldAutoSize
{
    ...
}
```

---

## File: 3.0/exports/concerns.md

# Export concerns

| Interface | Explanation |
|---- |----|
|`Maatwebsite\Excel\Concerns\FromCollection`| Use a Laravel Collection to populate the export. |
|`Maatwebsite\Excel\Concerns\FromQuery`| Use an Eloquent query to populate the export. | 
|`Maatwebsite\Excel\Concerns\FromView`| Use a (Blade) view to populate the export. |
|`Maatwebsite\Excel\Concerns\WithTitle`| Set the Workbook or Worksheet title. |
|`Maatwebsite\Excel\Concerns\WithHeadings`| Prepend a heading row. |
|`Maatwebsite\Excel\Concerns\WithMapping`| Format the row before it's written to the file. |
|`Maatwebsite\Excel\Concerns\WithColumnFormatting`| Format certain columns. |
|`Maatwebsite\Excel\Concerns\WithMultipleSheets`| Enable multi-sheet support. Each sheet can have its own concerns (except this one). |
|`Maatwebsite\Excel\Concerns\ShouldAutoSize`| Auto-size the columns in the worksheet. |
|`Maatwebsite\Excel\Concerns\WithStrictNullComparison`| Uses strict comparisions when testing cells for null value. |
|`Maatwebsite\Excel\Concerns\WithEvents`| Register events to hook into the PhpSpreadsheet process. |
|`Maatwebsite\Excel\Concerns\WithCustomQuerySize`| Allows Exportables that implement the FromQuery concern, to provide their own custom query size. |
|`Maatwebsite\Excel\Concerns\WithCustomCsvSettings`| Allows to run custom Csv settings for this specific exportable. |
|`Maatwebsite\Excel\Concerns\WithCharts`| Allows to run one or multiple PhpSpreadsheet Chart instances. |
|`Maatwebsite\Excel\Concerns\WithDrawings`| Allows to run one or multiple PhpSpreadsheet (Base)Drawing instances. |
|`Maatwebsite\Excel\Concerns\WithCustomStartCell`| Allows to specify a custom start cell. Do note that this is only supported for FromCollection exports. |

### Traits

| Trait | Explanation |
|---- |----|
|`Maatwebsite\Excel\Concerns\Exportable` | Add download/store abilities right on the export class itself.
|`Maatwebsite\Excel\Concerns\RegistersEventListeners` | Auto-register the available event listeners. |

---

## File: 3.0/exports/export-formats.md

# Export formats

By default the export format is determined by the extension of the file, however if you want 
to explicitly configured this, you can pass through the export format as 2nd parameter. 

## XLSX

```php
(new InvoicesExport)->download('invoices.xlsx', \Maatwebsite\Excel\Excel::XLSX);
```

## CSV

```php
(new InvoicesExport)->download('invoices.csv', \Maatwebsite\Excel\Excel::CSV);
```

## TSV

```php
(new InvoicesExport)->download('invoices.tsv', \Maatwebsite\Excel\Excel::TSV);
```

## ODS

```php
(new InvoicesExport)->download('invoices.ods', \Maatwebsite\Excel\Excel::ODS);
```

## XLS

```php
(new InvoicesExport)->download('invoices.xls', \Maatwebsite\Excel\Excel::XLS);
```

## SLK

```php
(new InvoicesExport)->download('invoices.slk', \Maatwebsite\Excel\Excel::SLK);
```

## XML

```php
(new InvoicesExport)->download('invoices.xml', \Maatwebsite\Excel\Excel::XML);
```

## GNUMERIC

```php
(new InvoicesExport)->download('invoices.gnumeric', \Maatwebsite\Excel\Excel::GNUMERIC);
```

## HTML

```php
(new InvoicesExport)->download('invoices.html', \Maatwebsite\Excel\Excel::HTML);
```

## MPDF

```php
(new InvoicesExport)->download('invoices.pdf', \Maatwebsite\Excel\Excel::MPDF);
```

## DOMPDF

```php
(new InvoicesExport)->download('invoices.pdf', \Maatwebsite\Excel\Excel::DOMPDF);
```

## TCPDF

```php
(new InvoicesExport)->download('invoices.pdf', \Maatwebsite\Excel\Excel::TCPDF);
```

---

## File: 3.0/exports/exportables.md

# Exportables

In the previous example, we used the `Excel::download` facade to start an export. 

Laravel Excel also provides a `Maatwebsite\Excel\Concerns\Exportable` trait, to make export classes exportable.

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\Exportable;

class InvoicesExport implements FromCollection
{
    use Exportable;

    public function collection()
    {
        return Invoice::all();
    }
}
```

We can now download the export without the need for the facade:

```php
return (new InvoicesExport)->download('invoices.xlsx');
```

Or store it on a disk:

```php
return (new InvoicesExport)->store('invoices.xlsx', 's3');
```

### Responsable

The previous example can be made even shorter when adding Laravel's `Responsable` interface to the export class:

```php
namespace App\Exports;

use Illuminate\Contracts\Support\Responsable;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\Exportable;

class InvoicesExport implements FromCollection, Responsable
{
    use Exportable;
    
    /**
    * It's required to define the fileName within
    * the export class when making use of Responsable.
    */
    private $fileName = 'invoices.xlsx';

    public function collection()
    {
        return Invoice::all();
    }
}
```

You can now easily return the export class, without the need of calling `->download()`.

```php
return new InvoicesExport();
```

---

## File: 3.0/exports/extending.md

# Extending

[[toc]]

## Events

The export process has a few events you can leverage to interact with the underlying 
classes to add custom behaviour to the export.

You are able to hook into the parent package by using events.
No need to use convenience methods like "query" or "view", if you need full control over the export.

The events will be activated by adding the `WithEvents` concern. Inside the `registerEvents` method, you 
will have to return an array of events. The key is the Fully Qualified Name (FQN) of the event and the value is a callable event listener.
This can either be a closure, array-callable or invokable class.

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Events\BeforeExport;
use Maatwebsite\Excel\Events\BeforeWriting;
use Maatwebsite\Excel\Events\BeforeSheet;

class InvoicesExport implements WithEvents
{
    /**
     * @return array
     */
    public function registerEvents(): array
    {
        return [
            // Handle by a closure.
            BeforeExport::class => function(BeforeExport $event) {
                $event->writer->getProperties()->setCreator('Patrick');
            },
            
            // Array callable, refering to a static method.
            BeforeWriting::class => [self::class, 'beforeWriting'],
            
            // Using a class with an __invoke method.
            BeforeSheet::class => new BeforeSheetHandler()
        ];
    }
    
    public static function beforeWriting(BeforeWriting $event) 
    {
        //
    }
}
```

Do note that using a `Closure` will not be possible in combination with queued exports, as PHP cannot serialize the closure.
In those cases it might be better to use the `RegistersEventListeners` trait.

### Auto register event listeners

By using the `RegistersEventListeners` trait you can auto-register the event listeners,
without the need of using the `registerEvents`. The listener will only be registered if the method is created. 

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Concerns\RegistersEventListeners;
use Maatwebsite\Excel\Events\BeforeExport;
use Maatwebsite\Excel\Events\BeforeWriting;
use Maatwebsite\Excel\Events\BeforeSheet;
use Maatwebsite\Excel\Events\AfterSheet;

class InvoicesExport implements WithEvents
{
    use Exportable, RegistersEventListeners;
    
    public static function beforeExport(BeforeExport $event)
    {
        //
    }

    public static function beforeWriting(BeforeWriting $event)
    {
        //
    }

    public static function beforeSheet(BeforeSheet $event)
    {
        //
    }

    public static function afterSheet(AfterSheet $event)
    {
        //
    }
}
```

### Global event listeners

Event listeners can also be configured globally, if you want to perform the same actions on all exports in your app.
You can add them to e.g. your `AppServiceProvider` in the `register()` method.

```php
Writer::listen(BeforeExport::class, function () {
    //
});

Writer::listen(BeforeWriting::class, function () {
    //
});

Sheet::listen(BeforeSheet::class, function () {
    //
});

Sheet::listen(AfterSheet::class, function () {
    //
});
```

### Available events

| Event name | Payload | Explanation |
|---- |----| ----|
|`Maatwebsite\Excel\Events\BeforeExport` | `$event->writer : Writer` | Event gets raised at the start of the process. | 
| `Maatwebsite\Excel\Events\BeforeWriting` | `$event->writer : Writer` | Event gets raised before the download/store starts. |
| `Maatwebsite\Excel\Events\BeforeSheet` | `$event->sheet : Sheet` | Event gets raised just after the sheet is created. |
| `Maatwebsite\Excel\Events\AfterSheet` | `$event->sheet : Sheet` | Event gets raised at the end of the sheet process. |

## Custom Concerns

You can add custom concerns to your app. This can be useful if you want to share some concerns over a few projects or want to open source your custom concerns.

Let's add a `WithCustomProperties` concern to your app. You could add these concerns to `app/Exports/Concerns`, but any location will do as long as it can be auto-loaded by composer.

```php
namespace App\Exports\Concerns;

interface WithCustomProperties
{
    /**
     *
     * @return string
     */
    public function description(): string;
}
```

Next to this concern we will create a concern handler. `WithCustomerPropertiesHandler`. This class can also be added to `app/Exports/Concerns`, but is again completely free of choice. 
A concern handler is basically just an invokable class. It receives your exportable object and either a `Writer` or `Sheet` object, depending on the choosen event.

```php
namespace App\Exports\Concerns;

use App\Exports\Concerns\WithCustomProperties;
use Maatwebsite\Excel\Writer;

class WithCustomPropertiesHandler
{
    /**
     * @param WithCustomProperties $exportable
     * @param Writer               $writer
     */
    public function __invoke(WithCustomProperties $exportable, Writer $writer)
    {
        $writer
            ->getDelegate()
            ->getProperties()
            ->setDescription(
                $exportable->description()
            );
    }
}
```

We then will register this concern in a service provider. You could use `app/Providers/AppServiceProvider` for this.

```php
public function register()
{
    Excel::extend(WithCustomProperties::class, new WithCustomPropertiesHandler);
}
```

:bulb: `::extend` accepts a callable as second parameter. It's also possible to pass a closure.

```php
public function register()
{
    Excel::extend(WithCustomProperties::class, function(WithCustomProperties $exportable, Writer $writer) {
        $writer->getDelegate()->getProperties()->setDescription($exportable->description());
    });
}
```

You can also bind concern handlers to different hooks. By default a concern handler is always bound to the `BeforeWriting` event. You can easily customize this, by supplying a 3rd parameter.

```php
public function register()
{
    Excel::extend(WithCustomProperties::class, new WithCustomPropertiesHandler, BeforeExport::class);
}
```

## Macroable

Both `Writer` and `Sheet` are "macroable" which means they can easily be extended to fit your needs. 
Both Writer and Sheet have a `->getDelegate()` method which returns the underlying PhpSpreadsheet class. 
This will allow you to add custom macros as shortcuts to PhpSpreadsheet methods that are not available in this package. 

### Writer

```php
use \Maatwebsite\Excel\Writer;

Writer::macro('setCreator', function (Writer $writer, string $creator) {
    $writer->getDelegate()->getProperties()->setCreator($creator);
});
```

### Sheet

```php
use \Maatwebsite\Excel\Sheet;

Sheet::macro('setOrientation', function (Sheet $sheet, $orientation) {
    $sheet->getDelegate()->getPageSetup()->setOrientation($orientation);
});
```

### Customize  
You can create your own macro to add custom methods to a spreadsheet instance. 

For example, to add styling to a cell, we first create a macro, let's call it `styleCells`:


```php
use \Maatwebsite\Excel\Sheet;

Sheet::macro('styleCells', function (Sheet $sheet, string $cellRange, array $style) {
    $sheet->getDelegate()->getStyle($cellRange)->applyFromArray($style);
});
```

Once the macro is created, it can be used inside the `registerEvents()` method as such:

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Events\BeforeExport;
use Maatwebsite\Excel\Events\AfterSheet;

class InvoicesExport implements WithEvents
{
    /**
     * @return array
     */
    public function registerEvents(): array
    {
        return [
            BeforeExport::class  => function(BeforeExport $event) {
                $event->writer->setCreator('Patrick');
            },
            AfterSheet::class    => function(AfterSheet $event) {
                $event->sheet->setOrientation(\PhpOffice\PhpSpreadsheet\Worksheet\PageSetup::ORIENTATION_LANDSCAPE);

                $event->sheet->styleCells(
                    'B2:G8',
                    [
                        'borders' => [
                            'outline' => [
                                'borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THICK,
                                'color' => ['argb' => 'FFFF0000'],
                            ],
                        ]
                    ]
                );
            },
        ];
    }
}
```

Feel free to use the above macro, or be creative and invent your own!

For PhpSpreadsheet methods, please refer to their documentation: https://phpspreadsheet.readthedocs.io/

---

## File: 3.0/exports/from-query.md

# From Query

In the previous example, we did the query inside the export class. 
While this is a good solution for small exports, 
for bigger exports this will come at a hefty performance price.

By using the `FromQuery` concern, we can prepare a query for an export. Behind the scenes this query is executed in chunks.

In the `InvoicesExport` class, add the `FromQuery` concern, and return a query. Be sure to not `->get()` the results!

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\Exportable;

class InvoicesExport implements FromQuery
{
    use Exportable;

    public function query()
    {
        return Invoice::query();
    }
}
```

We can still download the export in the same way:

```php
return (new InvoicesExport)->download('invoices.xlsx');
```

### Customizing the query

It's easy to pass custom parameters to the query, 
by simply passing them as dependencies to the export class.

#### As constructor param

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\Exportable;

class InvoicesExport implements FromQuery
{
    use Exportable;

    public function __construct(int $year)
    {
        $this->year = $year;
    }

    public function query()
    {
        return Invoice::query()->whereYear('created_at', $this->year);
    }
}
```

The year can now be passed as dependency to the export class:

```php
return (new InvoicesExport(2018))->download('invoices.xlsx');
```

#### As setter

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\Exportable;

class InvoicesExport implements FromQuery
{
    use Exportable;

    public function forYear(int $year)
    {
        $this->year = $year;
        
        return $this;
    }

    public function query()
    {
        return Invoice::query()->whereYear('created_at', $this->year);
    }
}
```

We can adjust the year by using the `forYear` method:

```php
return (new InvoicesExport)->forYear(2018)->download('invoices.xlsx');
```

---

## File: 3.0/exports/from-view.md

# From View

Exports can be created from a Blade view, by using the `FromView` concern.

```php
namespace App\Exports;

use Illuminate\Contracts\View\View;
use Maatwebsite\Excel\Concerns\FromView;

class InvoicesExport implements FromView
{
    public function view(): View
    {
        return view('exports.invoices', [
            'invoices' => Invoice::all()
        ]);
    }
}
```

It will convert an HTML table into an Excel spreadsheet. For example; `users.blade.php`:

```
<table>
    <thead>
    <tr>
        <th>Name</th>
        <th>Email</th>
    </tr>
    </thead>
    <tbody>
    @foreach($users as $user)
        <tr>
            <td>{{ $user->name }}</td>
            <td>{{ $user->email }}</td>
        </tr>
    @endforeach
    </tbody>
</table>
```

---

## File: 3.0/exports/index.md

## :rocket: 5 minute quick start

:muscle: Create an export class in `app/Exports`

You may do this by using the `make:export` command.

```
php artisan make:export UsersExport --model=User
```

If you prefer to create the export manually, you can create the following in `app/Exports`:

```php
<?php

namespace App\Exports;

use App\User;
use Maatwebsite\Excel\Concerns\FromCollection;

class UsersExport implements FromCollection
{
    public function collection()
    {
        return User::all();
    }
}
```

:fire: In your controller you can call this export now:

```php

use App\Exports\UsersExport;
use Maatwebsite\Excel\Facades\Excel;
use App\Http\Controllers\Controller;

class UsersController extends Controller 
{
    public function export() 
    {
        return Excel::download(new UsersExport, 'users.xlsx');
    }
}
```

:page_facing_up: Find your `users.xlsx` in your downloads folder!

---

## File: 3.0/exports/mapping.md

# Mapping data

### Mapping rows

By adding `WithMapping` you map the data that needs to be added as row. This way you have control over the actual source for each column.
In case of using the Eloquent query builder: 

```php

use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithMapping;

class InvoicesExport implements FromQuery, WithMapping
    
    /**
    * @var Invoice $invoice
    */
    public function map($invoice): array
    {
        return [
            $invoice->invoice_number,
            Date::dateTimeToExcel($invoice->created_at),
        ];
    }
}
```

### Adding a heading row

A heading row can easily be added by adding the `WithHeadings` concern. The heading row will be added
as very first row of the sheet.

```php

use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;

class InvoicesExport implements FromQuery, WithHeadings
    
    public function headings(): array
    {
        return [
            '#',
            'Date',
        ];
    }
}
```

---

## File: 3.0/exports/multiple-sheets.md

# Multiple Sheets

To allow the export to have multiple sheets, the `WithMultipleSheets` concern should be used. 
The `sheets()` method expects an array of sheet export objects to be returned.

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\WithMultipleSheets;

class InvoicesExport implements WithMultipleSheets
{
    use Exportable;

    protected $year;
    
    public function __construct(int $year)
    {
        $this->year = $year;
    }

    /**
     * @return array
     */
    public function sheets(): array
    {
        $sheets = [];

        for ($month = 1; $month <= 12; $month++) {
            $sheets[] = new InvoicesPerMonthSheet($this->year, $month);
        }

        return $sheets;
    }
}
```

The `InvoicesPerMonthSheet` can implement concerns like `FromQuery`, `FromCollection`, ... 

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithTitle;

class InvoicesPerMonthSheet implements FromQuery, WithTitle
{
    private $month;
    private $year;

    public function __construct(int $year, int $month)
    {
        $this->month = $month;
        $this->year  = $year;
    }

    /**
     * @return Builder
     */
    public function query()
    {
        return Invoice
            ::query()
            ->whereYear('created_at', $this->year)
            ->whereMonth('created_at', $this->month);
    }

    /**
     * @return string
     */
    public function title(): string
    {
        return 'Month ' . $this->month;
    }
}
```

This will now download an xlsx of all invoices in 2018, with 12 worksheets representing each month of the year.

```php
public function download() 
{
    return (new InvoicesExport(2018))->download('invoices.xlsx');
}
```

---

## File: 3.0/exports/queued.md

# Queued

In case you are working with a lot of data, it might be wise to queue the entire process. 

Given we have the following export class:

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromQuery;

class InvoicesExport implements FromQuery
{
    use Exportable;

    public function query()
    {
        return Invoice::query();
    }
}
```

It's as easy as calling `->queue()` now.

```php
(new InvoicesExport)->queue('invoices.xlsx');

return back()->withSuccess('Export started!');
```

Behind the scenes the query will be chunked and multiple jobs will be chained. These jobs will be executed in the correct order,
and will only execute if none of the previous have failed. 

### Implicit Export queueing

You can also mark an export implicitly as a queued export. You can do this by using Laravel's `ShouldQueue` contract.

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromQuery;
use Illuminate\Contracts\Queue\ShouldQueue;

class InvoicesExport implements FromQuery, ShouldQueue
{
    use Exportable;

    public function query()
    {
        return Invoice::query();
    }
}
```

In your controller you can now call the normal `->store()` method. 
Based on the presence of the `ShouldQueue` contract, the export will be queued.

```php
(new InvoicesExport)->store('invoices.xlsx');
```

### Appending jobs

The `queue()` method returns an instance of Laravel's `PendingDispatch`. This means you can chain extra jobs that will be added to the end of the queue and only executed if all export jobs are correctly executed.

```php
(new InvoicesExport)->queue('invoices.xlsx')->chain([
    new NotifyUserOfCompletedExport(request()->user()),
]);
```

```php
namespace App\Jobs;

use App\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\SerializesModels;

class NotifyUserOfCompletedExport implements ShouldQueue
{
    use Queueable, SerializesModels;
    
    public $user;
    
    public function __construct(User $user)
    {
        $this->user = $user;
    }

    public function handle()
    {
        $this->user->notify(new ExportReady());
    }
}
```

### Custom queues

Because `PendingDispatch` is returned, we can also change the queue that should be used.

```php
(new InvoicesExport)->queue('invoices.xlsx')->allOnQueue('exports');
```

---

## File: 3.0/exports/store.md

# Storing exports on disk

Exports can easily be stored on any [filesystem](https://laravel.com/docs/5.6/filesystem) that Laravel supports.

```php
public function storeExcel() 
{
    // Store on default disk
    Excel::store(new InvoicesExport(2018), 'invoices.xlsx');
    
    // Store on a different disk (e.g. s3)
    Excel::store(new InvoicesExport(2018), 'invoices.xlsx', 's3');
    
    // Store on a different disk with a defined writer type. 
    Excel::store(new InvoicesExport(2018), 'invoices.xlsx', 's3', Excel::XLSX);
}
```

---

## File: 3.0/exports/testing.md

# Testing

The Excel facade can be used to swap the exporter to a fake.

### Testing downloads

```php
/**
* @test
*/
public function user_can_download_invoices_export() 
{
    Excel::fake();

    $this->actingAs($this->givenUser())
         ->get('/invoices/download/xlsx');

    Excel::assertDownloaded('filename.xlsx', function(InvoicesExport $export) {
        // Assert that the correct export is downloaded.
        return $export->collection()->contains('#2018-01');
    });
}
```

### Testing storing exports

```php
/**
* @test
*/
public function user_can_store_invoices_export() 
{
    Excel::fake();

    $this->actingAs($this->givenUser())
         ->get('/invoices/store/xlsx');

    Excel::assertStored('filename.xlsx', 'diskName');
    
    Excel::assertStored('filename.xlsx', 'diskName', function(InvoicesExport $export) {
        return true;
    });
    
    // When passing the callback as 2nd param, the disk will be the default disk.
    Excel::assertStored('filename.xlsx', function(InvoicesExport $export) {
        return true;
    });
}
```

### Testing queuing exports

```php
/**
* @test
*/
public function user_can_queue_invoices_export() 
{
    Excel::fake();

    $this->actingAs($this->givenUser())
         ->get('/invoices/queue/xlsx');

    Excel::assertQueued('filename.xlsx', 'diskName');
    
    Excel::assertQueued('filename.xlsx', 'diskName', function(InvoicesExport $export) {
        return true;
    });
    
    // When passing the callback as 2nd param, the disk will be the default disk.
    Excel::assertQueued('filename.xlsx', function(InvoicesExport $export) {
        return true;
    });
}
```

---

## File: 3.0/getting-started/contributing.md

# Contributing

[[toc]]

Please read and understand the contribution guide before creating an issue or pull request.

## Important Links

- [Docs](https://docs.laravel-excel.com)
- [Issue tracker](https://github.com/SpartnerNL/Laravel-Excel/issues)
- [Support](/3.0/getting-started/support.html)

## Etiquette

This project is an open source project, and as such, the maintainers use their free time to build and maintain it.
The code is freely available and can be used, forked and modified. 

Please be considerate towards maintainers when raising issues or presenting pull requests. 

It's the duty of the maintainer to ensure that all submissions to the project are of sufficient
quality to benefit the project. Many developers have different skill sets, strengths, and weaknesses. Respect the maintainer's decision, and do not be upset or abusive if your submission is not used.

## Viability

When requesting or submitting new features, first consider whether it might be useful to others. Open
source projects are used by many developers, who may have entirely different needs to your own. Think about
whether or not your feature is likely to be used by other users of the project.

## How to submit changes?

- Check the codebase to ensure that your feature doesn't already exist.
- Check the pull requests to ensure that another person hasn't already submitted the feature or fix.
- Use the [pull request template](https://github.com/SpartnerNL/Laravel-Excel/blob/3.0/.github/PULL_REQUEST_TEMPLATE.md).

## How to report a bug?

- Attempt to replicate the problem, to ensure that it wasn't a coincidental incident.
- Check to make sure your bug report isn't already present within the project.
- Check the pull requests tab to ensure that the bug doesn't have a fix in progress.
- Check the pull requests tab to ensure that the feature isn't already in progress.
- Use the [issue template](https://github.com/SpartnerNL/Laravel-Excel/blob/3.0/.github/ISSUE_TEMPLATE.md).

## Requirements

- **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)**. - Style will get automatically fixed by StyleCI.
- **Add tests backing up your change!** - You can run the test by running `vendor/bin/phpunit`
- **Document any change in behaviour** - Documentation is located in the [https://github.com/SpartnerNL/laravel-excel-docs](https://github.com/SpartnerNL/laravel-excel-docs)
- **One feature per Pull Request**
- **Add meaningful commit messages**

---

## File: 3.0/getting-started/index.md

# Introduction

:rocket: Laravel Excel is intended at being Laravel-flavoured PhpSpreadsheet: a simple, but elegant wrapper around PhpSpreadsheet with the goal of simplifying
exports. 

:fire: [PhpSpreadsheet](https://phpspreadsheet.readthedocs.io/) is a library written in pure PHP and providing a set of classes that allow you to read from and to write to different spreadsheet file formats, like Excel and LibreOffice Calc.

Laravel Excel features:

* Easily export collections to Excel
* Export queries with automatic chunking for better performance
* Queue exports for better performance
* Easily export Blade views to Excel

---

## File: 3.0/getting-started/installation.md

# Installation

## Requirements

* PHP: `^7.0`
* Laravel: `^5.5`
* PhpSpreadsheet: `^1.2`
* PHP extension `php_zip` enabled
* PHP extension `php_xml` enabled
* PHP extension `php_gd2` enabled

## Installation

Require this package in the `composer.json` of your Laravel project. This will download the package and PhpSpreadsheet.

```
composer require maatwebsite/excel
```

The `Maatwebsite\Excel\ExcelServiceProvider` is __auto-discovered__ and registered by default, but if you want to register it yourself:

Add the ServiceProvider in `config/app.php`:

```php
'providers' => [
    /*
     * Package Service Providers...
     */
    Maatwebsite\Excel\ExcelServiceProvider::class,
]
```

The `Excel` facade is also __auto-discovered__, but if you want to add it manually:

Add the Facade in `config/app.php`:

```php
'aliases' => [
    ...
    'Excel' => Maatwebsite\Excel\Facades\Excel::class,
]
```

To publish the config, run the vendor publish command:

```
php artisan vendor:publish
```

This will create a new config file named `config/excel.php`.

## Usage

Laravel Excel can be used in a various of ways. I'm sure you will find your prefered of using it. This can be either via dependency injection or if you prefer you can even use a facade.

### Via dependency injection

You can inject the `Excel` manager class into your class, either via constructor injection or method injection in case of a controller.

```php
use App\YourExport;
use Maatwebsite\Excel\Excel;

class YourController
{
    private $excel;

    public function __construct(Excel $excel)
    {
        $this->excel = $excel;
    }
    
    public function export()
    {
        return $this->excel->download(new YourExport);
    }
}
```

### Via Exporter interface

You can also use the `Maatwebsite\Excel\Exporter` to decouple more from the concrete Excel manager implementation.

```php
use App\YourExport;
use Maatwebsite\Excel\Exporter;

class YourController
{
    private $exporter;

    public function __construct(Exporter $exporter)
    {
        $this->exporter = $exporter;
    }
    
    public function export()
    {
        return $this->exporter->download(new YourExport);
    }
}
```

### Via the Facade

If you prefer facades, you can you use the `Maatwebsite\Excel\Facades\Excel` facade or if you use the alias the `Excel` facade alias.

```php
use App\YourExport;
use Maatwebsite\Excel\Facades\Excel;

class YourController
{
    public function export()
    {
        return Excel::download(new YourExport);
    }
}
```

### Via container binding

If you want to bind the `Excel` manager to your own class via a container binding, you can use the `excel` container binding.

```php
$this->app->bind(YourCustomExporter::class, function() {
    return new YourCustomExporter($this->app['excel']);
});
```

---

## File: 3.0/getting-started/license.md

# License

Our software is open source and licensed under the [MIT license](https://choosealicense.com/licenses/mit/). According to the [postcardware](https://en.wikipedia.org/wiki/Postcardware) concept, if you use the software for your project(s) we would appreciate to receive a postcard of your hometown. Please send it to:

**Spartner**  
Florijnruwe 111-2  
6218 CA Maastricht  
The Netherlands  

You are free to use the software as you like. The code can be forked and modified, but the original copyright author should always be included!

::: warning Support
We hold no liability and will provide support on a best effort basis. For more information about support please see [support](/3.0/getting-started/support).
:::

:rocket: If you use the software commercially and need support urgently, we can offer this on a commercial basis. Please contact  or phone +31 (0)10 744 9312.

---

## File: 3.0/getting-started/support.md

# Support

[[toc]]

Our software is free and open source, meaning that the use of our software is optional. We hold no liability and there is no obligation to support. We will provide support on a best effort basis. 

If you use the software commercially and need elaborate support or need it urgently, we can offer this on a commercial basis. Please contact  or via phone +31 (0)10 744 9312.

## Supported Versions

Versions will be supported for a limited amount of time.

| Version | Laravel Version | Php Version | Support |
|---- |----|----|----|
| 2.1 | <=5.6 | <=7.0 | EOL since 15-05-2018 |
| 3.0 | ^5.5 |  ^7.0 | New features |

::: warning PHP version support
Support for PHP versions will only be maintained for a period of six months beyond the end-of-life of that PHP version.
:::


## Requesting support
Before you request support, please check the following:
* Attempt to replicate the problem, to ensure that it wasn't a coincidental incident.
* Check to make sure your support request isn't already present within the project.
* Check the pull requests tab to ensure that the bug doesn't have a fix in progress.
* Use the [issue template](https://github.com/SpartnerNL/Laravel-Excel/blob/3.0/.github/ISSUE_TEMPLATE.md).

Filling out the template is required. Issues that do not include enough information might not  be picked up. Please write in English (or Dutch).

Please prefix your issue with one of the following: [BUG] [PROPOSAL] [QUESTION].

And please be considerate towards maintainers when raising issues.

---

## File: 3.0/getting-started/upgrade.md

# Upgrade Guide

[[toc]]

## Upgrading to 3.0 from 2.1

Version 3.0 is not backwards compatible with 2.*. It's not possible to provide a step-by-step migration guide as it's a complete paradigm shift.

__New dependencies__

3.0 introduces some new dependencies.

* Requires PHP 7.0 or higher.
* Requires Laravel 5.5 (or higher).
* Requires PhpSpreadsheet instead of PHPExcel.

__Deprecations__

ALL Laravel Excel 2.* methods are deprecated and will not be able to use in 3.0 . 

- Excel::load() is removed and will not be re-added until 3.1
- Excel::create() is removed and replaced by Excel::download/Excel::store($yourExport)
- 3.0 provides no convenience methods for styling, you are encouraged to use PhpSpreadsheets native methods.

---

## File: 3.1/index.md

<meta http-equiv="refresh" content="0;url=/3.1/getting-started/" />

---

## File: 3.1/architecture/concerns.md

# Concerns

[[toc]]

Most of the export/import configuration is done by using **Concerns**. 

## Contracts

Concerns are basically just simple interfaces. Implementing them will make the object adhere to a 
certain contract. This contract can request specific methods that e.g. data can be passed through.

For instance, the `FromCollection` requests the Export object to implement a `collection` method, that needs to return a `Collection` instance.

```php
namespace App\Exports;

use App\User;
use Maatwebsite\Excel\Concerns\FromCollection;

class UsersExport implements FromCollection
{
    public function collection()
    {
        return User::all();
    }
}
```

## Pointer interface

In other cases it might not ask for any methods to be implemented, but merely functions as a pointer interface.

For instance, the `ShouldAutoSize` concern doesn't pass on any specific information, but does tell the Export process that the columns need to be automatically sized.

```php
namespace App\Exports;

use App\User;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;

class UsersExport implements ShouldAutoSize
{

}
```

---

## File: 3.1/architecture/index.md

# Lifecycle

[[toc]]

## Introduction

When using a package in your application, it's good to understand how the package functions behind the scenes. 
Understanding the behind-the-scenes will make you feel more comfortable and confident using the maximum potential of the tool.

The goal of this page is to give you a high-level overview of how Laravel Excel works. 

## Exports Lifecycle Overview

This section will try to give you an overview of how the export works behind the scenes.

### Export Object

Everything starts with the `Export` object. This object **encapsulates** your entire export logic. 
It both configures and handles the export logic.

A simple example of an export object is:

```php
<?php

namespace App\Exports;

use App\User;
use Maatwebsite\Excel\Concerns\FromCollection;

class UsersExport implements FromCollection
{
    public function collection()
    {
        return User::all();
    }
}
```

If you want to read more about export objects, go to the architecture page of [export objects](/3.1/architecture/objects.html).

### Passing on the Export object

Next the Export object will be passed on to the Laravel Excel package. The main entry point for this is the `Maatwebsite/Excel/Excel` class. This class can be called in multiple ways.

#### Facade

The easiest way to work with the `Excel` class is to use the `Maatwebsite\Excel\Facades\Excel` facade. 
If you use [auto-discovery](https://laravel.com/docs/packages#package-discovery), you can use the alias `\Excel` directly instead of using the fully qualified namespace.

#### Dependency injection

You can inject the `Maatwebsite/Excel/Excel` manager class into your class, either via constructor injection 
or method injection in case of a controller.

```php
<?php
use App\Exports\UsersExport;
use Maatwebsite\Excel\Excel;

class ExportController
{
    private $excel;

    public function __construct(Excel $excel)
    {
        $this->excel = $excel;
    }
    
    public function exportViaConstructorInjection()
    {
        return $this->excel->download(new UsersExport, 'users.xlsx');
    }
    
    public function exportViaMethodInjection(Excel $excel)
    {
        return $excel->download(new UsersExport, 'users.xlsx');
    }
}
```

#### Contract

You can also use the `Maatwebsite\Excel\Exporter` interface to decouple more from the concrete Excel manager implementation. The contract offers the same methods as the `Excel` class. 
It will make it easier to e.g. stub out the Exporter in your unit tests. The `Exporter` contract can be either injected via the constructor or a method in a controller.

```php
use App\Exports\UsersExport;
use Maatwebsite\Excel\Exporter;

class ExportsController
{
    private $exporter;

    public function __construct(Exporter $exporter)
    {
        $this->exporter = $exporter;
    }
    
    public function export()
    {
        return $this->exporter->download(new UsersExport, 'users.xlsx');
    }
}
```

#### Container binding

If you want to bind the `Maatwebsite\Excel\Excel` manager to your own class via a container binding, you can use the `excel` container binding.

```php
$this->app->bind(YourCustomExporter::class, function() {
    return new YourCustomExporter($this->app['excel']);
});
```

#### Exportable trait

If you prefer a sprinkle of magic, you can use the `Maatwebsite\Excel\Concerns\Exportable` trait in your `Export` object. This trait will expose a couple of methods that will make it possible to directly export an `Export` object.

```php
namespace App\Exports;

use App\User;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\Exportable;

class UsersExport implements FromCollection
{
    use Exportable;

    public function collection()
    {
        return User::all();
    }
}
```

You can now download the export without the need for the `facade` or `Excel` manager.

```php
return (new UsersExport)->download('users.xlsx');
```

Read more about the exportable trait in the [exportables](/3.1/exports/exportables.html) docs.

### Handling the Export object

#### Writer type detection

After using one of the above methods to pass on the `Export` object to the `Excel` manager, it will try to figure out what export it needs to be generated to. 
This will be either based on the extension of the file, the explicitly passed writer type. You can find the extension to writer type mapping in the `excel.php` config, in the `extension_detector` section. 
In case no writer type can be detected, a `Maatwebsite\Excel\Exceptions\NoTypeDetectedException` exception is thrown and the export process will be stopped.

#### Starting the Writing process

The `Excel` manager will then delegate the handling to the `Maatwebsite\Excel\Writer`. The first action of the `Writer` is to register the event listeners that are registered. 
Next it will create a new `PhpOffice\PhpSpreadsheet\Spreadsheet` instance that we will use to convert our `Export` object to.

The first event raised is the `BeforeExport` event. This is raised just after the `Spreadsheet` instance is created and allows early access to it.

#### Multiple sheets

Next the `Writer` will determine if multiple sheets are configured, by checking for the `Maatwebsite\Excel\Concerns\WithMultipleSheets` concern.

Then it will delegate the further handling of each sheet to the `Maatwebsite\Excel\Sheet` class.

#### Processing the sheets

In the `Sheet` class, the most heavy lifting happens. It first will create a `PhpOffice\PhpSpreadsheet\Worksheet\Worksheet` instance. Then it will raise the `BeforeSheet` event which allows you to hook into the moment just before the sheet handling starts.

Then it will determine what kind of export we are dealing with: `FromQuery`, `FromArray`, `FromCollection` or `FromView`. Based on that it will start the connected export process.

- `FromView` will pass on the rendered `Blade` view to PhpSpreadsheet's `Html` Reader. That Reader will turn the table html into Excel cells. It also handles some inline styles (color and background color) and col/rowspans.
- The **Query** passed with the `FromQuery` will automatically be chunked and each chunk will be appended to the Sheet. The chunking is done to limit the amount of Eloquent objects it needs to keep in memory. It greatly reduces memory usage.
- The entire array of Collection will directly be appended to the Sheet. 

When the `Sheet` starts appending records, it will first call the `map()` method if the `WithMapping` concern is used. This allows the `Export` object to format the data before it is inserted.

Then it will handle column formatting (`WithColumnFormatting` concern) and cell autosizing (`ShouldAutoSize`).

To close off the Sheet processing, it will raise a `AfterSheet` event.

### Passing on to PhpSpreadsheet

After the sheets are processed, the writing process will start. The writing process is started by raising the `BeforeWriting` event; this allows you to hook into the process of writing.
Next we will create a new `PhpSpreadsheet Writer` based on the writer type that was determined. Then it will save it to a temporary file and return that filepath to the `Excel` manager.

### Creating a Response

The `Excel` manager basically has 2 types of responses, it either starts the **download** process or it will **store** the file to disk.

#### Download the file

We will take the temporary file that was returned by the `Writer` and use Laravel's `ResponseFactory` to create a `Symfony\Component\HttpFoundation\BinaryFileResponse`. When returning this response in your controller, it will start a download.

#### Storing the file

The storing of the file will be handled by Laravel's `Filesystem`. By default the file will be stored on your `default` disk, but you can also pass a custom disk via the `Excel::store()` method.

## Imports Lifecycle Overview

This section will try to give you an overview of how the import works behind the scenes.

### Import Object

Everything starts with the `Import` object. This object **encapsulates** your entire import logic. 
It both configures and handles the import logic.

A simple example of an import object is:

```php
namespace App\Imports;

use App\User;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\ToCollection;

class UsersImport implements ToCollection
{
    public function collection(Collection $rows)
    {
        foreach ($rows as $row) 
        {
            User::create([
                'name' => $row[0],
            ]);
        }
    }
}
```

If you want to read more about imports objects, go to the architecture page of [imports objects](/3.1/architecture/objects.html).

### Passing on the Import object

Next the Import object will be passed on to the Laravel Excel package. The main entry point for this is the `Maatwebsite/Excel/Excel` class. This class can be called in the same way as outlined in the Export lifecycle.

#### Contract

You can also use the `Maatwebsite\Excel\Importer` interface to decouple more from the concrete Excel manager implementation. The contract offers the same methods as the `Excel` class. 
It will make it easier to e.g. stub out the Importer in your unit tests. The `Importer` contract can be either injected via the constructor or the method of a controller.

```php
use App\Imports\UsersImport;
use Maatwebsite\Excel\Importer;

class ImportsController
{
    private $importer;

    public function __construct(Importer $importer)
    {
        $this->importer = $importer;
    }
    
    public function import()
    {
        return $this->importer->import(new UsersImport, 'users.xlsx');
    }
}
```

#### Importable trait

If you prefer a sprinkle of magic, you can use the `Maatwebsite\Excel\Concerns\Importable` trait in your `Import` object. This trait will expose a couple of methods that will make it possible to directly import an `Import` object.

```php
namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\ToCollection;
use Maatwebsite\Excel\Concerns\Importable;

class UsersImport implements ToCollection
{
    use Importable;

    ...
}
```

You can now import without the need for the `facade` or `Excel` manager.

```php
(new UsersImport)->import('users.xlsx');
```

Read more about the importable trait in the [importables](/3.1/imports/importables.html) docs.

### Handling the Import object

#### Reader type detection

After using one of the above methods to pass on the `Import` object to the `Excel` manager, it will try to figure out what reader type it is . 
This will be either based on the extension of the file or the explicitly passed reader type. You can find the extension to reader type mapping in the `excel.php` config, in the `extension_detector` section. 
In case no reader type can be detected, a `Maatwebsite\Excel\Exceptions\NoTypeDetectedException` exception is thrown and the import process will be stopped.

#### Starting the Reading process

The `Excel` manager will then delegate the handling to the `Maatwebsite\Excel\Reader`. The first action of the `Reader` is to register the event listeners that are registered. 
It will copy the file from Laravel's `Filesystem` to the local filesystem, so PhpSpreadsheet can read it. 
Next it will create a PhpSpreadsheet `Reader` based on the reader type that was given and load the file into a `PhpOffice\PhpSpreadsheet\Spreadsheet` instance.

Next it will create a new `PhpOffice\PhpSpreadsheet\Spreadsheet` instance that we will use to read our `Import` object from.

The first event that is raised, is the `BeforeImport` event. This is raised just after the `Spreadsheet` instance is loaded and allows early access to it.

#### Multiple sheets

Next we will determine if we are dealing with multiple sheets. This is done based on the `WithMultipleSheets` concern.

#### Processing the sheets

Then each Sheet gets processed. This process gets started off by raising the `BeforeSheet` event. 
Then it will either import it to a Collection, an array or handle each row as an Eloquent model.

- When using `ToModel`, each returned model will be persisted via Eloquent. When using this in combination with `WithBatchInserts`, it will defer the persistence till the batch is complete and then insert them as one batch in the database.
- When using `ToCollection` or `ToArray`, the entire dataset will be passed to the Import method and the user can determine itself how to use it.

The sheet handling is ended by raising the `AfterSheet` event.

---

## File: 3.1/architecture/objects.md

# Import & Export Objects

[[toc]]

The entire Laravel Excel philosophy evolves around having `Export` and/or `Import` objects.

## Directory structure

The location of these Import and Exports classes could be as follows:

::: vue
.
├── app
│   ├── `Exports` _(**Groups all exports in your app**)_
│   │   ├── UsersExport.php
│   │   ├── ProductsExport.php
│   │   └── `Sheets` _(**You can group sheets together**)_
│   │      ├── InactiveUsersSheet.php
│   │      └── ActiveUsersSheet.php
|   |
│   ├── `Imports` _(**Groups all imports in your app**)_
│   │   ├── UsersImport.php
│   │   ├── ProductsImport.php
│   │   └── `Sheets` _(**You can group sheets together**)_
│   │      ├── OutOfStockProductsSheet.php
│   │      └── ProductsOnSaleSheet.php
│ 
└── composer.json
:::

## Encapsulation

These objects encapsulate the entire export or import process. 
The idea behind it is that you can neatly use these objects in controllers, services, jobs, event listeners or commands. 
In all of theses cases, the entire logic of how the export/import needs to happen is kept within this object. 

## Data transfer object

The import/export objects are in essence simple data transfer objects (DTO). 
This means they will transfer the information you want to export/import to the Excel writer/reader. 
This information is not only the actual data you want to export, but also additional information like 
the styling of the file, the name of the worksheet, the number format of the cell etc.

In most cases, this means that your code doesn't need to have direct exposure to the actual read/write process.

## Plain Old PHP Object

Besides being a DTO, the import/export objects are also just Plain Old PHP Objects (POPO). This means that you can do anything with them that you can do with normal PHP objects. 

### Constructor

For instance, you can simply inject data through the constructor of the export object.

```php
class UsersExport implements FromCollection {
    private $year;

    public function __construct(int $year) 
    {
        $this->year = $year;
    }
    
    public function collection()
    {
        return Users::whereYear('created_at', $this->year)->get();
    }
}
```

```php
Excel::download(new UsersExport(2019), 'users.xlsx');
```

### Setters

Another option is to add setters for data that you want to pass.

```php
class UsersExport implements FromCollection {
    private $year;

    public function setYear(int $year)
    {
        $this->year = $year;
    }
    
    public function collection()
    {
        return Users::whereYear('created_at', $this->year)->get();
    }
}
```

```php
$export = new UsersExport();
$export->setYear(2019);

Excel::download($export, 'users.xlsx');
```

### Getters

In similar fashion to setters, you can also add getters. This can potentially be useful if you want to keep a state of your export/import.

For instance, you can keep a row count in your users import.

```php
namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\ToModel;

class UsersImport implements ToModel
{
    private $rows = 0;

    public function model(array $row)
    {
        ++$this->rows;
    
        return new User([
            'name' => $row[0],
        ]);
    }
    
    public function getRowCount(): int
    {
        return $this->rows;
    }
}
```

After doing the import, we can request the state with the getter.

```php
$import = new UsersImport;
Excel::import($import, 'users.xlsx');

dd('Row count: ' . $import->getRowCount()); 
```

## Concerns

Most of the export/import configuration is done by using **Concerns**. Concerns are basically just simple interfaces. 
Implementing them will make the object adhere to a certain contract. This contract can request specific methods that e.g. data can be passed through.
In other cases it might not ask for any methods to be implemented, but merely functions as a pointer interface.

Read more about Concerns in the [concerns documentation](/3.1/architecture/concerns.html).

## Hooks

In more complex cases you might want to hook into certain moments of the read/write process. This can be done by using Events.
To register these events in your import/export object, you need to implement the `Maatwebsite\Excel\Concerns\WithEvents` concern.

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Events\BeforeExport;

class UsersExport implements WithEvents
{
    /**
     * @return array
     */
    public function registerEvents(): array
    {
        return [
            // Handle by a closure.
            BeforeExport::class => function(BeforeExport $event) {
                // Do something before the export process starts.
            },
        ];
    }
}
```

Alternatively, you can also configure these listeners globally if you want it to happen to any export.

```php
Writer::listen(BeforeExport::class, function () {
    // Do something before any export process starts.
});
```

---

## File: 3.1/exports/charts.md

# Charts

[[toc]]

By using the `WithCharts` concern, you can add one or multiple charts to your worksheet.

## Instantiating a chart
You first have to instantiate a new `PhpOffice\PhpSpreadsheet\Worksheet\Chart`, passing the name, title, legend and plot in the constructor.

```php
$label      = [new DataSeriesValues('String', 'Worksheet!$B$1', null, 1)];
$categories = [new DataSeriesValues('String', 'Worksheet!$B$2:$B$5', null, 4)];
$values     = [new DataSeriesValues('Number', 'Worksheet!$A$2:$A$5', null, 4)];

$series = new DataSeries(DataSeries::TYPE_PIECHART, DataSeries::GROUPING_STANDARD,
    range(0, \count($values) - 1), $label, $categories, $values);
$plot   = new PlotArea(null, [$series]);

$legend = new Legend();
$chart  = new Chart('chart name', new Title('chart title'), $legend, $plot);

$chart->setTopLeftPosition('D1');
$chart->setBottomRightPosition('K12');
```

You can view all available properties for Charts on the [PhpSpreadsheet docs](https://phpoffice.github.io/PhpSpreadsheet/namespaces/phpoffice-phpspreadsheet-chart.html).

## Adding a single chart
When you've instantiated the chart, you can add the `WithCharts` concern to your export class and return the Chart instance in the `charts` method.

```php
<?php

namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithCharts;
use PhpOffice\PhpSpreadsheet\Worksheet\Chart;

class InvoicesExport implements WithCharts
{
    public function charts()
    {
        $label      = [new DataSeriesValues('String', 'Worksheet!$B$1', null, 1)];
        $categories = [new DataSeriesValues('String', 'Worksheet!$B$2:$B$5', null, 4)];
        $values     = [new DataSeriesValues('Number', 'Worksheet!$A$2:$A$5', null, 4)];

        $series = new DataSeries(DataSeries::TYPE_PIECHART, DataSeries::GROUPING_STANDARD,
            range(0, \count($values) - 1), $label, $categories, $values);
        $plot   = new PlotArea(null, [$series]);

        $legend = new Legend();
        $chart  = new Chart('chart name', new Title('chart title'), $legend, $plot);

        $chart->setTopLeftPosition('D1');
        $chart->setBottomRightPosition('K12');

        return $chart;
    }
}
```

## Adding multiple charts
You can add multiple charts to the worksheet by returning an array in the `charts` method.

```php
<?php

namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithCharts;
use PhpOffice\PhpSpreadsheet\Worksheet\Chart;

class InvoicesExport implements WithCharts
{
    public function charts()
    {
        $label      = [new DataSeriesValues('String', 'Worksheet!$B$1', null, 1)];
        $categories = [new DataSeriesValues('String', 'Worksheet!$B$2:$B$5', null, 4)];
        $values     = [new DataSeriesValues('Number', 'Worksheet!$A$2:$A$5', null, 4)];

        $series = new DataSeries(DataSeries::TYPE_PIECHART, DataSeries::GROUPING_STANDARD,
            range(0, \count($values) - 1), $label, $categories, $values);
        $plot   = new PlotArea(null, [$series]);

        $legend = new Legend();

        $chart  = new Chart('chart name', new Title('chart title'), $legend, $plot);
        $chart->setTopLeftPosition('D1');
        $chart->setBottomRightPosition('K12');

        $chart2 = new Chart('chart 2 name', new Title('chart 2 title'), $legend, $plot);
        $chart2->setTopLeftPosition('D13');
        $chart2->setBottomRightPosition('K24');

        return [$chart, $chart2];
    }
}
```

---

## File: 3.1/exports/collection.md

# Exporting collections

[[toc]]

The easiest way to start an export is to create a custom export class. We'll use an invoices export as example.

Create a new class called `InvoicesExport` in `app/Exports`:

```php
namespace App\Exports;

use App\Invoice;
use Maatwebsite\Excel\Concerns\FromCollection;

class InvoicesExport implements FromCollection
{
    public function collection()
    {
        return Invoice::all();
    }
}
```

In your controller we can now download this export:

```php
public function export() 
{
    return Excel::download(new InvoicesExport, 'invoices.xlsx');
}
```

Optionally you can pass in whether or not to output headers and custom response headers:

```php
public function export() 
{
    return Excel::download(new InvoicesExport, 'invoices.xlsx', true, ['X-Vapor-Base64-Encode' => 'True']);
}
```


Or store it on a disk, (e.g. s3):

```php
public function storeExcel() 
{
    return Excel::store(new InvoicesExport, 'invoices.xlsx', 's3');
}
```

:bulb: More about storing exports can be found in the [storing exports on disk page](/3.1/exports/store.html).

:::tip
If you want to use relationships in Collection, combine with [Mapping Data](/3.1/exports/mapping.html)
:::

## Using custom structures

If you are not using Eloquent or having another datasource (e.g. an API, MongoDB, Cache, ...) you can also return a custom collection:

```php
namespace App\Exports;

use App\Invoice;
use Maatwebsite\Excel\Concerns\FromCollection;

class InvoicesExport implements FromCollection
{
    public function collection()
    {
        return new Collection([
            [1, 2, 3],
            [4, 5, 6]
        ]);
    }
}
```

## Using arrays

If you prefer to use plain arrays over Collections, you can use the `FromArray` concern:

```php
namespace App\Exports;

use App\Invoice;
use Maatwebsite\Excel\Concerns\FromArray;

class InvoicesExport implements FromArray
{
    public function array(): array
    {
        return [
            [1, 2, 3],
            [4, 5, 6]
        ];
    }
}
```

If you need to pass data from the controller to your export, you can use the constructor to do so:

```php
namespace App\Exports;

use App\Invoice;
use Maatwebsite\Excel\Concerns\FromArray;

class InvoicesExport implements FromArray
{
    protected $invoices;

    public function __construct(array $invoices)
    {
        $this->invoices = $invoices;
    }

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

In your controller you can now use the constructor of the export class:

```php
public function export() 
{
    $export = new InvoicesExport([
        [1, 2, 3],
        [4, 5, 6]
    ]);

    return Excel::download($export, 'invoices.xlsx');
}
```

## Dependency injection

In case your export needs dependencies, you can inject the export class:

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\FromCollection;

class InvoicesExport implements FromCollection
{
    protected $invoices;

    public function __construct(InvoicesRepository $invoices)
    {
        $this->invoices = $invoices;
    }

    public function collection()
    {
        return $this->invoices->all();
    }
}
```

```php
public function export(Excel $excel, InvoicesExport $export) 
{
    return $excel->download($export, 'invoices.xlsx');
}
```

## Strict null comparisons

If you want your `0` values to be actual `0` values in your Excel sheet instead of `null` (empty cells), you can use `WithStrictNullComparison`.

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithStrictNullComparison;

class InvoicesExport implements FromCollection, WithStrictNullComparison
{
    public function __construct(InvoicesRepository $invoices)
    {
        $this->invoices = $invoices;
    }

    public function collection()
    {
        return $this->invoices->all();
    }
}
```

## Custom start cell
The default start cell is _A1_. Implementing the `WithCustomStartCell` concern in your export class allows you to specify a custom start cell.

```php
namespace App\Exports;

use App\Invoice;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithCustomStartCell;

class InvoicesExport implements FromCollection, WithCustomStartCell
{
    public function collection()
    {
        return Invoice::all();
    }

    public function startCell(): string
    {
        return 'B2';
    }
}
```

:::warning
`WithCustomStartCell` is only supported for `FromCollection` exports.
:::

## Storing raw contents

If you want to receive the raw contents of the exported file, you can use the `raw()` method:

```php
$contents = Excel::raw(new InvoicesExport, \Maatwebsite\Excel\Excel::XLSX);
```

## Collection macros

The package provides some macro to Laravel's collection class to easily download or store a collection.

### Downloading a collection as Excel

```php
User::all()->downloadExcel(
    $filePath,
    $writerType = null,
    $headings = false
)
```

It doesn't have to be an Eloquent collection to work:


```php
(new Collection([[1, 2, 3], [1, 2, 3]]))->downloadExcel(
    $filePath,
    $writerType = null,
    $headings = false
)
```

### Storing a collection on disk

```php
User::all()->storeExcel(
    $filePath,
    $disk = null,
    $writerType = null,
    $headings = false
)
```

---

## File: 3.1/exports/column-formatting.md

# Customizing columns

[[toc]]

## Formatting columns

You can easily format an entire column, by using `WithColumnFormatting`.
In case you want something more custom, it's suggested to use the `AfterSheet` event to directly interact with the underlying `Worksheet` class.

```php
namespace App\Exports;

use PhpOffice\PhpSpreadsheet\Shared\Date;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
use Maatwebsite\Excel\Concerns\WithColumnFormatting;
use Maatwebsite\Excel\Concerns\WithMapping;

class InvoicesExport implements WithColumnFormatting, WithMapping
{
    public function map($invoice): array
    {
        return [
            $invoice->invoice_number,
            Date::dateTimeToExcel($invoice->created_at),
            $invoice->total
        ];
    }
    
    public function columnFormats(): array
    {
        return [
            'B' => NumberFormat::FORMAT_DATE_DDMMYYYY,
            'C' => NumberFormat::FORMAT_CURRENCY_EUR_INTEGER,
        ];
    }
}
```

### Dates

When working with dates, it's recommended to use `\PhpOffice\PhpSpreadsheet\Shared\Date::dateTimeToExcel()` in your mapping
to ensure correct parsing of dates.

### Value binders

By default Laravel Excel uses PhpSpreadsheet's default value binder to intelligently format a cell's value when reading it. You may override this behavior by implementing the `WithCustomValueBinder` concern and the `bindValue` method. Your export class may also extend `DefaultValueBinder` to return the default behavior.

```php
namespace App\Exports;

use PhpOffice\PhpSpreadsheet\Cell\Cell;
use Maatwebsite\Excel\Concerns\ToModel;
use PhpOffice\PhpSpreadsheet\Cell\DataType;
use Maatwebsite\Excel\Concerns\WithCustomValueBinder;
use PhpOffice\PhpSpreadsheet\Cell\DefaultValueBinder;

class UsersExport extends DefaultValueBinder implements WithCustomValueBinder
{
    public function bindValue(Cell $cell, $value)
    {
        if (is_numeric($value)) {
            $cell->setValueExplicit($value, DataType::TYPE_NUMERIC);

            return true;
        }

        // else return default behavior
        return parent::bindValue($cell, $value);
    }
}
```

#### Available DataTypes 

* `PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_STRING`
* `PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_FORMULA`
* `PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_NUMERIC`
* `PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_BOOL`
* `PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_NULL`
* `PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_INLINE`
* `PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_ERROR`

### Disable intelligent formatting

If you want to disable the intelligent formatting of values, you can extend your export class with  `\PhpOffice\PhpSpreadsheet\Cell\StringValueBinder`. In this case all values are passed on as strings.

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithCustomValueBinder;

class UsersExport extends \PhpOffice\PhpSpreadsheet\Cell\StringValueBinder implements WithCustomValueBinder
{

}
```

### Default Value Binder

If you want to use one value binder for all your exports, you can configure the default value binder in the config.

In `config/excel.php`:

```php
'value_binder' => [
    'default' => Maatwebsite\Excel\DefaultValueBinder::class,
],
```

## Auto size

If you want Laravel Excel to perform an automatic width calculation, you need to implement the `ShouldAutoSize` interface, like the following code. 

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\ShouldAutoSize;

class InvoicesExport implements ShouldAutoSize
{
    ...
}
```

## Column widths

In some cases you might want more control over the actual column width instead of relying on autosizing. You can do so with the `WithColumnWidths` concerns. It accepts an array of columns (alphabetic representation: A, B, C) and a numeric width.

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithColumnWidths;

class InvoicesExport implements WithColumnWidths
{
    public function columnWidths(): array
    {
        return [
            'A' => 55,
            'B' => 45,            
        ];
    }
}
```

Can be used together with `ShouldAutoSize`. Only the columns with explicit widths won't be autosized. 

## Styling

The `WithStyles` (available after `v3.1.21`) concerns allows styling columns, cells and rows. This might be useful when you want to make the heading row bold.

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithStyles;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;

class InvoicesExport implements WithStyles
{
    public function styles(Worksheet $sheet)
    {
        return [
            // Style the first row as bold text.
            1    => ['font' => ['bold' => true]],

            // Styling a specific cell by coordinate.
            'B2' => ['font' => ['italic' => true]],

            // Styling an entire column.
            'C'  => ['font' => ['size' => 16]],
        ];
    }
}
```

For the contents of the styles array, please refer to the [PhpSpreadsheet docs](https://phpspreadsheet.readthedocs.io/en/latest/topics/recipes/#valid-array-keys-for-style-applyfromarray)

If you prefer the fluent syntax for styling cells, you can do it as follows:

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithStyles;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;

class InvoicesExport implements WithStyles
{
    public function styles(Worksheet $sheet)
    {
        $sheet->getStyle('B2')->getFont()->setBold(true);
    }
}
```

## Default styles

The `WithDefaultStyles` (available after `v3.1.40`) concerns allows styling the entire workbook.

```php
namespace App\Exports;

use PhpOffice\PhpSpreadsheet\Style\Fill;
use PhpOffice\PhpSpreadsheet\Style\Style;
use PhpOffice\PhpSpreadsheet\Style\Color;
use Maatwebsite\Excel\Concerns\WithDefaultStyles;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;

class InvoicesExport implements WithDefaultStyles
{
    public function defaultStyles(Style $defaultStyle)
    {
        // Configure the default styles
        return $defaultStyle->getFill()->setFillType(Fill::FILL_SOLID);
    
        // Or return the styles array
        return [
            'fill' => [
                'fillType'   => Fill::FILL_SOLID,
                'startColor' => ['argb' => Color::RED],
            ],
        ];
    }
}
```

## Workbook background color

The `WithBackgroundColor` (available after `v3.1.40`) concerns adds support to configure the background color of the entire workbook

```php
namespace App\Exports;

use PhpOffice\PhpSpreadsheet\Style\Fill;
use PhpOffice\PhpSpreadsheet\Style\Style;
use PhpOffice\PhpSpreadsheet\Style\Color;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use Maatwebsite\Excel\Concerns\WithBackgroundColor;

class InvoicesExport implements WithBackgroundColor
{
    public function backgroundColor()
    {
        // Return RGB color code.
        return '000000';
    
        // Return a Color instance. The fill type will automatically be set to "solid"
        return new Color(Color::COLOR_BLUE);
    
        // Or return the styles array
        return [
             'fillType'   => Fill::FILL_GRADIENT_LINEAR,
             'startColor' => ['argb' => Color::COLOR_RED],
        ];
    }
}
```

##  Full Styling Map

The full styling map can be taken from the PhpSpreadsheet Styles class as follows:

```php
/**
 * Apply styles from array.
 */
$spreadsheet->getActiveSheet()->getStyle('B2')->applyFromArray(
    [
        'font' => [
            'name' => 'Arial',
            'bold' => true,
            'italic' => false,
            'underline' => Font::UNDERLINE_DOUBLE,
            'strikethrough' => false,
            'color' => [
                'rgb' => '808080'
            ]
        ],
        'borders' => [
            'bottom' => [
                'borderStyle' => Border::BORDER_DASHDOT,
                'color' => [
                    'rgb' => '808080'
                ]
            ],
            'top' => [
                'borderStyle' => Border::BORDER_DASHDOT,
                'color' => [
                    'rgb' => '808080'
                ]
            ]
        ],
        'alignment' => [
            'horizontal' => Alignment::HORIZONTAL_CENTER,
            'vertical' => Alignment::VERTICAL_CENTER,
            'wrapText' => true,
        ],
        'quotePrefix'    => true
    ]
);
```

---

## File: 3.1/exports/concerns.md

---
pageClass: no-toc
---

# Export concerns

| Interface | Explanation | Documentation |
|---- |----|----|
|`Maatwebsite\Excel\Concerns\FromArray`| Use an array to populate the export. | [Exporting collections](/3.1/exports/collection.html#using-arrays) |
|`Maatwebsite\Excel\Concerns\FromCollection`| Use a Laravel Collection to populate the export. | [Exporting collections](/3.1/exports/collection.html) |
|`Maatwebsite\Excel\Concerns\FromGenerator`| Use a generator to populate the export. | [From Generator](/3.1/exports/from-generator.html) |
|`Maatwebsite\Excel\Concerns\FromIterator`| Use an iterator to populate the export. | |
|`Maatwebsite\Excel\Concerns\FromQuery`| Use an Eloquent query to populate the export. | [From Query](/3.1/exports/from-query.html) | 
|`Maatwebsite\Excel\Concerns\FromView`| Use a (Blade) view to populate the export. | [From View](/3.1/exports/from-view.html) |
|`Maatwebsite\Excel\Concerns\HasReferencesToOtherSheets`| Allows precalculated values where one sheet has references to another sheet. | [References to other sheets](/3.1/exports/multiple-sheets.html#making-calculations-work-when-referencing-between-sheets) |
|`Maatwebsite\Excel\Concerns\ShouldAutoSize`| Auto-size the columns in the worksheet. | [Auto size](/3.1/exports/column-formatting.html#auto-size) |
|`Maatwebsite\Excel\Concerns\WithCharts`| Allows to run one or multiple PhpSpreadsheet Chart instances. | [Charts](/3.1/exports/charts.html) |
|`Maatwebsite\Excel\Concerns\WithColumnFormatting`| Format certain columns. | [Formatting columns](/3.1/exports/column-formatting.html) |
|`Maatwebsite\Excel\Concerns\WithColumnWidths`| Set Column widths. | [Column widths](/3.1/exports/column-formatting.html#styling) |
|`Maatwebsite\Excel\Concerns\WithCustomChunkSize`| Allows Exportables to define their chunk size. | |
|`Maatwebsite\Excel\Concerns\WithCustomCsvSettings`| Allows to run custom Csv settings for this specific exportable. | [Custom CSV Settings](/3.1/exports/settings.html) |
|`Maatwebsite\Excel\Concerns\WithCustomQuerySize`| Allows Exportables that implement the FromQuery concern to provide their own custom query size. | [Custom Query Size](/3.1/exports/queued.html#custom-query-size) |
|`Maatwebsite\Excel\Concerns\WithCustomStartCell`| Allows to specify a custom start cell. Do note that this is only supported for FromCollection exports. | [Custom start cell](/3.1/exports/collection.html#custom-start-cell) |
|`Maatwebsite\Excel\Concerns\WithCustomValueBinder`| Allows to specify a custom value binder. | [Custom Value Binder](/3.1/exports/column-formatting.html#value-binders) |
|`Maatwebsite\Excel\Concerns\WithDrawings`| Allows to run one or multiple PhpSpreadsheet (Base)Drawing instances. | [Drawings](/3.1/exports/drawings.html) |
|`Maatwebsite\Excel\Concerns\WithEvents`| Register events to hook into the PhpSpreadsheet process. | [Events](/3.1/exports/extending.html#events) |
|`Maatwebsite\Excel\Concerns\WithHeadings`| Prepend a heading row. | [Adding a heading row](/3.1/exports/mapping.html#adding-a-heading-row) |
|`Maatwebsite\Excel\Concerns\WithMapping`| Format the row before it's written to the file. | [Mapping data](/3.1/exports/mapping.html) |
|`Maatwebsite\Excel\Concerns\WithMultipleSheets`| Enable multi-sheet support. Each sheet can have its own concerns (except this one). | [Multiple Sheets](/3.1/exports/multiple-sheets.html) |
|`Maatwebsite\Excel\Concerns\WithPreCalculateFormulas`| Forces PhpSpreadsheet to recalculate all formulae in a workbook when saving, so that the pre-calculated values are immediately available to MS Excel or other office spreadsheet viewer when opening the file. | |
|`Maatwebsite\Excel\Concerns\WithProperties`| Allows setting properties on the document.| [Properties](/3.1/exports/settings.html#properties) |
|`Maatwebsite\Excel\Concerns\WithStrictNullComparison`| Uses strict comparisons when testing cells for null value. | [Strict null comparisons](/3.1/exports/collection.html#strict-null-comparisons) |
|`Maatwebsite\Excel\Concerns\WithStyles`| Allows setting styles on worksheets. | [Styles](/3.1/exports/column-formatting.html#styling) |
|`Maatwebsite\Excel\Concerns\WithTitle`| Set the Workbook or Worksheet title. | [Multiple Sheets](/3.1/exports/multiple-sheets.html) |

### Traits

| Trait | Explanation | Documentation |
|---- |----|----|
|`Maatwebsite\Excel\Concerns\Exportable` | Add download/store abilities right on the export class itself. | [Exportables](/3.1/exports/exportables.html) |
|`Maatwebsite\Excel\Concerns\RegistersEventListeners` | Auto-register the available event listeners. | [Auto register event listeners](/3.1/exports/extending.html#auto-register-event-listeners) |

---

## File: 3.1/exports/drawings.md

# Drawings

[[toc]]

By using the `WithDrawings` concern, you can add one or multiple drawings to your worksheet.

## Instantiating a drawing
You first have to instantiate a new `\PhpOffice\PhpSpreadsheet\Worksheet\Drawing`, and assign its properties a meaningful value.

```php
$drawing = new \PhpOffice\PhpSpreadsheet\Worksheet\Drawing();
$drawing->setName('Logo');
$drawing->setDescription('This is my logo');
$drawing->setPath(public_path('/img/logo.jpg'));
$drawing->setHeight(90);
```

You can view all available properties for Drawing on the [PhpSpreadsheet docs](https://phpspreadsheet.readthedocs.io/en/latest/topics/recipes/#add-a-drawing-to-a-worksheet).

## Adding a single drawing
When you've instantiated the drawing, you can add the `WithDrawings` concern to your export class. Return the Drawing instance in the `drawings` method.

```php
<?php

namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithDrawings;
use PhpOffice\PhpSpreadsheet\Worksheet\Drawing;

class InvoicesExport implements WithDrawings
{
    public function drawings()
    {
        $drawing = new Drawing();
        $drawing->setName('Logo');
        $drawing->setDescription('This is my logo');
        $drawing->setPath(public_path('/img/logo.jpg'));
        $drawing->setHeight(90);
        $drawing->setCoordinates('B3');

        return $drawing;
    }
}
```

## Adding multiple drawings
You can add multiple drawings to the worksheet by returning an array in the `drawings` method.

```php
<?php

namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithDrawings;
use PhpOffice\PhpSpreadsheet\Worksheet\Drawing;

class InvoicesExport implements WithDrawings
{
    public function drawings()
    {
        $drawing = new Drawing();
        $drawing->setName('Logo');
        $drawing->setDescription('This is my logo');
        $drawing->setPath(public_path('/img/logo.jpg'));
        $drawing->setHeight(50);
        $drawing->setCoordinates('B3');

        $drawing2 = new Drawing();
        $drawing2->setName('Other image');
        $drawing2->setDescription('This is a second image');
        $drawing2->setPath(public_path('/img/other.jpg'));
        $drawing2->setHeight(120);
        $drawing2->setCoordinates('G2');

        return [$drawing, $drawing2];
    }
}
```

## Adding a drawing of remote image
You can instantiate a new drawing from `\PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing`, and create a string containing the binary image data, or from an external url by `imagecreatefromstring(file_get_contents($url))`, then assign it to `setImageResource`. Return the Drawing instance in the `drawings` method.

```php
<?php

namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithDrawings;
use PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing;

class InvoicesExport implements WithDrawings
{
    public function drawings()
    {
        if (!$imageResource = @imagecreatefromstring(file_get_contents('http://example.jpg'))) {
            throw new \Exception('The image URL cannot be converted into an image resource.');
        }

        $drawing = new MemoryDrawing();
        $drawing->setName('Logo');
        $drawing->setDescription('This is my logo');
        $drawing->setImageResource($imageResource);
        $drawing->setHeight(90);
        $drawing->setCoordinates('B3');

        return $drawing;
    }
}
```

---

## File: 3.1/exports/export-formats.md

# Export formats

[[toc]]

By default, the export format is determined by the extension of the file. If you want 
to explicitly configure the export format, you can pass it through as 2nd parameter. 

## XLSX

```php
return Excel::download(new InvoicesExport, 'invoices.xlsx', \Maatwebsite\Excel\Excel::XLSX);
```

## CSV

```php
return Excel::download(new InvoicesExport, 'invoices.csv', \Maatwebsite\Excel\Excel::CSV);
```

By default the CSV is download with Content Type `text/plain`, if you want to customize the Content-Type header, you can do so by passing it as 3rd parameter.

```php
return Excel::download(new InvoicesExport, 'invoices.csv', \Maatwebsite\Excel\Excel::CSV, [
      'Content-Type' => 'text/csv',
]);
```

:::tip Laravel CSV
You may have a look at our [Laravel CSV](/csv/1.0/getting-started/) package as well.
:::

## TSV

```php
return Excel::download(new InvoicesExport, 'invoices.tsv', \Maatwebsite\Excel\Excel::TSV);
```

## ODS

```php
return Excel::download(new InvoicesExport, 'invoices.ods', \Maatwebsite\Excel\Excel::ODS);
```

## XLS

```php
return Excel::download(new InvoicesExport, 'invoices.xls', \Maatwebsite\Excel\Excel::XLS);
```

## HTML

```php
return Excel::download(new InvoicesExport, 'invoices.html', \Maatwebsite\Excel\Excel::HTML);
```

::: warning Exporting to PDF
If you'd like to export to PDF, you must now install a PDF rendering library yourself. Please refer to the [PhpSpreadsheet Documentation](https://phpspreadsheet.readthedocs.io/en/latest/topics/reading-and-writing-to-file/#pdf) for more information.
:::

## MPDF

```php
return Excel::download(new InvoicesExport, 'invoices.pdf', \Maatwebsite\Excel\Excel::MPDF);
```

## DOMPDF

```php
return Excel::download(new InvoicesExport, 'invoices.pdf', \Maatwebsite\Excel\Excel::DOMPDF);
```

## TCPDF

```php
return Excel::download(new InvoicesExport, 'invoices.pdf', \Maatwebsite\Excel\Excel::TCPDF);
```

---

## File: 3.1/exports/exportables.md

# Exportables

[[toc]]

In the previous example, we used the `Excel::download` facade to start an export. 

Laravel Excel also provides a `Maatwebsite\Excel\Concerns\Exportable` trait, to make export classes exportable.

```php
namespace App\Exports;

use App\Invoice;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\Exportable;

class InvoicesExport implements FromCollection
{
    use Exportable;

    public function collection()
    {
        return Invoice::all();
    }
}
```

We can now download the export without the need for the facade:

```php
return (new InvoicesExport)->download('invoices.xlsx');
```

You can also pass the Writer Type and optional headers to the download method:

```php
return (new InvoicesExport)->download('invoices.csv', Excel::CSV, ['Content-Type' => 'text/csv']);
```

Or store it on a disk:

```php
return (new InvoicesExport)->store('invoices.xlsx', 's3');
```

You can also pass options to the disk if you like:

```php
return (new InvoicesExport)->store('invoices.xlsx', 's3', null, 'private');
```

## Responsable

The previous (download) example can be made even shorter when adding Laravel's `Responsable` interface to the export class:

```php
namespace App\Exports;

use App\Invoice;
use Maatwebsite\Excel\Excel;
use Illuminate\Contracts\Support\Responsable;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\Exportable;

class InvoicesExport implements FromCollection, Responsable
{
    use Exportable;
    
    /**
    * It's required to define the fileName within
    * the export class when making use of Responsable.
    */
    private $fileName = 'invoices.xlsx';
    
    /**
    * Optional Writer Type
    */
    private $writerType = Excel::XLSX;
    
    /**
    * Optional headers
    */
    private $headers = [
        'Content-Type' => 'text/csv',
    ];

    public function collection()
    {
        return Invoice::all();
    }
}
```

You can now easily return the export class, without the need of calling `->download()`.

```php
return new InvoicesExport();
```

---

## File: 3.1/exports/extending.md

# Extending

[[toc]]

## Events

The export process has a few events you can leverage to interact with the underlying 
classes to add custom behaviour to the export.

You are able to hook into the parent package by using events.
No need to use convenience methods like "query" or "view", if you need full control over the export.

The events will be activated by adding the `WithEvents` concern. Inside the `registerEvents` method, you 
will have to return an array of events. The key is the Fully Qualified Name (FQN) of the event and the value is a callable event listener.
This can either be a closure, array-callable or invokable class.

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Events\BeforeExport;
use Maatwebsite\Excel\Events\BeforeWriting;
use Maatwebsite\Excel\Events\BeforeSheet;

class InvoicesExport implements WithEvents
{
    /**
     * @return array
     */
    public function registerEvents(): array
    {
        return [
            // Handle by a closure.
            BeforeExport::class => function(BeforeExport $event) {
                $event->writer->getProperties()->setCreator('Patrick');
            },
            
            // Array callable, refering to a static method.
            BeforeWriting::class => [self::class, 'beforeWriting'],
            
            // Using a class with an __invoke method.
            BeforeSheet::class => new BeforeSheetHandler()
        ];
    }
    
    public static function beforeWriting(BeforeWriting $event) 
    {
        //
    }
}
```

Do note that using a `Closure` will not be possible in combination with queued exports, as PHP cannot serialize the closure.
In those cases it might be better to use the `RegistersEventListeners` trait.

### Auto register event listeners

By using the `RegistersEventListeners` trait you can auto-register the event listeners,
without the need of using the `registerEvents`. The listener will only be registered if the method is created. 

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Concerns\RegistersEventListeners;
use Maatwebsite\Excel\Events\BeforeExport;
use Maatwebsite\Excel\Events\BeforeWriting;
use Maatwebsite\Excel\Events\BeforeSheet;
use Maatwebsite\Excel\Events\AfterSheet;

class InvoicesExport implements WithEvents
{
    use Exportable, RegistersEventListeners;
    
    public static function beforeExport(BeforeExport $event)
    {
        //
    }

    public static function beforeWriting(BeforeWriting $event)
    {
        //
    }

    public static function beforeSheet(BeforeSheet $event)
    {
        //
    }

    public static function afterSheet(AfterSheet $event)
    {
        //
    }
}
```

### Global event listeners

Event listeners can also be configured globally, if you want to perform the same actions on all exports in your app.
You can add them to e.g. your `AppServiceProvider` in the `register()` method.

```php
Writer::listen(BeforeExport::class, function () {
    //
});

Writer::listen(BeforeWriting::class, function () {
    //
});

Sheet::listen(BeforeSheet::class, function () {
    //
});

Sheet::listen(AfterSheet::class, function () {
    //
});
```

### Available events

| Event name | Payload | Explanation |
|---- |----| ----|
|`Maatwebsite\Excel\Events\BeforeExport` | `$event->writer : Writer` | Event gets raised at the start of the process. | 
| `Maatwebsite\Excel\Events\BeforeWriting` | `$event->writer : Writer` | Event gets raised before the download/store starts. |
| `Maatwebsite\Excel\Events\BeforeSheet` | `$event->sheet : Sheet` | Event gets raised just after the sheet is created. |
| `Maatwebsite\Excel\Events\AfterSheet` | `$event->sheet : Sheet` | Event gets raised at the end of the sheet process. |

## Custom Concerns

You can add custom concerns to your app. This can be useful if you want to share some concerns over a few projects or want to open source your custom concerns.

Let's add a `WithCustomProperties` concern to your app. You could add these concerns to `App/Exports/Concerns`, but any location will do as long as it can be autoloaded by Composer.

```php
namespace App\Exports\Concerns;

interface WithCustomProperties
{
    /**
     *
     * @return string
     */
    public function description(): string;
}
```

Next to this concern we will create a concern handler `WithCustomPropertiesHandler`. This class can also be added to `App/Exports/Concerns`, but is again completely free of choice. 
A concern handler is basically just an invokable class. It receives your exportable object and either a `Writer` or `Sheet` object, depending on the chosen event.

```php
namespace App\Exports\Concerns;

use App\Exports\Concerns\WithCustomProperties;
use Maatwebsite\Excel\Writer;

class WithCustomPropertiesHandler
{
    /**
     * @param WithCustomProperties $exportable
     * @param Writer               $writer
     */
    public function __invoke(WithCustomProperties $exportable, Writer $writer)
    {
        $writer
            ->getDelegate()
            ->getProperties()
            ->setDescription(
                $exportable->description()
            );
    }
}
```

We will then register this concern in a service provider. You could use `App/Providers/AppServiceProvider` for this.

```php
public function register()
{
    Excel::extend(WithCustomProperties::class, new WithCustomPropertiesHandler);
}
```

:bulb: `::extend` accepts a callable as second parameter. It's also possible to pass a closure.

```php
public function register()
{
    Excel::extend(WithCustomProperties::class, function(WithCustomProperties $exportable, Writer $writer) {
        $writer->getDelegate()->getProperties()->setDescription($exportable->description());
    });
}
```

You can also bind concern handlers to different hooks. By default a concern handler is always bound to the `BeforeWriting` event. You can easily customize this, by supplying a 3rd parameter.

```php
public function register()
{
    Excel::extend(WithCustomProperties::class, new WithCustomPropertiesHandler, BeforeExport::class);
}
```

## Macroable

Both `Writer` and `Sheet` are "macroable" which means they can easily be extended to fit your needs. 
Both Writer and Sheet have a `->getDelegate()` method which returns the underlying PhpSpreadsheet class. 
This will allow you to add custom macros as shortcuts to PhpSpreadsheet methods that are not available in this package. 

### Writer

```php
use \Maatwebsite\Excel\Writer;

Writer::macro('setCreator', function (Writer $writer, string $creator) {
    $writer->getDelegate()->getProperties()->setCreator($creator);
});
```

### Sheet

```php
use \Maatwebsite\Excel\Sheet;

Sheet::macro('setOrientation', function (Sheet $sheet, $orientation) {
    $sheet->getDelegate()->getPageSetup()->setOrientation($orientation);
});
```

### Customize  
You can create your own macro to add custom methods to a spreadsheet instance. 

For example, to add styling to a cell, we first create a macro, let's call it `styleCells`:


```php
use \Maatwebsite\Excel\Sheet;

Sheet::macro('styleCells', function (Sheet $sheet, string $cellRange, array $style) {
    $sheet->getDelegate()->getStyle($cellRange)->applyFromArray($style);
});
```

Once the macro is created, it can be used inside the `registerEvents()` method as such:

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Events\BeforeExport;
use Maatwebsite\Excel\Events\AfterSheet;

class InvoicesExport implements WithEvents
{
    /**
     * @return array
     */
    public function registerEvents(): array
    {
        return [
            BeforeExport::class  => function(BeforeExport $event) {
                $event->writer->setCreator('Patrick');
            },
            AfterSheet::class    => function(AfterSheet $event) {
                $event->sheet->setOrientation(\PhpOffice\PhpSpreadsheet\Worksheet\PageSetup::ORIENTATION_LANDSCAPE);

                $event->sheet->styleCells(
                    'B2:G8',
                    [
                        'borders' => [
                            'outline' => [
                                'borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THICK,
                                'color' => ['argb' => 'FFFF0000'],
                            ],
                        ]
                    ]
                );
            },
        ];
    }
}
```
### RTL (Right to Left) Sheets

To change the Excel sheet direction you can use `setRightToLeft(true)` as in the below example

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Events\BeforeExport;
use Maatwebsite\Excel\Events\AfterSheet;

class InvoicesExport implements WithEvents
{
    /**
     * @return array
     */
    public function registerEvents(): array
    {
        return [
            AfterSheet::class    => function(AfterSheet $event) {
                $event->sheet->getDelegate()->setRightToLeft(true);
            },
        ];
    }
}
```

Feel free to use the above macro, or be creative and invent your own!

For PhpSpreadsheet methods, please refer to [their documentation](https://phpspreadsheet.readthedocs.io/).

---

## File: 3.1/exports/from-generator.md

---
pageClass: no-toc
---

# From Generator

Exports can be created from a PHP [generator](https://www.php.net/manual/en/class.generator.php) class, by using the `FromGenerator` concern.

A generator allows you to write code that uses foreach to iterate over a set of data without needing to build an array in memory.

```php
namespace App\Exports;

use Generator;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromGenerator;

class DataExport implements FromGenerator
{
    use Exportable;

    public function generator(): Generator
    {
        for ($i = 1; $i <= 100; $i++) {
            yield [$i, $i+1, $i+2];
        }
    }
}
```

You can download the export in your controller:

```php
public function export() 
{
    return (new DataExport)->download('data.xlsx');
}
```

:::tip Using Queue with FromGenerator is not supported. In case a queue is desired, we recommend wrapping the export file in a job, then using `->store` :::

---

## File: 3.1/exports/from-query.md

# From Query

[[toc]]

In the previous example, we did the query inside the export class. 
While this is a good solution for small exports, 
for bigger exports this will come at a hefty performance price.

By using the `FromQuery` concern, we can prepare a query for an export. Behind the scenes this query is executed in chunks.

In the `InvoicesExport` class, add the `FromQuery` concern and return a query. Be sure to **not** `->get()` the results!

```php
namespace App\Exports;

use App\Invoice;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\Exportable;

class InvoicesExport implements FromQuery
{
    use Exportable;

    public function query()
    {
        return Invoice::query();
    }
}
```

We can still download the export in the same way:

```php
return (new InvoicesExport)->download('invoices.xlsx');
```

## Customizing the query

It's easy to pass custom parameters to the query, 
by simply passing them as dependencies to the export class.

### As constructor parameter

```php
namespace App\Exports;

use App\Invoice;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\Exportable;

class InvoicesExport implements FromQuery
{
    use Exportable;

    public function __construct(int $year)
    {
        $this->year = $year;
    }

    public function query()
    {
        return Invoice::query()->whereYear('created_at', $this->year);
    }
}
```

The year can now be passed as dependency to the export class:

```php
return (new InvoicesExport(2018))->download('invoices.xlsx');
```

### As setter

```php
namespace App\Exports;

use App\Invoice;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\Exportable;

class InvoicesExport implements FromQuery
{
    use Exportable;

    public function forYear(int $year)
    {
        $this->year = $year;
        
        return $this;
    }

    public function query()
    {
        return Invoice::query()->whereYear('created_at', $this->year);
    }
}
```

We can adjust the year by using the `forYear` method:

```php
return (new InvoicesExport)->forYear(2018)->download('invoices.xlsx');
```

### Macro's and Mixins

The Eloquent Builder/Model has a macro to directly download an Eloquent query to Excel.

```php
User::query()->where('name', 'Patrick')->downloadExcel('query-download.xlsx');
```

If you want to include header row, you can pass `true` as third parameter:

```php
User::query()->downloadExcel('query-download.xlsx', Excel::XLSX, true);
```

Similarly, you can store the results of a query:

```php
User::query()->storeExcel('query-store.xlsx', 'your-disk');
```

---

## File: 3.1/exports/from-view.md

---
pageClass: no-toc
---

# From View

Exports can be created from a Blade view, by using the `FromView` concern.

```php
namespace App\Exports;

use App\Invoice;
use Illuminate\Contracts\View\View;
use Maatwebsite\Excel\Concerns\FromView;

class InvoicesExport implements FromView
{
    public function view(): View
    {
        return view('exports.invoices', [
            'invoices' => Invoice::all()
        ]);
    }
}
```

It will convert an HTML table into an Excel spreadsheet. For example; `invoices.blade.php`:

```html
<table>
    <thead>
    <tr>
        <th>Name</th>
        <th>Email</th>
    </tr>
    </thead>
    <tbody>
    @foreach($invoices as $invoice)
        <tr>
            <td>{{ $invoice->name }}</td>
            <td>{{ $invoice->email }}</td>
        </tr>
    @endforeach
    </tbody>
</table>
```

Attribute in tag html support:

|Attributes|Description
|-----------|-------------
|bgcolor| set background color to cell ``
|colspan| merge column cell
|rowspan| merge row cell
|width| set width to cell
|height| set height to cell
|data-format| set format `PhpOffice\PhpSpreadsheet\Style::NumberFormat`
|data-type| set type `PhpOffice\PhpSpreadsheet\Cell`
|align| set text align to cell
|valign| set vertical align to cell
|style| set style to cell

Style inline support
- background
- background-color
- color
- border|border-top|border-bottom|border-left|border-right
- font-size|font-weight|font-sytle|font-family
- text-decoration: underline|line-through
- text-align
- vertical-align
- width|height
- word-wrap
- text-indent

You can download the export in your controller:

```php
public function export() 
{
    return Excel::download(new InvoicesExport, 'invoices.xlsx');
}
```

---

## File: 3.1/exports/headings.md

# Headings

[[toc]]

## Adding a heading row

A heading row can easily be added by adding the `WithHeadings` concern. The heading row will be added
as very first row of the sheet.

```php

use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;

class InvoicesExport implements FromQuery, WithHeadings
{
    public function headings(): array
    {
        return [
            '#',
            'User',
            'Date',
        ];
    }
}
```

If you need to have multiple heading rows, you can return multiple rows from the `headings()` method:


```php

use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;

class InvoicesExport implements FromQuery, WithHeadings
{
    public function headings(): array
    {
        return [
           ['First row', 'First row'],
           ['Second row', 'Second row'],
        ];
    }
}
```

---

## File: 3.1/exports/index.md

---
pageClass: no-toc
---

# :rocket: 5 minute quick start

[[toc]]

:muscle: Create an export class in `app/Exports`

You may do this by using the `make:export` command.

```
php artisan make:export UsersExport --model=User
```

The file can be found in `app/Exports`:

::: vue
.
├── app
│   ├── `Exports` 
│   │   ├── UsersExport.php
│ 
└── composer.json
:::

If you prefer to create the export manually, you can create the following in `app/Exports`:

```php
<?php

namespace App\Exports;

use App\Models\User;
use Maatwebsite\Excel\Concerns\FromCollection;

class UsersExport implements FromCollection
{
    public function collection()
    {
        return User::all();
    }
}
```

:fire: In your controller you can call this export now:

```php
<?php

namespace App\Http\Controllers;

use App\Exports\UsersExport;
use Maatwebsite\Excel\Facades\Excel;

class UsersController extends Controller 
{
    public function export() 
    {
        return Excel::download(new UsersExport, 'users.xlsx');
    }
}
```

And finally add a route to be able to access the export:
```php
Route::get('users/export/', [UsersController::class, 'export']);
```


:page_facing_up: Find your `users.xlsx` in your downloads folder!

---

## File: 3.1/exports/mapping.md

# Mapping data

[[toc]]

## Mapping rows

By adding `WithMapping` you map the data that needs to be added as row. This way you have control over the actual source for each column.
In case of using the Eloquent query builder: 

```php

use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithMapping;
use PhpOffice\PhpSpreadsheet\Shared\Date;

class InvoicesExport implements FromQuery, WithMapping
{    
    /**
    * @param Invoice $invoice
    */
    public function map($invoice): array
    {
        return [
            $invoice->invoice_number,
            $invoice->user->name,
            Date::dateTimeToExcel($invoice->created_at),
        ];
    }
}
```


### Multiple rows

You can also return multiple rows inside the map function:

```php

use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithMapping;
use PhpOffice\PhpSpreadsheet\Shared\Date;

class InvoicesExport implements FromQuery, WithMapping
{    
    /**
    * @param Invoice $invoice
    */
    public function map($invoice): array
    {
        // This example will return 3 rows.
        // First row will have 2 column, the next 2 will have 1 column
        return [
            [
                $invoice->invoice_number,
                Date::dateTimeToExcel($invoice->created_at),
            ],
            [
                $invoice->lines->first()->description,
            ],
            [
                $invoice->lines->last()->description,
            ]
        ];
    }
}
```

## Prepare rows

If you need to prepare rows before appending these rows to sheet, you can add method `prepareRows` to your export class. This method will be called before flattening the query output and calling `map()`.

```php

use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;

class UsersExport implements FromQuery, WithHeadings
{   
    public function prepareRows($rows)
    {
        return $rows->transform(function ($user) {
            $user->name .= ' (prepared)';

            return $user;
        });
    }
}
```

---

## File: 3.1/exports/multiple-sheets.md

# Multiple Sheets

[[toc]]

To allow the export to have multiple sheets, the `WithMultipleSheets` concern should be used. 
The `sheets()` method expects an array of sheet export objects to be returned.

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\WithMultipleSheets;

class InvoicesExport implements WithMultipleSheets
{
    use Exportable;

    protected $year;
    
    public function __construct(int $year)
    {
        $this->year = $year;
    }

    /**
     * @return array
     */
    public function sheets(): array
    {
        $sheets = [];

        for ($month = 1; $month <= 12; $month++) {
            $sheets[] = new InvoicesPerMonthSheet($this->year, $month);
        }

        return $sheets;
    }
}
```

## Sheet classes

The `InvoicesPerMonthSheet` can implement concerns like `FromQuery`, `FromCollection`, `FromView`, ... 

_Note: The WithTitle concern is needed in order to name each sheet using the `title()` method_
```php
namespace App\Exports\Sheets;

use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithTitle;

class InvoicesPerMonthSheet implements FromQuery, WithTitle
{
    private $month;
    private $year;

    public function __construct(int $year, int $month)
    {
        $this->month = $month;
        $this->year  = $year;
    }

    /**
     * @return Builder
     */
    public function query()
    {
        return Invoice
            ::query()
            ->whereYear('created_at', $this->year)
            ->whereMonth('created_at', $this->month);
    }

    /**
     * @return string
     */
    public function title(): string
    {
        return 'Month ' . $this->month;
    }
}
```

The code below can be implemented in any class in order to download an xlsx of all invoices from the current year, with 12 worksheets representing each month of the year.

```php
public function downloadInvoices() 
{
    return (new InvoicesExport(2018))->download('invoices.xlsx');
}
```

---

## File: 3.1/exports/queued.md

# Queued

[[toc]]

In case you are working with a lot of data, it might be wise to queue the entire process. 

Given we have the following export class:

```php
namespace App\Exports;

use App\Invoice;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromQuery;

class InvoicesExport implements FromQuery
{
    use Exportable;

    public function query()
    {
        return Invoice::query();
    }
}
```

It's as easy as calling `->queue()` now.

```php
(new InvoicesExport)->queue('invoices.xlsx');

return back()->withSuccess('Export started!');
```

Behind the scenes the query will be chunked and multiple jobs will be chained. These jobs will be executed in the correct order,
and will only execute if none of the previous have failed. 

## Implicit Export queueing

You can also mark an export implicitly as a queued export. You can do this by using Laravel's `ShouldQueue` contract.

```php
namespace App\Exports;

use App\Invoice;
use Illuminate\Contracts\Queue\ShouldQueue;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromQuery;

class InvoicesExport implements FromQuery, ShouldQueue
{
    use Exportable;

    public function query()
    {
        return Invoice::query();
    }
}
```

In your controller you can now call the normal `->store()` method. 
Based on the presence of the `ShouldQueue` contract, the export will be queued.

```php
(new InvoicesExport)->store('invoices.xlsx');
```

## Appending jobs

The `queue()` method returns an instance of Laravel's `PendingDispatch`. This means you can chain extra jobs that will be added to the end of the queue and only executed if all export jobs are correctly executed.

```php
(new InvoicesExport)->queue('invoices.xlsx')->chain([
    new NotifyUserOfCompletedExport(request()->user()),
]);
```

```php
namespace App\Jobs;

use App\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\SerializesModels;

class NotifyUserOfCompletedExport implements ShouldQueue
{
    use Queueable, SerializesModels;
    
    public $user;
    
    public function __construct(User $user)
    {
        $this->user = $user;
    }

    public function handle()
    {
        $this->user->notify(new ExportReady());
    }
}
```

## Handling failures in queued exports

When queuing exports you might want a way to handle failed exports. You can do this by adding `failed` method to your export class.

```php

use Throwable;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;

class UsersExport implements FromQuery, WithHeadings
{   
    public function failed(Throwable $exception): void
    {
        // handle failed export
    }
}
```


## Custom queues

Because `PendingDispatch` is returned, we can also change the queue that should be used.

For Laravel 8+:

```php
(new InvoicesExport)->queue('invoices.xlsx')->onQueue('exports');
```
For older versions of Laravel:

```php
(new InvoicesExport)->queue('invoices.xlsx')->allOnQueue('exports');
```

## Multi-server setup

If you are dealing with a multi-server setup (using e.g. a loadbalancer), you might want to make sure the temporary file that is used to store each chunk of data on, is the same for each job. You can achieve this by configuring a remote temporary file in the config.

In `config/excel.php`

```php
'temporary_files' => [
    'remote_disk' => 's3',
],
```

## Job Middleware

If you are using Laravel 6, [job middleware](https://laravel.com/docs/6.x/queues#job-middleware) can be attached to the export class using the `middleware` method:

```php
namespace App\Exports;

use App\Jobs\Middleware\RateLimited;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromQuery;

class ExportClass implements FromQuery
{
    use Exportable;
    
    public function middleware()
    {
        return [new RateLimited];
    }

    public function query()
    {
        // ...
    }
}
```

## Localizing Queued Export

If you want to localize your queued export you should implement `HasLocalePreference` contract on your export:

```php
namespace App\Exports;

use Illuminate\Contracts\Translation\HasLocalePreference;
use Maatwebsite\Excel\Concerns\Exportable;

class ExportClass implements HasLocalePreference
{
    use Exportable;
    
    public function __construct(string $locale)
    {
        $this->locale = $locale;
    }
    
    public function preferredLocale()
    {
        return $this->locale;
    }
}
```

## Custom Query Size
Queued exportables are processed in chunks; each chunk being a job pushed to the queue by the `QueuedWriter`.
In case of exportables that implement the [FromQuery](/3.1/exports/from-query.html) concern, the number of jobs is calculated by dividing the `$query->count()` by the chunk size.

### When to use
Depending on the implementation of the `query()` method (e.g. when using a `groupBy` clause), the calculation mentioned before might not be correct.

If this is the case, you should use the `WithCustomQuerySize` concern to provide a custom calculation of the query size.

---

## File: 3.1/exports/settings.md

# Settings

[[toc]]

## Properties

By default the Worksheet properties get configured in `config/excel.php`. You can configure a default title, description, creator, etc.

If you want to overrule on a per export basis, you can use the `WithProperties` concern.

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithProperties;

class InvoicesExport implements WithProperties
{    
    public function properties(): array
    {
        return [
            'creator'        => 'Patrick Brouwers',
            'lastModifiedBy' => 'Patrick Brouwers',
            'title'          => 'Invoices Export',
            'description'    => 'Latest Invoices',
            'subject'        => 'Invoices',
            'keywords'       => 'invoices,export,spreadsheet',
            'category'       => 'Invoices',
            'manager'        => 'Patrick Brouwers',
            'company'        => 'Spartner',
        ];
    }
}
```

It's not required to return all properties, you can ommit the keys you don't want to overrule.

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithProperties;

class InvoicesExport implements WithProperties
{    
    public function properties(): array
    {
        return [
            'creator'        => 'Patrick Brouwers',
        ];
    }
}
```

## Custom CSV Settings

By default Laravel Excel uses the defaults from the config (`config/excel.php`). You can change this by adding the `WithCustomCsvSettings` interface.

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithCustomCsvSettings;

class InvoicesExport implements WithCustomCsvSettings
{    
    public function getCsvSettings(): array
    {
        return [
            'delimiter' => ';',
            'use_bom' => false,
            'output_encoding' => 'ISO-8859-1',
        ];
    }
}
```

### Available csv settings

* `delimiter`
* `enclosure`
* `line_ending`
* `use_bom`
* `include_separator_line`
* `excel_compatibility`
* `output_encoding`

## Cell caching

By default PhpSpreadsheet keeps all cell values in memory, however when dealing with large files, this might result into memory issues. If you want to mitigate that, you can configure a cell caching driver here.

When using the illuminate driver, it will store each value in the cache store. This can slow down the process, because it needs to store each value. However it will use less memory.
It will automatically use your default cache store. However if you prefer to have the cell cache on a separate store, you can configure the store name here. You can use any store defined in your cache config. When leaving at "null" it will use the default store.

You can use the "batch" store if you want to only persist to the store when the memory limit is reached. You can tweak the memory limit in the config.

Cells written to the cache store expire after `cache.default_ttl` seconds (set it to `null` to keep them indefinitely).

::: warning
`default_ttl` is only applied when the cache is called without a TTL argument. An explicit `null` TTL stores the cell forever. If you wrap or extend the `batch` driver (for example with `CacheManager::extend()`), don't forward a `null` TTL to it: leave the argument out, or pass `$ttl ?? config('excel.cache.default_ttl')`. Otherwise, the cells of any export that fails before PhpSpreadsheet releases them stay in the cache store permanently.
:::

---

## File: 3.1/exports/store.md

# Storing exports on disk

[[toc]]

Exports can easily be stored on any [filesystem](https://laravel.com/docs/master/filesystem) that Laravel supports.


## Default disk

```php
public function storeExcel() 
{
    // Store on default disk
    Excel::store(new InvoicesExport(2018), 'invoices.xlsx');
}
```

## Custom disks

```php
public function storeExcel() 
{
    // Store on a different disk (e.g. s3)
    Excel::store(new InvoicesExport(2018), 'invoices.xlsx', 's3');
    
    // Store on a different disk with a defined writer type. 
    Excel::store(new InvoicesExport(2018), 'invoices.xlsx', 's3', Excel::XLSX);
}
```

## Disk options

If you want to pass some options to the disk, pass them to Excel::store() as the fifth parameter.

```php
public function storeExcel() 
{
    Excel::store(new InvoicesExport(2018), 'invoices.xlsx', 's3', null, [
        'visibility' => 'private',
    ]);
}
```

Laravel has a shortcut for private files:

```php
public function storeExcel() 
{
    Excel::store(new InvoicesExport(2018), 'invoices.xlsx', 's3', null, 'private');
}
```

::: warning File names cannot include certain characters: 
- `<` (less than)
- `>` (greater than)
- `:` (colon)
- `"` (double quote)
- `/` (forward slash)
- `\` (backslash)
- `|` (vertical bar or pipe)
- `?` (question mark)
- `*` (asterisk)
:::

## Note about queuing
If you are storing the export using `Excel::queue()` or using the `ShouldQueue` interface, make sure to have a look at the [queuing docs](https://docs.laravel-excel.com/3.1/exports/queued.html)

---

## File: 3.1/exports/testing.md

# Testing

[[toc]]

The Excel facade can be used to swap the exporter to a fake.

## Testing downloads

```php
/**
* @test
*/
public function user_can_download_invoices_export() 
{
    Excel::fake();

    $this->actingAs($this->givenUser())
         ->get('/invoices/download/xlsx');

    Excel::assertDownloaded('filename.xlsx', function(InvoicesExport $export) {
        // Assert that the correct export is downloaded.
        return $export->collection()->contains('#2018-01');
    });
}
```

## Testing storing exports

```php
/**
* @test
*/
public function user_can_store_invoices_export() 
{
    Excel::fake();

    $this->actingAs($this->givenUser())
         ->get('/invoices/store/xlsx');

    Excel::assertStored('filename.xlsx', 'diskName');
    
    Excel::assertStored('filename.xlsx', 'diskName', function(InvoicesExport $export) {
        return true;
    });
    
    // When passing the callback as 2nd param, the disk will be the default disk.
    Excel::assertStored('filename.xlsx', function(InvoicesExport $export) {
        return true;
    });
}
```

## Testing queuing exports

```php
/**
* @test
*/
public function user_can_queue_invoices_export() 
{
    Excel::fake();

    $this->actingAs($this->givenUser())
         ->get('/invoices/queue/xlsx');

    Excel::assertQueued('filename.xlsx', 'diskName');
    
    Excel::assertQueued('filename.xlsx', 'diskName', function(InvoicesExport $export) {
        return true;
    });
    
    // When passing the callback as 2nd param, the disk will be the default disk.
    Excel::assertQueued('filename.xlsx', function(InvoicesExport $export) {
        return true;
    });
    
    // Assert that the export was queued with a specific chain of other jobs.
    Excel::assertQueuedWithChain([
        new NotifyUsers(),
    ])
}
```

## Testing exports with dynamic file name/path

If you have dynamic naming for files or paths, you can use a regular expression to represent those while testing:

 ```php
/**
* @test
*/
public function user_can_store_invoices_export() 
{
    Excel::fake();
    
    $this->actingAs($this->givenUser())
         ->get('/invoices/store/xlsx');
    
    // Tells the mock to use regular expressions
    Excel::matchByRegex(); 
    // For a given dynamic named file 'invoices_2019.xlsx'
    Excel::assertStored('/invoices_\d{4}\.xlsx/', 'diskName');
}
```
Please note that your expression must match only one file/path. If more than one match is found, the test will fail.

---

## File: 3.1/getting-started/contributing.md

# Contributing

[[toc]]

Please read and understand the contribution guide before creating an issue or pull request.

## Important Links

- [Docs](https://docs.laravel-excel.com/)
- [Issue tracker](https://github.com/SpartnerNL/Laravel-Excel/issues)
- [Support](/3.1/getting-started/support.html)

## Etiquette

This project is an open source project, and as such, the maintainers use their free time to build and maintain it.
The code is freely available and can be used, forked and modified. 

Please be considerate towards maintainers when raising issues or presenting pull requests. 

It's the duty of the maintainer to ensure that all submissions to the project are of sufficient
quality to benefit the project. Many developers have different skill sets, strengths, and weaknesses. Respect the maintainer's decision, and do not be upset or abusive if your submission is not used.

## Viability

When requesting or submitting new features, first consider whether it might be useful to others. Open
source projects are used by many developers, who may have entirely different needs to your own. Think about
whether or not your feature is likely to be used by other users of the project.

## How to submit changes?

- Check the codebase to ensure that your feature doesn't already exist.
- Check the pull requests to ensure that another person hasn't already submitted the feature or fix.
- Use the [pull request template](https://github.com/SpartnerNL/Laravel-Excel/blob/3.1/.github/PULL_REQUEST_TEMPLATE.md).

## How to report a bug?

- Attempt to replicate the problem, to ensure that it wasn't a coincidental incident.
- Check to make sure your bug report isn't already present within the project.
- Check the pull requests tab to ensure that the bug doesn't have a fix in progress.
- Check the pull requests tab to ensure that the feature isn't already in progress.
- Use the [issue template](https://github.com/SpartnerNL/Laravel-Excel/blob/3.1/.github/ISSUE_TEMPLATE.md).

## PR Requirements
- The PR **must** apply to [PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md). StyleCI help you detect code style issues.
- The PR **must** be as clean as possible. Try to remove all inline TODOs and unneeded comments. They are noise and distraction for the reviewer. Use Github's (inline) comment system to start a discussion about a change.
- The existing tests **must** not fail after your changes. This would indicate that existing functionality is broken and should be addressed before a review is started. You can run the test by running `vendor/bin/phpunit`
- The changes **must** be backed-up with tests. 
- The PR **must** only have one feature. Split up multiple features in multiple PRs, so they can be individually reviewed and merged.
- The PR **must** be accompanied by a PR to the docs in case of new features. Documentation is located in the [https://github.com/SpartnerNL/laravel-excel-docs](https://github.com/SpartnerNL/laravel-excel-docs) repository.
- The PR should contain meaningful commit messages.

---

## File: 3.1/getting-started/index.md

---
pageClass: no-toc
---

# Introduction

:rocket: Laravel Excel is intended at being Laravel-flavoured PhpSpreadsheet: a simple, but elegant wrapper around PhpSpreadsheet with the goal of simplifying
exports and imports. 

:fire: [PhpSpreadsheet](https://phpspreadsheet.readthedocs.io/) is a library written in pure PHP and providing a set of classes that allow you to read from and to write to different spreadsheet file formats, like Excel and LibreOffice Calc.

## Laravel Excel Features

* Easily export collections to Excel.
* Export queries with automatic chunking for better performance.
* Queue exports for better performance.
* Easily export Blade views to Excel.
* Easily import to collections.
* Read the Excel file in chunks.
* Handle the import inserts in batches.

---

## File: 3.1/getting-started/installation.md

# Installation

[[toc]]

## Requirements

* PHP: `^7.2\|^8.0`
* Laravel: `^5.8`
* PhpSpreadsheet: `^1.21`
* PHP extension `php_zip` enabled
* PHP extension `php_xml` enabled
* PHP extension `php_gd2` enabled
* PHP extension `php_iconv` enabled
* PHP extension `php_simplexml` enabled
* PHP extension `php_xmlreader` enabled
* PHP extension `php_zlib` enabled

## Installation

Require this package in the `composer.json` of your Laravel project. This will download the package and _PhpSpreadsheet_.

```
composer require "maatwebsite/excel:^3.1"
```

If installing your receive the following error 

```
  Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - Root composer.json requires maatwebsite/excel 3.1 -> satisfiable by maatwebsite/excel[3.1.0].
    - maatwebsite/excel 3.1.0 requires php ^7.0 -> your php version (8.2.8) does not satisfy that requirement.
```

You can try simply to install without the caret

```
composer require maatwebsite/excel
```

If you don't get the latest version or run into more composer errors, please make sure you have installed all required PHP extensions like zip, gd, etc.

The `Maatwebsite\Excel\ExcelServiceProvider` is __auto-discovered__ and registered by default.

If you want to register it yourself, add the ServiceProvider in `config/app.php`:

```php
'providers' => [
    /*
     * Package Service Providers...
     */
    Maatwebsite\Excel\ExcelServiceProvider::class,
]
```

The `Excel` facade is also __auto-discovered__.

If you want to add it manually, add the Facade in `config/app.php`:

```php
'aliases' => [
    ...
    'Excel' => Maatwebsite\Excel\Facades\Excel::class,
]
```

To publish the config, run the vendor publish command:

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

This will create a new config file named `config/excel.php`.

---

## File: 3.1/getting-started/license.md

# License

[[toc]]

## MIT
Our software is open source and licensed under the [MIT license](https://choosealicense.com/licenses/mit/). You are free to use the software as you like. The code can be forked and modified, but the original copyright author should always be included!

## Postcardware
According to the [postcardware](https://en.wikipedia.org/wiki/Postcardware) concept, if you use the software for your project(s) we would appreciate to receive a postcard of your hometown. Please send it to:

**Spartner**  
Markt 2   
6231 LS Meerssen  
The Netherlands  

## Created by Spartner (formerly Maatwebsite)

We are a strategic development partner, creating web-based custom built software from Laravel. In need of a digital solution for your challenge? Give us a call. 

[https://spartner.software](https://spartner.software)  
[info@spartner.nl](mailto:info@spartner.nl)  
+31 (0) 10 - 7449312  

## Support

::: warning Support
We hold no liability and will provide support on a best effort basis. For more information about support please see [support](https://docs.laravel-excel.com/3.1/getting-started/support.html).
:::

:::tip Commercial Support
:rocket: If you use the software commercially and need support urgently, we can offer this on a commercial basis. Please contact  or phone +31 (0)10 744 9312.
:::

---

## File: 3.1/getting-started/support.md

# Support

[[toc]]

Our software is free and open source, meaning that the use of our software is optional. We hold no liability and there is no obligation to support. We will provide support on a best effort basis.

:::tip Commercial Support
If you use the software commercially and need elaborate support or need it urgently, we can offer this on a commercial basis. Please contact  or via phone +31 (0)10 744 9312.
:::

## Supported Versions

Versions will be supported for a limited amount of time.

| Version | Laravel Version                     | Php Version | Support                      |
|---------|-------------------------------------|-------------|------------------------------|
| 2.1     | <=5.6                               | <=7.0       | Unsupported since 15-5-2018  |
| 3.0     | ^5.5                                | ^7.0        | Unsupported since 31-12-2018 |
| 3.1     | ^5.8\|^6.0\|^7.0\|^8.0\|^9.0\|^10.0 | ^7.2\|^8.0  | No active support, CVE only  |

::: warning PHP version support
Support for PHP versions will only be maintained for a period of six months beyond the end-of-life of that PHP version.
:::

## Requesting support
Before you request support, please check the following:
* Attempt to replicate the problem, to ensure that it wasn't a coincidental incident.
* Check to make sure your support request isn't already present within the project.
* Check the pull requests tab to ensure that the bug doesn't have a fix in progress.
* Use one of the [issue templates](https://github.com/SpartnerNL/Laravel-Excel/tree/3.1/.github/ISSUE_TEMPLATE).

Filling out the template is required. Issues that do not include enough information might not  be picked up. Please write in English (or Dutch).

Please prefix your issue with one of the following: [BUG] [PROPOSAL] [QUESTION].

And please be considerate towards maintainers when raising issues.

---

## File: 3.1/getting-started/upgrade.md

# Upgrade Guide

[[toc]]

## Upgrading to 3.1 from 3.0

Version 3.1 is backwards compatible with 3.0. Only features were added in this release.

__Additions__

* Imports feature.
* ChunkReading
* BatchInserts
* Queued imports
* ToArray concern for Exports.
* Custom value binders for Imports and Exports.

__Removals__

* `Excel::filter('chunk')` method is removed, chunk filter is automatically added when using chunk reading.

## Upgrading to 3.* from 2.1

Version 3.* is not backwards compatible with 2.*. It's not possible to provide a step-by-step migration guide as it's a complete paradigm shift.

__New dependencies__

3.* introduces some new dependencies.

* Requires PHP 7.0 or higher.
* Requires Laravel 5.5 (or higher).
* Requires PhpSpreadsheet instead of PHPExcel.

__Deprecations__

ALL Laravel Excel 2.* methods are deprecated and will not be able to use in 3.0 . 

- `Excel::load()` is removed and replaced by `Excel::import($yourImport)`
- `Excel::create()` is removed and replaced by `Excel::download/Excel::store($yourExport)`
- `Excel::create()->string('xlsx')` is removed an replaced by `Excel::raw($yourExport, Excel::XLSX)`
- 3.0 provides no convenience methods for styling, you are encouraged to use PhpSpreadsheets native methods.

You can find an example upgrade for an export here: [https://github.com/SpartnerNL/Laravel-Excel/issues/1799](https://github.com/SpartnerNL/Laravel-Excel/issues/1799)

---

## File: 3.1/imports/basics.md

## Importing basics

[[toc]]

If you have followed the 5 minute quick start, you'll already have a `UsersImport` class.

```php
<?php

namespace App\Imports;

use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Maatwebsite\Excel\Concerns\ToModel;

class UsersImport implements ToModel
{
    /**
     * @param array $row
     *
     * @return User|null
     */
    public function model(array $row)
    {
        return new User([
           'name'     => $row[0],
           'email'    => $row[1],
           'password' => Hash::make($row[2]),
        ]);
    }
}
```

## Importing from default disk

Passing the UsersImport object to the `Excel::import()` method will tell the package how to import the file that is passed as second parameter. 
The file is expected to be located in your default filesystem disk (see `config/filesystems.php`).

```php
Excel::import(new UsersImport, 'users.xlsx');
```

### Importing from another disk

You can specify another disk with the third parameter like your Amazon s3 disk. (see `config/filesystems.php`)

```php
Excel::import(new UsersImport, 'users.xlsx', 's3');
```

## Importing uploaded files

If you let your user upload the document, you can also just pass the uploaded file directly.

```php
Excel::import(new UsersImport, request()->file('your_file'));
```

### Importing full path 

If you want to specifiy the path where your file is, without having to move it to a disk, you can directly pass that file path to the import method.

```php
Excel::import(new UsersImport, storage_path('users.xlsx'));
```

## Importing to array or collection

If you want to bypass the `ToArray` or `ToCollection` concerns and want to have an array of imported data in your controller (beware of performance!), you can use the `::toArray()` or `::toCollection()` method.

```php
$array = Excel::toArray(new UsersImport, 'users.xlsx');

$collection = Excel::toCollection(new UsersImport, 'users.xlsx');
```

## Specifying a reader type

If the reader type is not detectable by the file extension, you can specify a reader type by passing it as fourth parameter.

```php
Excel::import(new UsersImport, 'users.xlsx', 's3', \Maatwebsite\Excel\Excel::XLSX);
```

---

## File: 3.1/imports/batch-inserts.md

# Batch inserts

[[toc]]

Importing a large file to Eloquent models, might quickly become a bottleneck as every row results into an insert query. 

With the `WithBatchInserts` concern you can limit the amount of queries done by specifying a batch size. This batch size will determine how many models will be inserted into the database in one time. This will drastically reduce the import duration.

```php
namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithBatchInserts;

class UsersImport implements ToModel, WithBatchInserts
{
    public function model(array $row)
    {
        return new User([
            'name' => $row[0],
        ]);
    }
    
    public function batchSize(): int
    {
        return 1000;
    }
}
```

:::warning ToModel
This concern **only** works with the `ToModel` concern.
:::

:::tip Batch Size
A batch size of `1000` will not be the most optimal situation for your import. Play around with this number to find the sweet spot.
:::

## Batch upserts

For batch upserts, you can additionally implement the `WithUpserts` concern.

```php
class UsersImport implements ToModel, WithBatchInserts, WithUpserts
{
    public function model(array $row)
    {
        return new User([
            'name' => $row[0],
        ]);
    }
    
    public function batchSize(): int
    {
        return 1000;
    }

    public function uniqueBy()
    {
        return 'email';
    }
}
```

In the example above, if a user already exists with the same email, the row will be updated instead. Behind the scenes, this feature uses the Laravel `upsert` method and the `uniqueBy` method is used for the second argument of the `upsert` method, which lists the column(s) that uniquely identify records within the associated table.

:::warning
All databases except SQL Server require the `uniqueBy` columns to have a "primary" or "unique" index.
:::

## Skipping duplicate rows

For skipping duplicate models, you can additionally implement the `WithSkipDuplicates` concern.

```php
class UsersImport implements ToModel, WithBatchInserts, WithSkipDuplicates
{
    public function model(array $row)
    {
        return new User([
            'name' => $row[0],
        ]);
    }
    
    public function batchSize(): int
    {
        return 1000;
    }
}
```

In the example above, if a user already exists with the same primary or unique key, the row will be ignored. Behind the scenes, this feature uses the Laravel `insertOrIgnore` method to insert records while ignoring duplicates, preventing any errors that would normally occur due to duplicate entries.

---

## File: 3.1/imports/chunk-reading.md

# Chunk reading

[[toc]]

Importing a large file can have a huge impact on the memory usage, as the library will try to load the entire sheet into memory.

To mitigate this increase in memory usage, you can use the `WithChunkReading` concern. This will read the spreadsheet in chunks and keep the memory usage under control.

```php
namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithChunkReading;

class UsersImport implements ToModel, WithChunkReading
{
    public function model(array $row)
    {
        return new User([
            'name' => $row[0],
        ]);
    }
    
    public function chunkSize(): int
    {
        return 1000;
    }
}
```

::: warning
A chunk size of `1000` will not be the most optimal situation for your import. Play around with this number to find the sweet spot.
:::

## Using it together with Batch Inserts

The most ideal situation (regarding time and memory consumption) you will find when combining batch inserts and chunk reading.

```php
namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithBatchInserts;
use Maatwebsite\Excel\Concerns\WithChunkReading;

class UsersImport implements ToModel, WithBatchInserts, WithChunkReading
{
    public function model(array $row)
    {
        return new User([
            'name' => $row[0],
        ]);
    }
    
    public function batchSize(): int
    {
        return 1000;
    }
    
    public function chunkSize(): int
    {
        return 1000;
    }
}
```

## Keep Track of the Row number

If you need the row number you can use the `RemembersRowNumber` Trait.

```php
namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\RemembersRowNumber;
use Maatwebsite\Excel\Concerns\WithChunkReading;

class UsersImport implements ToModel, WithChunkReading
{
    use RemembersRowNumber;

    public function model(array $row)
    {
        $currentRowNumber = $this->getRowNumber();

        return new User([
            'name' => $row[0],
        ]);
    }
    
    public function chunkSize(): int
    {
        return 1000;
    }
}
```

::: warning
Remembering row numbers is only intended for ToModel imports.
:::

If you only need the information about the offset of the chunk you can use the `RemembersChunkOffset` Trait.

```php
namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\RemembersChunkOffset;
use Maatwebsite\Excel\Concerns\WithChunkReading;

class UsersImport implements ToModel, WithChunkReading
{
    use RemembersChunkOffset;

    public function model(array $row)
    {
        $chunkOffset = $this->getChunkOffset();

        return new User([
            'name' => $row[0],
        ]);
    }
    
    public function chunkSize(): int
    {
        return 1000;
    }
}
```

---

## File: 3.1/imports/collection.md

---
pageClass: no-toc
---

# Importing to collections

[[toc]]

The easiest way to start an import is to create a custom import class. We'll use a user import as example.

Create a new class called `UsersImport` in `app/Imports`:

```php
namespace App\Imports;

use App\User;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\ToCollection;

class UsersImport implements ToCollection
{
    public function collection(Collection $collection)
    {
        foreach ($collection as $row) 
        {
            User::create([
                'name' => $row[0],
            ]);
        }
    }
}
```

The collection method will receive a collection of rows. A row is an array filled with the cell values. 

In case of the file having multiple sheets, the `collection()` method will be called multiple times.

In your controller we can now import this:

```php
public function import() 
{
    Excel::import(new UsersImport, 'users.xlsx');
}
```

:::warning
Whatever you return in the `collection()` method will **not** be returned to the controller.
:::

---

## File: 3.1/imports/concerns.md

---
pageClass: no-toc
---

# Import concerns

| Interface | Explanation | Documentation |
|---- |----|----|
|`Maatwebsite\Excel\Concerns\ToCollection`| Import to a collection. | [Importing to collections](/3.1/imports/collection.html) |
|`Maatwebsite\Excel\Concerns\ToArray`| Import to an array. | |
|`Maatwebsite\Excel\Concerns\ToModel`| Import each row to a model. | [Importing to models](/3.1/imports/model.html) |
|`Maatwebsite\Excel\Concerns\OnEachRow`| Handle each row manually. | |
|`Maatwebsite\Excel\Concerns\WithBatchInserts`| Insert models in batches. | [Batch inserts](/3.1/imports/batch-inserts.html) |
|`Maatwebsite\Excel\Concerns\WithChunkReading`| Read the sheet in chunks. | [Chunk reading](/3.1/imports/chunk-reading.html) |
|`Maatwebsite\Excel\Concerns\WithHeadingRow`| Define a row as heading row. | [Heading row](/3.1/imports/heading-row.html) |
|`Maatwebsite\Excel\Concerns\WithGroupedHeadingRow`| Allows columns sharing the same header key to group values in array | [Heading row](/3.1/imports/heading-row.html#grouping-values-of-multiple-columns-sharing-same-header) |
|`Maatwebsite\Excel\Concerns\WithLimit`| Define a limit of the amount of rows that need to be imported. |
|`Maatwebsite\Excel\Concerns\WithCustomValueBinder`| Define a custom value binder. | [Custom Formatting Values](/3.1/imports/custom-formatting-values.html) |
|`Maatwebsite\Excel\Concerns\WithMappedCells`| Define a custom cell mapping. | [Mapped Cells](/3.1/imports/mapped-cells.html) |
|`Maatwebsite\Excel\Concerns\WithMapping`| Map the row before being called in ToModel/ToCollection. | |
|`Maatwebsite\Excel\Concerns\WithMultipleSheets`| Enable multi-sheet support. Each sheet can have its own concerns (except this one). | [Multiple Sheets](/3.1/imports/multiple-sheets.html) |
|`Maatwebsite\Excel\Concerns\WithCalculatedFormulas`| Calculates the formulas when importing. By default this is disabled. | |
|`Maatwebsite\Excel\Concerns\WithEvents`| Register events to hook into the PhpSpreadsheet process. | [Events](/3.1/imports/extending.html#events) |
|`Maatwebsite\Excel\Concerns\WithCustomCsvSettings`| Allows to run custom Csv settings for this specific importable. | [Custom CSV Settings](/3.1/imports/custom-csv-settings.html) |
|`Maatwebsite\Excel\Concerns\WithStartRow`| Define a custom start row. | |
|`Maatwebsite\Excel\Concerns\WithProgressBar`| Shows a progress bar when uploading via the console. | [Progress Bar](/3.1/imports/progress-bar.html) |
|`Maatwebsite\Excel\Concerns\WithUpserts`| Allows to upsert models. | [Upserting models](/3.1/imports/model.html#upserting-models) |
|`Maatwebsite\Excel\Concerns\WithUpsertColumns`| Allows upsert columns definition. | [Upserting with specific columns](/3.1/imports/model.html#upserting-with-specific-columns) |
|`Maatwebsite\Excel\Concerns\WithValidation`| Validates each row against a set of rules. | [Row Validation](/3.1/imports/validation.html) |
|`Maatwebsite\Excel\Concerns\SkipsEmptyRows`| Skips empty rows. | [Row Validation](/3.1/imports/validation.html#skipping-empty-rows) |
|`Maatwebsite\Excel\Concerns\SkipsOnFailure`| Skips on validation errors. | [Row Validation](/3.1/imports/validation.html#skipping-failures) |
|`Maatwebsite\Excel\Concerns\SkipsOnError`| Skips on database exceptions. | [Row Validation](/3.1/imports/validation.html#skipping-errors) |
|`Maatwebsite\Excel\Concerns\WithColumnLimit` | Allows setting an end column ||
|`Maatwebsite\Excel\Concerns\WithReadFilter` | Allows defining a custom read filter ||


### Traits

| Trait | Explanation | Documentation |
|---- |----|----|
|`Maatwebsite\Excel\Concerns\Importable` | Add import/queue abilities right on the import class itself. | [Importables](/3.1/imports/importables.html) |
|`Maatwebsite\Excel\Concerns\RegistersEventListeners` | Auto-register the available event listeners. | [Auto register event listeners](/3.1/imports/extending.html#auto-register-event-listeners) |

---

## File: 3.1/imports/custom-csv-settings.md

# Custom CSV Settings

[[toc]]

By default Laravel Excel uses the defaults from the config (`config/excel.php`). You can change this by adding the `WithCustomCsvSettings` interface.

```php
namespace App\Imports;

use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithCustomCsvSettings;

class UsersImport implements ToModel, WithCustomCsvSettings
{
    public function model(array $row)
    {
        return new User([
            'name' => $row['0'],
            'email' => $row['1']
        ]);
    }
    
    public function getCsvSettings(): array
    {
        return [
            'input_encoding' => 'ISO-8859-1'
        ];
    }
}
```


A CSV file stores data in rows and the values in each row is separated with a separator, also known as a delimiter. Although the file is defined as Comma Separated Values, the delimiter could be anything. Delimiter requires a single character. For Tab use `"\t"`. The most common delimiters are: a comma `,`, a semicolon `;`, a tab `\t`, a space ` `, or a pipe `|`.

```php
public function getCsvSettings(): array
{
    return [
        'delimiter' => "\t"
    ];
}
```

## Available settings

* `delimiter`
* `enclosure`
* `escape_character`
* `contiguous`
* `input_encoding`

---

## File: 3.1/imports/custom-formatting-values.md

# Custom Formatting Values

[[toc]]

## Value Binder

By default Laravel Excel uses PhpSpreadsheet's default value binder to intelligently format a cell's value when reading it. You may override this behavior by implementing the `WithCustomValueBinder` concern and the `bindValue` method. Your import class may also extend `DefaultValueBinder` to return the default behavior.

```php
namespace App\Imports;

use PhpOffice\PhpSpreadsheet\Cell\Cell;
use Maatwebsite\Excel\Concerns\ToModel;
use PhpOffice\PhpSpreadsheet\Cell\DataType;
use Maatwebsite\Excel\Concerns\WithCustomValueBinder;
use PhpOffice\PhpSpreadsheet\Cell\DefaultValueBinder;

class UsersImport extends DefaultValueBinder implements WithCustomValueBinder, ToModel
{
    public function bindValue(Cell $cell, $value)
    {
        if (is_numeric($value)) {
            $cell->setValueExplicit($value, DataType::TYPE_NUMERIC);

            return true;
        }

        // else return default behavior
        return parent::bindValue($cell, $value);
    }
}
```

## Available DataTypes

* `PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_STRING`
* `PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_FORMULA`
* `PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_NUMERIC`
* `PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_BOOL`
* `PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_NULL`
* `PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_INLINE`
* `PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_ERROR`

## Disable intelligent formatting

If you want to disable the intelligent formatting of values, you can extend your import class with  `\PhpOffice\PhpSpreadsheet\Cell\StringValueBinder`. In this case all values are passed on as strings.

```php
namespace App\Imports;

use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithCustomValueBinder;

class UsersImport extends \PhpOffice\PhpSpreadsheet\Cell\StringValueBinder implements WithCustomValueBinder, ToModel
{

}
```

## Default Value Binder

If you want to use one value binder for all your imports, you can configure the default value binder in the config.

In `config/excel.php`:

```php
'value_binder' => [
    'default' => Maatwebsite\Excel\DefaultValueBinder::class,
],
```

---

## File: 3.1/imports/extending.md

# Extending

[[toc]]

## Events

The import process has a few events you can leverage to interact with the underlying 
classes to add custom behaviour to the import.

You are able to hook into the parent package by using events.

The events will be activated by adding the `WithEvents` concern. Inside the `registerEvents` method, you 
will have to return an array of events. The key is the Fully Qualified Name (FQN) of the event and the value is a callable event listener.
This can either be a closure, array-callable or invokable class.

```php
namespace App\Imports;

use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Events\BeforeImport;
use Maatwebsite\Excel\Events\AfterImport;
use Maatwebsite\Excel\Events\AfterSheet;
use Maatwebsite\Excel\Events\BeforeSheet;


class UsersImport implements WithEvents
{
    /**
     * @return array
     */
    public function registerEvents(): array
    {
        return [
            // Handle by a closure.
            BeforeImport::class => function(BeforeImport $event) {
                $creator = $event->reader->getProperties()->getCreator();
            },
			
		   
            // Using a class with an __invoke method.
            BeforeSheet::class => new BeforeSheetHandler(),
            
            // Array callable, refering to a static method.
            AfterSheet::class => [self::class, 'afterSheet'],
                        
        ];
    }
    
    public static function afterSheet(AfterSheet $event) 
    {
        //
    }
	
}
```

Do note that using a `Closure` will not be possible in combination with queued imports, as PHP cannot serialize the closure.
In those cases it might be better to use the `RegistersEventListeners` trait.

### Auto register event listeners

By using the `RegistersEventListeners` trait you can auto-register the event listeners,
without the need of using the `registerEvents`. The listener will only be registered if the method is created. 

```php
namespace App\Imports;

use Maatwebsite\Excel\Concerns\Importable;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Concerns\RegistersEventListeners;
use Maatwebsite\Excel\Events\BeforeImport;
use Maatwebsite\Excel\Events\AfterImport;
use Maatwebsite\Excel\Events\BeforeSheet;
use Maatwebsite\Excel\Events\AfterSheet;

class UsersImport implements WithEvents
{
    use Importable, RegistersEventListeners;
    
    public static function beforeImport(BeforeImport $event)
    {
        //
    }
	
    public static function afterImport(AfterImport $event)
    {
        //
    }

    public static function beforeSheet(BeforeSheet $event)
    {
        //
    }

    // From 3.1.50 onwards the methods do not need to be static, allowing use of $this
    public function afterSheet(AfterSheet $event)
    {
        //
    }
	
}
```

### Global event listeners

Event listeners can also be configured globally, if you want to perform the same actions on all exports in your app.
You can add them to e.g. your `AppServiceProvider` in the `register()` method.

```php
Reader::listen(BeforeImport::class, function () {
    //
});

Sheet::listen(AfterImport::class, function () {
    //
});

Sheet::listen(BeforeSheet::class, function () {
    //
});

Sheet::listen(AfterSheet::class, function () {
    //
});


```

### Available events

| Event name | Payload | Explanation |
|---- |----| ----|
|`Maatwebsite\Excel\Events\BeforeImport` | `$event->reader : Reader` | Event gets raised at the start of the process. | 
| `Maatwebsite\Excel\Events\AfterImport` | `$event->reader : Reader` | Event gets raised at the end of the  process. |
| `Maatwebsite\Excel\Events\ImportFailed` | `$event->getException() : Throwable` | Event gets raised on failure of the import process. |
| `Maatwebsite\Excel\Events\BeforeSheet` | `$event->sheet : Sheet` | Event gets raised just after the sheet is created. |
| `Maatwebsite\Excel\Events\AfterSheet` | `$event->sheet : Sheet` | Event gets raised at the end of the sheet process. |
| `Maatwebsite\Excel\Events\AfterChunk` | `$event->sheet : Sheet` | Event gets raised after each chunk from the import file has been processed. Only available with [chunk reading](https://docs.laravel-excel.com/3.1/imports/chunk-reading.html) |
| `Maatwebsite\Excel\Events\AfterBatch` | `$event->manager : ModelManager` | Event gets raised after each batch of model has been flushed to the database. Only available with [batch inserts](https://docs.laravel-excel.com/3.1/imports/batch-inserts.html) |


## Macroable

Both `Reader` and `Sheet` are "macroable" (which means they can easily be extended to fit your needs). 
Both Reader and Sheet have a `->getDelegate()` method which returns the underlying PhpSpreadsheet class. 
This will allow you to add custom macros as shortcuts to PhpSpreadsheet methods that are not available in this package. 

### Reader

```php
use \Maatwebsite\Excel\Reader;

Reader::macro('setCreator', function (Reader $reader, string $creator) {
    $reader->getDelegate()->getProperties()->setCreator($creator);
});
```

### Sheet

```php
use \Maatwebsite\Excel\Sheet;

Sheet::macro('setOrientation', function (Sheet $sheet, $orientation) {
    $sheet->getDelegate()->getPageSetup()->setOrientation($orientation);
});
```

For PhpSpreadsheet methods, please refer to [their documentation](https://phpspreadsheet.readthedocs.io/).

---

## File: 3.1/imports/heading-row.md

# Heading row

[[toc]]

In case your file contains a heading row (a row in which each cells indicates the purpose of that column) and you want to use those names as array keys of each row, you can implement the `WithHeadingRow` concern.

Given we have an Excel file looking like this:

| Name | Email | @ Field |
|---- |----|---|
| Patrick Brouwers | patrick@spartner.nl | Some value |

We can now reference the heading instead of a numeric array key.

```php
namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithHeadingRow;

class UsersImport implements ToModel, WithHeadingRow
{
    public function model(array $row)
    {
        return new User([
            'name'  => $row['name'],
            'email' => $row['email'],
            'at'    => $row['at_field'],
        ]);
    }
}
```

## Heading row on different row

In case your heading row is not on the first row, you can easily specify this in your import class:

```php
namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithHeadingRow;

class UsersImport implements ToModel, WithHeadingRow
{
    public function model(array $row)
    {
        return new User([
            'name'  => $row['name'],
            'email' => $row['email'],
        ]);
    }
    
    public function headingRow(): int
    {
        return 2;
    }
}
```

The 2nd row will now be used as heading row.

## Heading key formatting

By default the heading keys are formatted with the Laravel `str_slug()` helper. E.g. this means all spaces are converted to `_`.

If you want to change this behaviour, you can do so by extending the `HeadingRowFormatter`

### No formatting

If you want no formatting at all, you can use the `none` formatter. The array keys will contain the exact data that was in the heading row.

```php
use Maatwebsite\Excel\Imports\HeadingRowFormatter;

HeadingRowFormatter::default('none');

public function model(array $row)
{
    return new User([
        'name'  => $row['Name'],
        'email' => $row['Email'],
    ]);
}
```

### Custom formatter

You can define a custom formatter with `::extend()` in a service provider.

```php
HeadingRowFormatter::extend('custom', function($value, $key) {
    return 'do-something-custom' . $value; 
    
    // And you can use heading column index.
    // return 'column-' . $key; 
});
```

You can set the custom formatter in `config/excel.php`.

```php
'imports' => [
    'heading_row' => [
        'formatter' => 'custom',
    ],
],
```

Or you can then set this new formatter in a service provider.

```php
HeadingRowFormatter::default('custom');
```

## Importing only the heading row

Sometimes you might want to prefetch the heading row to do some validation. We have an easy shortcut for this: `HeadingRowImport`.

```php
use Maatwebsite\Excel\HeadingRowImport;

class UsersImportController extends Controller 
{
    public function import()
    {
        $headings = (new HeadingRowImport)->toArray('users.xlsx');
    }
}
```

The headings array contains an array of headings per sheet. 

## Grouping values of multiple columns sharing same header

Given we have an Excel file looking like this:

| Name | Email | Options | Options |
|---- |----|---|---|
| Patrick Brouwers | patrick@spartner.nl | Some value | Some other value |

We can group the values of the Options columns in an array using import concern `WithGroupedHeadingRow`. Data returned from row will be in format:
```php
[
    'name'    => 'Patrick Brouwers',
    'email'   => 'patrick@spartner.nl',
    'options' => [
        'Some value',
        'Some other value'
    ]
]
```

---

## File: 3.1/imports/import-formats.md

# Import formats

[[toc]]

By default, the import format is determined by the extension of the file. If you want 
to explicitly configure the import format, you can pass it through as 3rd parameter. 

## XLSX

```php
(new UsersImport)->import('users.xlsx', null, \Maatwebsite\Excel\Excel::XLSX);
```

## CSV

```php
(new UsersImport)->import('users.csv', null, \Maatwebsite\Excel\Excel::CSV);
```

## TSV

```php
(new UsersImport)->import('users.tsv', null, \Maatwebsite\Excel\Excel::TSV);
```

## ODS

```php
(new UsersImport)->import('users.ods', null, \Maatwebsite\Excel\Excel::ODS);
```

## XLS

```php
(new UsersImport)->import('users.xls', null, \Maatwebsite\Excel\Excel::XLS);
```

## SLK

```php
(new UsersImport)->import('users.slk', null, \Maatwebsite\Excel\Excel::SLK);
```

## XML

```php
(new UsersImport)->import('users.xml', null, \Maatwebsite\Excel\Excel::XML);
```

## GNUMERIC

```php
(new UsersImport)->import('users.gnumeric', null, \Maatwebsite\Excel\Excel::GNUMERIC);
```

## HTML

```php
(new UsersImport)->import('users.html', null, \Maatwebsite\Excel\Excel::HTML);
```

---

## File: 3.1/imports/importables.md

# Importables

[[toc]]

In the previous example, we used the `Excel::import` facade to start an import. 

Laravel Excel also provides a `Maatwebsite\Excel\Concerns\Importable` trait, to make import classes importable.

```php
namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\Importable;

class UsersImport implements ToModel
{
    use Importable;

    public function model(array $row)
    {
        return new User([
            'name' => $row[0],
        ]);
    }
}
```

## Importing

We can now import without the need for the facade:

```php
(new UsersImport)->import('users.xlsx', 'local', \Maatwebsite\Excel\Excel::XLSX);
```

## Queuing

Or queue the import:

```php
(new UsersImport)->queue('users.xlsx');
```

## To array

The import can be loaded into an array :

```php
$array = (new UsersImport)->toArray('users.xlsx');
```

## To collection

The import can be loaded into a collection:

```php
$collection = (new UsersImport)->toCollection('users.xlsx');
```

---

## File: 3.1/imports/index.md

---
pageClass: no-toc
---

## :rocket: 5 minute quick start

:muscle: Create an import class in `app/Imports`

You may do this by using the `make:import` command.

```
php artisan make:import UsersImport --model=User
```

The file can be found in `app/Imports`:

::: vue
.
├── app
│   ├── `Imports` 
│   │   ├── UsersImport.php
│ 
└── composer.json
:::

If you prefer to create the import manually, you can create the following in `app/Imports`:

```php
<?php

namespace App\Imports;

use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Maatwebsite\Excel\Concerns\ToModel;

class UsersImport implements ToModel
{
    /**
     * @param array $row
     *
     * @return User|null
     */
    public function model(array $row)
    {
        return new User([
           'name'     => $row[0],
           'email'    => $row[1], 
           'password' => Hash::make($row[2]),
        ]);
    }
}
```

:fire: In your controller you can call this import now:

```php

use App\Imports\UsersImport;
use Maatwebsite\Excel\Facades\Excel;
use App\Http\Controllers\Controller;

class UsersController extends Controller 
{
    public function import() 
    {
        Excel::import(new UsersImport, 'users.xlsx');
        
        return redirect('/')->with('success', 'All good!');
    }
}
```

:page_facing_up: Find the imported users in your database!

---

## File: 3.1/imports/mapped-cells.md

---
pageClass: no-toc
---

# Mapped Cells

In case you have a more custom spreadsheet and only want to access specific **cells**, you can implement the `WithMappedCells` concern.

You might have a speadsheet looking like this:

|name | Patrick Brouwers|
|---- |----|
| email | patrick@spartner.nl |

We can now map `name` to `B1` and `email` to `B2`. The value of those coordinates will then be available under the given array key.

```php
namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithMappedCells;

class UsersImport implements WithMappedCells, ToModel 
{
    public function mapping(): array
    {
        return [
            'name'  => 'B1',
            'email' => 'B2',
        ];
    }
    
    public function model(array $row)
    {
        return new User([
            'name' => $row['name'],
            'email' => $row['email'],
        ]);
    }
}
```

::: warning
This concern is not meant to map **columns**, only specific **cell** reference are allowed.
:::

## Multi-dimensional Mapping

In case you have repeating data in your table, e. g. a spreadsheet looking like this:

| Team 1 | | Team 2| |
|-|-|-|-|
| Max | 2 | Peter | 3 |
| Annie | 0 | Alex | 1 |

you are also able to define cell coordinates in a nested array:

```php
public function mapping(): array
{
    return [
        'team1' => [
            [
                'name' => 'A2',
                'score' => 'B2',
            ],
            [
                'name' => 'A3',
                'score' => 'B3',
            ],
        ],
        'team2' => [
            [
                'name' => 'C2',
                'score' => 'D2',
            ],
            [
                'name' => 'C3',
                'score' => 'D3',
            ],
        ],
    ];
}```

Note that an array of the same form will be returned.

---

## File: 3.1/imports/model.md

# Importing to models

[[toc]]

In case you want to import a workbook to an Eloquent model, you can use the `ToModel` concern. The concern enforces a `model()` method which accepts a model to be returned.

```php
namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\ToModel;

class UsersImport implements ToModel
{
    public function model(array $row)
    {
        return new User([
            'name' => $row[0],
        ]);
    }
}
```

The returned model will be saved for you. Each row will result into (at least) one save and will also fire model events.

:::warning
When using `ToModel` you should never save the model yourself, as that will break the batch insert functionality. If you need this, consider using `OnEachRow`.
:::

## Upserting models

In case you want to upsert models, instead of inserting, you can implement the `WithUpserts` concern. 

```php
class UsersImport implements ToModel, WithUpserts
{
    /**
     * @return string|array
     */
    public function uniqueBy()
    {
        return 'email';
    }
}
```

In the example above, if a user already exists with the same email, the row will be updated instead. Behind the scenes, this feature uses the Laravel `upsert` method and the `uniqueBy` method is used for the second argument of the `upsert` method, which lists the column(s) that uniquely identify records within the associated table.

:::warning
All databases except SQL Server require the `uniqueBy` columns to have a "primary" or "unique" index.
:::

### Upserting with specific columns

By default, `upsert`, in case of updating, will update all columns that match model's attributes. However, if you need to update only specific column(s) during `upsert`, you can also implement the `WithUpsertColumns` concern.

```php
class UsersImport implements ToModel, WithUpserts, WithUpsertColumns
{
    /**
     * @return array
     */
    public function upsertColumns()
    {
        return ['name', 'role'];
    }
}
```

In this example, if a user already exists, only "name" and "role" columns will be updated.

## Skipping duplicate rows

In case you want to skip duplicate models, you can implement the `WithSkipDuplicates` concern. 

```php
class UsersImport implements ToModel, WithSkipDuplicates
{
    // No additional methods are required for this concern
}
```

In the example above, if a user already exists with the same primary or unique key, the row will be ignored. Behind the scenes, this feature uses the Laravel `insertOrIgnore` method to insert records while ignoring duplicates, preventing any errors that would normally occur due to duplicate entries.

## Skipping specific rows

In case you want to skip a row, you can return null. 

```php
public function model(array $row)
{
    if (!isset($row[0])) {
        return null;
    }

    return new User([
        'name' => $row[0],
    ]);
}
```

## Possible column names

In case you want to import rows by several possible column names (using `WithHeadingRow`), you can use null coalescing operator (`??`). If the column with the first name (in example _client_name_) exists and is not NULL, return its value; otherwise look for second possible name (in example _client_) etc.

```php
public function model(array $row)
{
    return new User([
        'name' => $row['client_name'] ?? $row['client'] ?? $row['name'] ?? null
    ]);
}
```

## Cascading relation persistence

By default, ToModel doesn't save relations, you can enable this behaviour for `BelongsTo` and `BelongsToMany` relations by adding the `PersistRelations` concern.

```php
class UsersImport implements ToModel, PersistRelations
{
    public function model(array $row)
    {
        $user = new User([
            'name' => $row[0],
        ]);
        
        // There should be a `public function team(): BelongsTo` relation in the User model.
        $user->setRelation('team', new Team(['name' => $row[1]]));
        
        return $user;
    }
}
```

:::warning
`PersistRelations` doesn't work together with BatchInserts.
:::

## Handling persistence on your own

In some cases you might not have an import in which each row is an Eloquent model and you want more control over what happens. In those cases you can use the `OnEachRow` concern.

```php
namespace App\Imports;

use App\Group;
use App\User;
use Maatwebsite\Excel\Row;
use Maatwebsite\Excel\Concerns\OnEachRow;

class UsersImport implements OnEachRow
{
    public function onRow(Row $row)
    {
        $rowIndex = $row->getIndex();
        $row      = $row->toArray();
        
        $group = Group::firstOrCreate([
            'name' => $row[1],
        ]);
    
        $group->users()->create([
            'name' => $row[0],
        ]);
    }
}
```

:::warning
When using `OnEachRow` you cannot use batch inserts, as the model is already persisted in the `onRow` method.
:::

### Macro's and Mixins

The Eloquent Builder/Model has a macro to directly import an excel to Eloquent rows. When using this, make sure your file has a heading row with the database table column names.

```php
User::query()->import('import-users-with-headings.xlsx');
```

If you want to define the mapping yourself, you can use the `importAs` method.

```php
User::query()->importAs('import-users.xlsx', function (array $row) {
    return [
        'name'     => $row[0],
        'email'    => $row[1],
        'password' => 'secret',
    ];
});
```

---

## File: 3.1/imports/multiple-sheets.md

# Multiple Sheets

[[toc]]

When a file has multiple sheets, each sheet will go through the import object. If you want to handle each sheet separately, you'll need to implement the `WithMultipleSheets` concern.

The `sheets()` method expects an array of sheet import objects to be returned. The order of the sheets is important, the first sheet import object in the array will automatically be linked to the first worksheet in the Excel file.

```php
namespace App\Imports;

use Maatwebsite\Excel\Concerns\WithMultipleSheets;

class UsersImport implements WithMultipleSheets 
{
   
    public function sheets(): array
    {
        return [
            new FirstSheetImport()
        ];
    }
}
```

A sheet import class can import the same concerns as a normal import object. 

```php
namespace App\Imports;

use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\ToCollection;

class FirstSheetImport implements ToCollection
{
    public function collection(Collection $rows)
    {
        //
    }
}
```

## Selecting sheets by worksheet index

If you want more control over which sheets are selected and how they are mapped to specific sheet import objects, you can use the sheet index as key. Sheet indices start at 0.

```php
namespace App\Imports;

use Maatwebsite\Excel\Concerns\WithMultipleSheets;

class UsersImport implements WithMultipleSheets 
{
   
    public function sheets(): array
    {
        return [
            0 => new FirstSheetImport(),
            1 => new SecondSheetImport(),
        ];
    }
}
```

## Selecting sheets by worksheet name

If you only know the name of the worksheet and don't know the sheet index, you can also use the worksheet name as a selector. Put the worksheet name as array index to link that worksheet to your sheet import object.

```php
namespace App\Imports;

use Maatwebsite\Excel\Concerns\WithMultipleSheets;

class UsersImport implements WithMultipleSheets 
{
    public function sheets(): array
    {
        return [
            'Worksheet 1' => new FirstSheetImport(),
            'Worksheet 2' => new SecondSheetImport(),
        ];
    }
}
```

:::warning
Sheets that are not explicitly defined in the `sheet()` method, will be ignored and thus not be imported.
:::

## Skipping unknown sheets

When you have defined a sheet **name** or **index** that does not exist a `Maatwebsite\Excel\Exceptions\SheetNotFoundException` will be thrown.

If you want to ignore when a sheet does not exists, you can use the `Maatwebsite\Excel\Concerns\SkipsUnknownSheets` concern.

```php
namespace App\Imports;

use Maatwebsite\Excel\Concerns\WithMultipleSheets;
use Maatwebsite\Excel\Concerns\SkipsUnknownSheets;

class UsersImport implements WithMultipleSheets, SkipsUnknownSheets
{
    public function sheets(): array
    {
        return [
            'Worksheet 1' => new FirstSheetImport(),
            'Worksheet 2' => new SecondSheetImport(),
        ];
    }
    
    public function onUnknownSheet($sheetName)
    {
        // E.g. you can log that a sheet was not found.
        info("Sheet {$sheetName} was skipped");
    }
}
```

### Skipping only specific sheets

If you want to have 1 optional sheet and still have the others fail, you can also let the Sheet import object implement `SkipsUnknownSheets`.

```php
namespace App\Imports;

use Maatwebsite\Excel\Concerns\SkipsUnknownSheets;

class FirstSheetImport implements SkipsUnknownSheets
{
    public function onUnknownSheet($sheetName)
    {
        // E.g. you can log that a sheet was not found.
        info("Sheet {$sheetName} was skipped");
    }
}
```

Now only `FirstSheetImport` will be skipped if it's not found. Any other defined sheet will be skipped.

## Conditional sheet loading

If you want to indicate per import which sheets should be imported, you can use the `Maatwebsite\Excel\Concerns\WithConditionalSheets` trait.

```php
namespace App\Imports;

use Maatwebsite\Excel\Concerns\WithMultipleSheets;
use Maatwebsite\Excel\Concerns\WithConditionalSheets;

class UsersImport implements WithMultipleSheets 
{
    use WithConditionalSheets;

    public function conditionalSheets(): array
    {
        return [
            'Worksheet 1' => new FirstSheetImport(),
            'Worksheet 2' => new SecondSheetImport(),
            'Worksheet 3' => new ThirdSheetImport(),
        ];
    }
}
```

Now you can use the `onlySheets` method to indicate which sheets should be loaded for this import.

```php
$import = new UsersImport();
$import->onlySheets('Worksheet 1', 'Worksheet 3');

Excel::import($import, 'users.xlsx');
```

## Making calculations work when referencing between sheets

When importing you have to implement the `Maatwebsite\Excel\Concerns\WithCalculatedFormulas` concern for Laravel Excel to calculate values from formulas. However, if one sheet creates a calculation by referencing another sheet, e.g. `=Sheet1!A1`, then you also have to implement the concern `Maatwebsite\Excel\Concerns\HasReferencesToOtherSheets`. An example is given below

```php
namespace App\Imports;

use Maatwebsite\Excel\Concerns\WithMultipleSheets;

class UsersImport implements WithMultipleSheets 
{
    public function sheets(): array
    {
        return [
            new FirstSheetImport(),
            new SecondSheetImport()
        ];
    }
}
```

Then if `SecondSheetImport` contains formulas that reference `FirstSheetImport` then `FirstSheetImport` has to be defined using the `HasReferencesToOtherSheets` concern

```php
namespace App\Imports;

use Maatwebsite\Excel\Concerns\ToArray;
use Maatwebsite\Excel\Concerns\HasReferencesToOtherSheets;

class FirstSheetImport implements ToArray, HasReferencesToOtherSheets
{
    public function array(array: $row)
    {
        
    }
}
```

```php
namespace App\Imports;

use Maatwebsite\Excel\Concerns\WithCalculatedFormulas;

class SecondSheetImport implements ToArray, WithCalculatedFormulas
{
    public function array(array: $row)
    {
        
    }
}
```

---

## File: 3.1/imports/progress-bar.md

---
pageClass: no-toc
---

# Progress Bar

You can implement the `WithProgressBar` concern to display a progress bar when importing an Excel file via the console.

For example, your import class could look like this:

```php
<?php

namespace App\Imports;

use App\User;
use Illuminate\Support\Facades\Hash;
use Maatwebsite\Excel\Concerns\Importable;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithProgressBar;

class UsersImport implements ToModel, WithProgressBar
{
    use Importable;

    public function model(array $row)
    {
        return new User([
            'name'     => $row[0],
            'email'    => $row[1],
            'password' => Hash::make($row[2]),
        ]);
    }
}
```

In your console command, you'd use it as follows:

```php
<?php

namespace App\Console\Commands;

use App\Imports\UsersImport;
use Illuminate\Console\Command;

class ImportExcel extends Command
{
    protected $signature = 'import:excel';

    protected $description = 'Laravel Excel importer';

    public function handle()
    {
        $this->output->title('Starting import');
        (new UsersImport)->withOutput($this->output)->import('users.xlsx');
        $this->output->success('Import successful');
    }
}
```

By calling `php artisan import:excel` on the command line, your import will start.
You should now see the start message, the progress bar and (when completed) the success message.

---

## File: 3.1/imports/queued.md

# Queued reading

[[toc]]

## Notes
:::warning
You currently cannot queue `xls` imports. PhpSpreadsheet's Xls reader contains some non-utf8 characters, which makes it impossible to queue.
:::


## Queuing chunks

When using the `WithChunkReading` concern, you can also choose to execute each chunk into a queue job. You can do so by simply adding the `ShouldQueue` contract.

```php
namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\ToModel;
use Illuminate\Contracts\Queue\ShouldQueue;
use Maatwebsite\Excel\Concerns\WithChunkReading;

class UsersImport implements ToModel, WithChunkReading, ShouldQueue
{
    public function model(array $row)
    {
        return new User([
            'name' => $row[0],
        ]);
    }

    public function chunkSize(): int
    {
        return 1000;
    }
}
```

Each chunk of 1000 rows will now be executed into a queue job.

:::warning
`ShouldQueue` is only supported in combination with `WithChunkReading`.
:::

### Explicit queued imports

You can explicitly queue the import by using `::queueImport`.

```
Excel::queueImport(new UsersImport, 'users.xlsx');
```

When using the `Importable` trait you can use the `queue` method:

```
(new UsersImport)->queue('users.xlsx');
```

:::warning
The `ShouldQueue` is always required.
:::

### Implicit queued imports

When `ShouldQueue` is used, the import will automatically be queued.

```
Excel::import(new UsersImport, 'users.xlsx');
```

## Handling failures in queued imports

When queuing imports you might want a way to handle failed imports. You can do this by using the `ImportFailed` event.

```php
namespace App\Imports;

use App\User;
use App\Notifications\ImportHasFailedNotification;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Events\ImportFailed;
use Illuminate\Contracts\Queue\ShouldQueue;
use Maatwebsite\Excel\Concerns\WithChunkReading;

class UsersImport implements ToModel, WithChunkReading, ShouldQueue, WithEvents
{
    public function __construct(User $importedBy)
    {
        $this->importedBy = $importedBy;
    }

    public function registerEvents(): array
    {
        return [
            ImportFailed::class => function(ImportFailed $event) {
                $this->importedBy->notify(new ImportHasFailedNotification);
            },
        ];
    }
}
```

## Appending jobs

When queuing an import an instance of Laravel's `PendingDispatch` is returned. This means you can chain extra jobs that will be added to the end of the queue and only executed if all import jobs are correctly executed.

```php
(new UsersImport)->queue('users.xlsx')->chain([
    new NotifyUserOfCompletedImport(request()->user()),
]);
```

```php
namespace App\Jobs;

use App\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\SerializesModels;

class NotifyUserOfCompletedImport implements ShouldQueue
{
    use Queueable, SerializesModels;

    public $user;

    public function __construct(User $user)
    {
        $this->user = $user;
    }

    public function handle()
    {
        $this->user->notify(new ImportReady());
    }
}
```

## Custom queues

Because `PendingDispatch` is returned, we can also change the queue that should be used.

```php
(new UsersImport)->queue('users.xlsx')->allOnQueue('imports');
```

## Multi-server setup

If you are dealing with a multi-server setup (using e.g. a loadbalancer), you might want to make sure the temporary file is the same for each job. You can achieve this by configuring a remote temporary file in the config.

In `config/excel.php`

```php
'temporary_files' => [
    'remote_disk' => 's3',
],
```

When dealing with a multi server setup as above, it's possible for the clean up that occurs after entire queue has been run to only cleanup the server that the last AfterImportJob runs on. The rest of the server would still have the local temporary file stored on it. In this case your local storage limits can be exceeded and future imports won't be processed. To mitigate this you can set this config value to be true, so that after every queued chunk is processed the local temporary file is deleted on the server that processed it.

```php
'temporary_files' => [
    'force_resync_remote' => true,
],
```


## Job Middleware

If you are using Laravel, [job middleware](https://laravel.com/docs/7.x/queues#job-middleware) can be attached to the import class using the `middleware` method.

```php
namespace App\Imports;

use App\Jobs\Middleware\RateLimited;
use Maatwebsite\Excel\Concerns\Importable;
use Maatwebsite\Excel\Concerns\FromQuery;

class ImportClass implements FromQuery
{
    use Importable;

    public function middleware()
    {
        return [new RateLimited];
    }

    public function retryUntil()
    {
        return now()->addSeconds(5);
    }

    public function query()
    {
        // ...
    }
}
```

---

## File: 3.1/imports/start-row.md

# Start row

[[toc]]

If you want to skip a certain number of rows during an import, you can specify the starting row by implementing the `WithStartRow` concern.

```php
namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithStartRow;

class UsersImport implements ToModel, WithStartRow
{
    public function model(array $row)
    {
        return new User([
            'name' => $row[0],
        ]);
    }

    public function startRow(): int
    {
        return 2;
    }
}
```

---

## File: 3.1/imports/testing.md

# Testing

[[toc]]

The Excel facade can be used to swap the importer to a fake.

## Testing imports

```php
/**
* @test
*/
public function user_can_import_users() 
{
    Excel::fake();
    
    $this->actingAs($this->givenUser())
         ->get('/users/import/xlsx');

    Excel::assertImported('filename.xlsx', 'diskName');
    
    Excel::assertImported('filename.xlsx', 'diskName', function(UsersImport $import) {
        return true;
    });
    
    // When passing the callback as 2nd param, the disk will be the default disk.
    Excel::assertImported('filename.xlsx', function(UsersImport $import) {
        return true;
    });
}
```

## Testing queuing imports

```php
/**
* @test
*/
public function user_can_queue_the_users_import() 
{
    Excel::fake();

    $this->actingAs($this->givenUser())
         ->get('/users/queue/xlsx');

    Excel::assertQueued('filename.xlsx', 'diskName');
    
    Excel::assertQueued('filename.xlsx', 'diskName', function(UsersImport $import) {
        return true;
    });
    
    // When passing the callback as 2nd param, the disk will be the default disk.
    Excel::assertQueued('filename.xlsx', function(UsersImport $import) {
        return true;
    });
}
```

## Testing imports with dynamic file name/path

If you have dynamic naming for files or paths, you can use a regular expression to represent those while testing:

```php
/**
* @test
*/
public function user_can_import_users() 
{
    Excel::fake();
    
    $this->actingAs($this->givenUser())
         ->get('/users/import/xlsx');
    
    // Tells the mock to use regular expressions
    Excel::matchByRegex(); 
    // For a given dynamic named file 'dynamic_1234_filename.xlsx'
    Excel::assertImported('/\w{7}_\d{4}\_\w{8}\.xlsx/', 'diskName');
}
```
Please note that your expression must match only one file/path. If more than one match is found, the test will fail.

---

## File: 3.1/imports/validation.md

# Row Validation

[[toc]]

Sometimes you might want to validate each row before it's inserted into the database. 
By implementing the `WithValidation` concern, you can indicate the rules that each row need to adhere to.

The `rules()` method, expects an array with Laravel Validation rules to be returned. 

```php
<?php

namespace App\Imports;

use App\User;
use Illuminate\Validation\Rule;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\Importable;
use Maatwebsite\Excel\Concerns\WithValidation;

class UsersImport implements ToModel, WithValidation
{
    use Importable;

    public function model(array $row)
    {
        return new User([
            'name'     => $row[0],
            'email'    => $row[1],
            'password' => 'secret',
        ]);
    }

    public function rules(): array
    {
        return [
            '1' => Rule::in(['patrick@spartner.nl']),

             // Above is alias for as it always validates in batches
             '*.1' => Rule::in(['patrick@spartner.nl']),
             
             // Can also use callback validation rules
             '0' => function($attribute, $value, $onFailure) {
                  if ($value !== 'Patrick Brouwers') {
                       $onFailure('Name is not Patrick Brouwers');
                  }
              }
        ];
    }
}
```

## Validating with a heading row

When using the `WithHeadingRow` concern, you can use the heading row name as rule attribute.

```php
<?php

namespace App\Imports;

use App\User;
use Illuminate\Validation\Rule;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\Importable;
use Maatwebsite\Excel\Concerns\WithValidation;
use Maatwebsite\Excel\Concerns\WithHeadingRow;

class UsersImport implements ToModel, WithValidation, WithHeadingRow
{
    use Importable;

    public function model(array $row)
    {
        return new User([
            'name'     => $row['name'],
            'email'    => $row['email'],
            'password' => 'secret',
        ]);
    }

    public function rules(): array
    {
        return [
            'email' => Rule::in(['patrick@spartner.nl']),

             // Above is alias for as it always validates in batches
             '*.email' => Rule::in(['patrick@spartner.nl']),
        ];
    }
}
```

If your validation rules reference other field names, as in the `different`, `lt`, `lte`, `gt`, `gte`, and `same` rules, the field name must be prefixed with `*.` as in the example below, because validation is done in batches.

```php
public function rules(): array
{
    return [
        'maximum' => 'gte:*.minimum',
    ];
}
```

## Custom validation messages

By adding `customValidationMessages()` method to your import, you can specify custom messages for each failure.


```php
/**
* @return array
*/
public function rules(): array
{
    return [
        '1' => Rule::in(['patrick@spartner.nl']),
    ];
}

/**
 * @return array
 */
public function customValidationMessages()
{
    return [
        '1.in' => 'Custom message for :attribute.',
    ];
}
```

## Custom validation attributes

By adding `customValidationAttributes()` method to your import, you can specify custom attribute names for each column.

```php
/**
* @return array
*/
public function rules(): array
{
    return [
        '1' => Rule::in(['patrick@spartner.nl']),
    ];
}

/**
 * @return array
 */
public function customValidationAttributes()
{
    return ['1' => 'email'];
}
```

## Handling validation errors

### Database transactions

The entire import is automatically wrapped in a **database transaction**, that means that *every* error will rollback the entire import (even when using batch inserts).

#### Disable transactions

If you prefer to not have any database transactions around your import (or chunk import), you can change which transaction handler you want to use in the config:

In `config/excel.php`:

```php
'transactions' => [
    'handler' => 'db',
],
```

Supported handlers are currently: `null` or `db`.

#### Custom transaction handlers

If you want a custom transaction handler (for e.g. a MongoDB database), you can add your own handler:

```php
$this->app->make(\Maatwebsite\Excel\Transactions\TransactionManager::class)->extend('your_handler', function() {
    return new YourTransactionHandler();
});
```

The Handler should implement `Maatwebsite\Excel\Transactions\TransactionHandler`.

### Gathering all failures at the end

You can gather all validation failures at the end of the import, when used in conjunction with Batch Inserts. You can try-catch the `ValidationException`. On this exception you can get all failures.

Each failure is an instance of `Maatwebsite\Excel\Validators\Failure`. The `Failure` holds information about which row, which column and what the validation errors are for that cell.

```php
try {
    $import->import('import-users.xlsx');
} catch (\Maatwebsite\Excel\Validators\ValidationException $e) {
     $failures = $e->failures();
     
     foreach ($failures as $failure) {
         $failure->row(); // row that went wrong
         $failure->attribute(); // either heading key (if using heading row concern) or column index
         $failure->errors(); // Actual error messages from Laravel validator
         $failure->values(); // The values of the row that has failed.
     }
}
```

### Skipping failures

Sometimes you might want to skip failures. By using the `SkipsOnFailure` concern, you get control over what happens the moment a validation failure happens. 
When using `SkipsOnFailure` the entire import will **not** be rollbacked when a failure occurs.

```php
<?php

namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Validators\Failure;
use Maatwebsite\Excel\Concerns\Importable;
use Maatwebsite\Excel\Concerns\SkipsOnFailure;
use Maatwebsite\Excel\Concerns\WithValidation;

class UsersImport implements ToModel, WithValidation, SkipsOnFailure
{
    use Importable;

    /**
     * @param Failure[] $failures
     */
    public function onFailure(Failure ...$failures)
    {
        // Handle the failures how you'd like.
    }
}
```

If you automatically want to skip all failed rows and collect the failures at the end of the import, you can use the `Maatwebsite\Excel\Concerns\SkipsFailures` trait.

```php
<?php

namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Validators\Failure;
use Maatwebsite\Excel\Concerns\Importable;
use Maatwebsite\Excel\Concerns\SkipsOnFailure;
use Maatwebsite\Excel\Concerns\WithValidation;
use Maatwebsite\Excel\Concerns\SkipsFailures;

class UsersImport implements ToModel, WithValidation, SkipsOnFailure
{
    use Importable, SkipsFailures;
}
```

Every row that has failed the validation rules, will have been skipped. We can now collect all the failures at the end:

```php
$import = new UsersImport();
$import->import('users.xlsx');

foreach ($import->failures() as $failure) {
     $failure->row(); // row that went wrong
     $failure->attribute(); // either heading key (if using heading row concern) or column index
     $failure->errors(); // Actual error messages from Laravel validator
     $failure->values(); // The values of the row that has failed.
}
```

## Skipping empty rows

Sometimes you might want to skip empty rows, for example when using the `required` validation rule. By using the `SkipsEmptyRows` concern, empty rows will get skipped during both validation **and the import**.

```php
<?php

namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\Importable;
use Maatwebsite\Excel\Concerns\SkipsEmptyRows;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Maatwebsite\Excel\Concerns\WithValidation;

class UsersImport implements ToModel, SkipsEmptyRows, WithHeadingRow, WithValidation
{
    use Importable;
    
    public function rules(): array
    {
        return [
            'name' => [
                'required',
                'string',
            ],
        ];
    }
}
```
## Extend empty rows logic

Along with `SkipsEmptyRows` you can have your own logic to skip rows by having `isEmptyWhen` in the importer

```php
<?php

namespace App\Imports;

use Maatwebsite\Excel\Concerns\Importable;
use Maatwebsite\Excel\Concerns\ToArray;

class UsersImport implements ToArray,
{
    use Importable;
    
    public function isEmptyWhen(array $row): bool
    {
        return $row['name'] === 'John Doe';
    }
}
```

### Skipping errors

Sometimes you might want to skip **all** errors, e.g. duplicate database records. By using the `SkipsOnError` concern, you get control over what happens the moment a model import fails. 
When using `SkipsOnError` the entire import will **not** be rollbacked when an database exception occurs.

```php
<?php

namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\Importable;
use Maatwebsite\Excel\Concerns\SkipsOnError;
use Maatwebsite\Excel\Concerns\WithValidation;

class UsersImport implements ToModel, WithValidation, SkipsOnError
{
    use Importable;

    /**
     * @param \Throwable $e
     */
    public function onError(\Throwable $e)
    {
        // Handle the exception how you'd like.
    }
}
```

If you automatically want to skip all exceptions and collect them at the end of the import, you can use the `Maatwebsite\Excel\Concerns\SkipsErrors` trait.

```php
<?php

namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Validators\Failure;
use Maatwebsite\Excel\Concerns\Importable;
use Maatwebsite\Excel\Concerns\SkipsOnError;
use Maatwebsite\Excel\Concerns\WithValidation;
use Maatwebsite\Excel\Concerns\SkipsErrors;

class UsersImport implements ToModel, WithValidation, SkipsOnError
{
    use Importable, SkipsErrors;
}
```

Every row that has errored, will have been skipped. We can now collect all the errors at the end:

```php
$import = new UsersImport();
$import->import('users.xlsx');

dd($import->errors());
```

## Row Validation without ToModel

If you are not using the `ToModel` concern, you can very easily do row validation by just using the Laravel validator.

```php
<?php

namespace App\Imports;

use App\User;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Validator;
use Maatwebsite\Excel\Concerns\ToCollection;

class UsersImport implements ToCollection
{
    public function collection(Collection $rows)
    {
         Validator::make($rows->toArray(), [
             '*.0' => 'required',
         ])->validate();

        foreach ($rows as $row) {
            User::create([
                'name' => $row[0],
            ]);
        }
    }
}
```

## Prepare data for validation
Sometimes data may not pass validation directly, but still be valid. When this happens you may want to tweak the data slightly before sending it to the validator, to do this you may add a `prepareForValidation` method on your import, this method receives row data as well as the row number and should return the manipulated row data.

```php
class UsersImport implements WithValidation
{
    public function prepareForValidation($data, $index)
    {
        $data['email'] = $data['email'] ?? $this->myOtherWayOfFindingTheEmail($data);
        
        return $data;
    }
}
```

## Configuring the validator
If you want to add conditional validation or complex validation that cannot be expressed through rules you can configure the validator similar to how you would do this with a [Form request](https://laravel.com/docs/master/validation#form-request-validation)

:::tip Manual validation
You can use `$validator->getData()` to get access to the data under validation
:::

```php
class UsersImport implements WithValidation
{
    public function withValidator($validator)
    {
        $validator->after(function ($validator) {
            if ($this->somethingElseIsInvalid()) {
                $validator->errors()->add('field', 'Something is wrong with this field!');
            }
        });

        // or...

        $validator->sometimes('*.email', 'required', $this->someConditionalRequirement());
    }
}
```

:::tip Validation rules
For a list of all validation rules, please refer to the [Laravel document](https://laravel.com/docs/master/validation#available-validation-rules).
:::

:::tip Validating Across Multiple Rows 
Validation rules that check multiple rows (such as `distinct`) will work only when using `WithBatchInserts` or `ToCollection` concerns.
:::

---

## File: 4.x/index.md

<meta http-equiv="refresh" content="0;url=/4.x/getting-started/" />

---

## File: 4.x/architecture/concerns.md

# Concerns

[[toc]]

Most of the export/import configuration is done by using **Concerns**. 

## Contracts

Concerns are basically just simple interfaces. Implementing them will make the object adhere to a 
certain contract. This contract can request specific methods that e.g. data can be passed through.

For instance, the `FromCollection` requests the Export object to implement a `collection` method, that needs to return a `Collection` instance.

```php
namespace App\Exports;

use App\User;
use Maatwebsite\Excel\Concerns\FromCollection;

class UsersExport implements FromCollection
{
    public function collection(): Collection
    {
        return User::all();
    }
}
```

## Pointer interface

In other cases it might not ask for any methods to be implemented, but merely functions as a pointer interface.

For instance, the `ShouldAutoSize` concern doesn't pass on any specific information, but does tell the Export process that the columns need to be automatically sized.

```php
namespace App\Exports;

use App\User;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;

class UsersExport implements ShouldAutoSize
{

}
```

## 2. Official Technical Reference & Guides (SpartnerNL/laravel-excel-docs)

## File: README.md

<meta http-equiv="refresh" content="0;url=/4.x/getting-started/" />

---

## File: index.md

---
head:
  - - meta
    - http-equiv: refresh
      content: 0;url=/4.x/getting-started/
---

Redirecting to the [Laravel Excel 4.x documentation](/4.x/getting-started/)…

---

## File: package.json

{
    "private": true,
    "type": "module",
    "engines": {
        "node": ">=20.19.0"
    },
    "scripts": {
        "docs:dev": "vitepress dev",
        "docs:build": "vitepress build",
        "docs:preview": "vitepress preview"
    },
    "devDependencies": {
        "@fontsource-variable/ibm-plex-sans": "^5.3.0",
        "@fontsource/ibm-plex-mono": "^5.3.0",
        "markdown-it-container": "^4.0.0",
        "vitepress": "^1.6.4",
        "vitepress-plugin-llms": "^1.14.0"
    }
}

---

## File: 2.1/index.md

<meta http-equiv="refresh" content="0;url=/2.1/getting-started/" />

---

## File: 2.1/blade/load-view.md

# @Blade to Excel

We can utilise the magic of Laravel's Blade engine to power our Excel export. Sharing a view, loading a view per sheet, creating a html table inside a view, basic CSS styling, ...

# Loading a view for a single sheet

We can load a view for every sheet we create with `->loadView()`.

    Excel::create('New file', function($excel) {

        $excel->sheet('New sheet', function($sheet) {

            $sheet->loadView('folder.view');

        });

    });

# Using different views for different sheets

    Excel::create('New file', function($excel) {

        $excel->sheet('First sheet', function($sheet) {

            $sheet->loadView('view_first');
        });

        $excel->sheet('Second sheet', function($sheet) {

            $sheet->loadView('view_second');
        });

    });

# Sharing a view for all sheets

We can share a view for all sheets with `shareView()`.

    Excel::shareView('folder.view')->create();

# Unsetting a view for a sheet

When we are using a shared view, but we don't want to use a view for the current sheet, we can use `->unsetView()`.

    $sheet->unsetView();

---

## File: 2.1/blade/styling.md

# Styling sheets

### General styling

If you want to change the general styling of your sheet (not cell or range specific), you can use the `->setStyle()` method or any of the other setters which can be found inside the export documentation.

    // Font family
    $sheet->setFontFamily('Comic Sans MS');

    // Set font with ->setStyle()`
    $sheet->setStyle(array(
        'font' => array(
            'name'      =>  'Calibri',
            'size'      =>  12,
            'bold'      =>  true
        )
    ));

### Styling with PHPExcel methods

It's possible to style the sheets and specific cells with help of PHPExcel methods. This package includes a lot of shortcuts (see export documentation), but also always the use of the native methods.

    // Set background color for a specific cell
    $sheet->getStyle('A1')->applyFromArray(array(
        'fill' => array(
            'type'  => PHPExcel_Style_Fill::FILL_SOLID,
            'color' => array('rgb' => 'FF0000')
        )
    ));

### Using HTML tags

Most of the HTML tags are supported.

    <html>

        
        <h1>Big title</h1>

        
        **Bold cell**
        **Bold cell**

        
        *Italic cell*

        
        

    </html>

> Inside the `view.php` config you can change how these tags will be interpreted by Excel by default.

### Using HTML attributes

Some of the basic styling can be done with HTML attributes.

    <html>

        
        Big title

        
        Bold cell

        
        Bold cell

        
        Italic cell

        
        Cell with width of 100

        
        Cell with height of 100

    </html>

### Styling through inline-styles

It's possible to use inline styles inside your view files. Most of the general styles are supported.

    <html>

        
        Cell

    </html>

> Inside the reference guide you can find a list of supported styles.

### Styling through external CSS file

Styling can be done through an external CSS file.

External css file:

    #cell {
        background-color: #000000;
        color: #ffffff;
    }

    .cell {
        background-color: #000000;
        color: #ffffff;
    }

    tr td {
        background-color: #ffffff;
    }

    tr > td {
        border-bottom: 1px solid #000000;
    }

Table:

```html
<html>
    {{ HTML::style('css/table.css') }}

    <!-- Cell styled with class -->
    <td class="cell">Cell</td>

    <!-- Cell styled with ID -->
    <td id="cell">Cell</td>
</html>
```

> Inside the reference guide you can find a list of supported styles.

> It's advised to include `<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />` into the view to fix problems with UTF-8 encoding.

---

## File: 2.1/blade/vars.md

# Passing variables to the view

### As parameter

We can pass variables to the view by using the second parameter inside the `loadView()` method.

	$sheet->loadView('view', array('key' => 'value'));

### With with()

Alternatively you can use the `with()` method which works the same as with Laravel views.

	// Using normal with()
	$sheet->loadView('view')
		  ->with('key', 'value');

	// using dynamic with()
	$sheet->loadView('view')
		  ->withKey('value');

---

## File: 2.1/changelog/version-1.md

# Version 1

### 1.3.5
- PHPExcel 1.8.1 compatibility
- Clean-up ServiceProvider
- Fix short array syntax for PHP5.3

### 1.3.4
- Fix usage of sheet callback when modifying an existing file
- Modifying existing files improvements (support style overriding)
- Add text-indent support to HtmlReader
- Add simple sheet password protection
- Add support for exporting multiple pdf pages
- Add inline cell formatting to Blade

### 1.3.3
- Fix issue with different start row in chunk filter

### 1.3.2
- Custom value binders
- Html reader update

### 1.3.1
- Fix short array syntax

### 1.3.0
- Additional headers with export() 
- Float, integer, string, timestamps problems
- Cell content ending by zeros
- Images in html
- Font family bug
- Setting row number of row with headings

### 1.2.3
- PDF writer
- Include charts config
- Chunk filter with selected sheet
- Compatibility fix with new PHPExcel release
- setDateColumns fix
- Optional dependencies to require-dev
- Several bugfixes

### 1.2.2
- Chunk filter fixes
- Isset() CellCollection fixes
- PHP 5.3 support
- Missing border styles
- Add CSV settings (delimiter, enclosure, lineEnding) to ExcelFile objects

### 1.2.1
- Fix with() method parameters

### 1.2.0
- Filters
- Chunk filter (with chunked importer)
- ExcelFile (method) injections
- NewExcelFile (method) injections
- Edit existing worksheets
- Converting existing worksheet
- Laravel 4.* + 5.0 support

### 1.1.9
- PHP 5.3 fixes

### 1.1.8
- PHP 5.3 support
- fromArray bugfix

### 1.1.7
- Fix heading generation for export with `->fromArray()`
- Bugfix for non-Unix kernels
- Enhanced CSS parser (thanks to `tijsverkoyen/CssToInlineStyles`)
- Support for nested CSS styles
- Support for multiple css attributes per class
- Support for internal and external CSS files
- Support for inline style blocks (`<style>`)

### 1.1.6

- Provides.json fix
- DocBlock fixes
- Define Illuminate dependencies inside composer.json
- Better HTML rowspan handling views
- use new CellCollection() instead of ::make, to support upcoming Laravel version
- Workaround for long integers
- Add support to `wrap-text` in views
- Fix empty dates parsing
- Support local stylesheets in view parsing
- Push tr classes to td-children in views
- Support for dynamically appending rows to an empty (new) sheet
- Fix separator typo in config

### 1.1.5

- Select sheets by index with `Excel::selectSheetsByIndex(0,1)->load(...)`
- Separator typo fix
- Added `->setFileName()` method
- Use `->setTitle()` only for workbook title not for setting the filename anymore
- Made `setAutoSize()` chainable for other sheet methods
- Export config setting to disable pre calculation of formulas during export
- Export config setting to set the autosizing method (approx|exact)
- Auto sizing export from view fix

### 1.1.4

- Fix for importing 0 as null
- New unit tests

### 1.1.3

- Cell writer `->setBorder()` fix

### 1.1.2

- Fix for multiple imports on one pageload
- Multiple new import heading conversions (`Config: excel::import.heading: true|false|slugged|ascii|numeric|hashed|trans|original`)

### 1.1.1

- Retrieve workbook and sheet title during import (`->getTitle()`)

### 1.1.0

- `Limit()`, `skip()` and `take()` support for fetching results
- Set default page margins
- Export Eloquent models directly (`fromModel()`)
- Auto generate the first row (table heading) from the array keys
- Manipulate cells and cell ranges inside a closure
- Set cell backgrounds/fonts/values, ...
- Create/append/prepend new row/rows
- Manipulate row cells (background, fonts, ...)
- Config value default alignment on merge cells
- DocBlock updates to support better use of IDE autocomplete features
- Parse width and height inside views
- Parse images in views
- Optional to ASCII conversion of imported header columns (array indices)
- Config values for default null comparision and start cells for exports
- Changed default CSV enclosure to `"`
- Support for Laravel package installer

### 1.0.9

- Blade to Excel export fix for PHP5.3

### 1.0.8

- File format identifier enhancements

### 1.0.7

- Set workbook properties fix
- Extra units tests

### 1.0.6

- BatchReader fix

### 1.0.5

- Date parsing fix

### 1.0.4

- Fix calling $this in  anonymous function to set locale and cache

### 1.0.3

- Table headings to attribute names undefined offset fix
- Composer.json enhancements
- Documentation fixes

### 1.0.2

- Cell Collection fixes
- Default autosizing bugfixes
- ->load() accepts input encoding parameter
- Documentation fixes

### 1.0.1

- Column width and row height bugfix
- Typo fixes

### 1.0.0

- New documentation
- More logical file structure (dividing into files, separating the different functionality (import / export)
- More optional config settings
- CSV Delimiter fixes
- CSV Encoding
- Import into collections (to support utilisation of ->first(), etc.)
- Better column selecting and result limiting
- Batch upload
- Import dates as Carbon objects by default
- Advanced file import through config coordinates
- Select sheets to import
- Create closure (Excel::create('file', function($excel) { } ))
- More logical syntax for creating new files, syntaxes of creating by array and creating with view should be as identical as possible
- Rewrite of sheet building for views
- Using closures to build sheets for normal sheet creation
- Better support for calling native PHPExcel methods
- Better use of setters
- Config setting to set default store behavior
- Column/row width
- Share views over all sheets + easy views switching per sheet
- External stylesheet with classes/ids parsing for views
- Colspan fix
- Th default styling
- Caching / Cell caching

---

## File: 2.1/changelog/version-2.md

# Version 2

### 2.0.4
- PHPExcel 1.8.1 compatibility
- Clean-up ServiceProvider

### 2.0.3
- Fix usage of sheet callback when modifying an existing file
- Modifying existing files improvements (support style overriding)
- Add text-indent support to HtmlReader
- Add simple sheet password protection
- Add support for exporting multiple pdf pages
- Add inline cell formatting to Blade

### 2.0.2
- Fix issue with different start row in chunk filter

### 2.0.1
- Custom value binders
- Html reader update

### 2.0.0
- Laravel 5 release

---

## File: 2.1/export/array.md

# Creating a sheet from an array

## Array

To create a new file from an array use `->fromArray($source, $nullValue, $startCell, $strictNullComparison, $headingGeneration)` inside the sheet closure.

    Excel::create('Filename', function($excel) {

        $excel->sheet('Sheetname', function($sheet) {

            $sheet->fromArray(array(
                array('data1', 'data2'),
                array('data3', 'data4')
            ));

        });

    })->export('xls');

Alternatively you can use `->with()`.

    $sheet->with(array(
        array('data1', 'data2'),
        array('data3', 'data4')
    ));

If you want to pass variables inside the closure, use `use($data)`

    $data = array(
        array('data1', 'data2'),
        array('data3', 'data4')
    );

    Excel::create('Filename', function($excel) use($data) {

        $excel->sheet('Sheetname', function($sheet) use($data) {

            $sheet->fromArray($data);

        });

    })->export('xls');

### Null comparision

By default 0 is shown as an empty cell. If you want to change this behaviour, you can pass true as 4th parameter:

    // Will show 0 as 0
    $sheet->fromArray($data, null, 'A1', true);

> To change the default behaviour, you can use `excel::export.sheets.strictNullComparison` config setting.

## Eloquent model

It's also possible to pass an Eloquent model and export it by using `->fromModel($model)`. The method accepts the same parameters as fromArray

## Auto heading generation

By default the export will use the keys of your array (or model attribute names) as first row (header column). To change this behaviour you can edit the default config setting (`excel::export.generate_heading_by_indices`) or pass `false` as 5th parameter:

    // Won't auto generate heading columns
    $sheet->fromArray($data, null, 'A1', false, false);

---

## File: 2.1/export/autofilter.md

# Auto filter

To enable the auto filter use `->setAutoFilter($range = false)`.

    // Auto filter for entire sheet
    $sheet->setAutoFilter();

    // Set auto filter for a range
    $sheet->setAutoFilter('A1:E10');

---

## File: 2.1/export/autosize.md

# Auto size

By default the exported file be automatically auto sized. To change this behaviour you can either change the config or use the setters:

    // Set auto size for sheet
    $sheet->setAutoSize(true);

    // Disable auto size for sheet
    $sheet->setAutoSize(false);

    // Disable auto size for columns
    $sheet->setAutoSize(array(
        'A', 'C'
    ));

> The default config setting can be found in: `export.php`.

---

## File: 2.1/export/call.md

# Calling PHPExcel's native methods

It's possible to call all native PHPExcel methods on the `$excel` and `$sheet` objects.

### Calling Workbook methods

Example:

    // Get default style for this workbook
    $excel->getDefaultStyle();

### Calling worksheet methods

Example:

    // Protect cells
    $sheet->protectCells('A1', $password);

> Head over to PHPOffice to learn more about the native methods.

---

## File: 2.1/export/cells.md

# Cell manipulation

    $sheet->cell('A1', function($cell) {

        // manipulate the cell
        $cell->setValue('data1');

    });

    $sheet->cells('A1:A5', function($cells) {

        // manipulate the range of cells

    });

### Set background

To change the background of a range of cells we can use `->setBackground($color, $type, $colorType)`

    // Set black background
    $cells->setBackground('#000000');

### Change fonts

    // Set with font color
    $cells->setFontColor('#ffffff');

    // Set font family
    $cells->setFontFamily('Calibri');

    // Set font size
    $cells->setFontSize(16);

    // Set font weight to bold
    $cells->setFontWeight('bold');

    // Set font
    $cells->setFont(array(
        'family'     => 'Calibri',
        'size'       => '16',
        'bold'       =>  true
    ));

### Set borders

    // Set all borders (top, right, bottom, left)
    $cells->setBorder('solid', 'none', 'none', 'solid');

    // Set borders with array
    $cells->setBorder(array(
        'top'   => array(
            'style' => 'solid'
        ),
    ));

### Set horizontal alignment

    // Set alignment to center
    $cells->setAlignment('center');

### Set vertical alignment

    // Set vertical alignment to middle
     $cells->setValignment('center');

---

## File: 2.1/export/export.md

# Exporting

To download the created file, use `->export($ext)` or `->download($ext)`.

#### Export to Excel5 (xls)

    Excel::create('Filename', function($excel) {

    })->export('xls');

    // or
    ->download('xls');

#### Export to Excel2007 (xlsx)

    ->export('xlsx');

    // or
    ->download('xlsx');

#### Export to CSV

    ->export('csv');

    // or
    ->download('csv');

> You can set the default enclosure and delimiter inside the config

#### Export to PDF

To export files to pdf, you will have to include `"dompdf/dompdf": "~0.6.1"`, `"mpdf/mpdf": "~6.1"` or `"tecnick.com/tcpdf": "~6.0.0"` in your `composer.json` and change the `export.pdf.driver` config setting accordingly.

    ->export('pdf');

---

## File: 2.1/export/format.md

# Column formatting

To tell Excel how it should interpret certain columns, you can use `->setColumnFormat($array)`.

    // Format column as percentage
    $sheet->setColumnFormat(array(
        'C' => '0%'
    ));
    
    // Format a range with e.g. leading zeros
    $sheet->setColumnFormat(array(
        'A2:K2' => '0000'
    ));

    // Set multiple column formats
    $sheet->setColumnFormat(array(
        'B' => '0',
        'D' => '0.00',
        'F' => '@',
        'F' => 'yyyy-mm-dd',
    ));

> Go to the reference guide to see a list of available formats.

---

## File: 2.1/export/freeze.md

# Freeze rows

If you want to freeze a cell, row or column, use:

    // Freeze first row
    $sheet->freezeFirstRow();

    // Freeze the first column
    $sheet->freezeFirstColumn();

    // Freeze the first row and column
    $sheet->freezeFirstRowAndColumn();

    // Set freeze
    $sheet->setFreeze('A2');

---

## File: 2.1/export/index.md

# Simple Excel Export

### Basics

A new file can be created using the `create` method with the filename as first parameter.

    Excel::create('Filename');

To manipulate the creation of the file you can use the callback with `LaravelExcelWriter` parameter

    Excel::create('Filename', function($excel) {

        // Call writer methods here

    });

### Changing properties

There are a couple of properties we can change inside the closure. Most of them are set to the config values by default. See `app/config/packages/maatwebsite/excel/config.php`.

    Excel::create('Filename', function($excel) {

        // Set the title
        $excel->setTitle('Our new awesome title');

        // Chain the setters
        $excel->setCreator('Spartner')
              ->setCompany('Spartner');

        // Call them separately
        $excel->setDescription('A demonstration to change the file properties');

    });

> Go to the reference guide to see a list of available properties.

---

## File: 2.1/export/injection.md

# NewExcelFile injections

Following the Laravel 5.0 philosophy with its new awesome FormRequest injections, we introduce you NewExcelFile injections.

## NewExcelFile class

This NewExcelFile is a wrapper for a new Excel file. Inside the `getFilename()` you can declare the wanted filename.

    class UserListExport extends \Maatwebsite\Excel\Files\NewExcelFile {

        public function getFilename()
        {
            return 'filename';
        }
    }

## Usage

You can inject these NewExcelFiles inside the __constructor or inside the method (when using Laravel 5.0), in e.g. the controller.

    class ExampleController extends Controller {

        public function exportUserList(UserListExport $export)
        {
            // work on the export
            return $export->sheet('sheetName', function($sheet)
            {

            })->export('xls');
        }

    }

## Export Handlers

To decouple your Excel-export code completely from the controller, you can use the export handlers.

    class ExampleController extends Controller {

        public function exportUserList(UserListExport $export)
        {
            // Handle the export
            $export->handleExport();
        }

    }

The `handleExport()` method will dynamically call a handler class which is your class name appended with `Handler`

    class UserListExportHandler implements \Maatwebsite\Excel\Files\ExportHandler {

        public function handle(UserListExport $export)
        {
            // work on the export
            return $export->sheet('sheetName', function($sheet)
            {

            })->export('xls');
        }

    }

---

## File: 2.1/export/merge.md

# Column merging

### Merging cells

To merge a range of cells, use `->mergeCells($range)`.

    $sheet->mergeCells('A1:E1');

### Merging columns and rows

To merge columns and rows, use `->setMergeColumn($array)`.

    $sheet->setMergeColumn(array(
        'columns' => array('A','B','C','D'),
        'rows' => array(
            array(2,3),
            array(5,11),
        )
    ));

---

## File: 2.1/export/rows.md

# Row manipulation

### Manipulate certain row

#### Change cell values

    // Manipulate first row
    $sheet->row(1, array(
         'test1', 'test2'
    ));

    // Manipulate 2nd row
    $sheet->row(2, array(
        'test3', 'test4'
    ));

#### Manipulate row cells

    // Set black background
    $sheet->row(1, function($row) {

        // call cell manipulation methods
        $row->setBackground('#000000');

    });

### Append row

    // Append row after row 2
    $sheet->appendRow(2, array(
        'appended', 'appended'
    ));

    // Append row as very last
    $sheet->appendRow(array(
        'appended', 'appended'
    ));

### Prepend row

    // Add before first row
    $sheet->prependRow(1, array(
        'prepended', 'prepended'
    ));

    // Add as very first
    $sheet->prependRow(array(
        'prepended', 'prepended'
    ));

### Append multiple rows

    // Append multiple rows
    $sheet->rows(array(
        array('test1', 'test2'),
        array('test3', 'test4')
    ));

    // Append multiple rows
    $sheet->rows(array(
        array('test5', 'test6'),
        array('test7', 'test8')
    ));

---

## File: 2.1/export/sheet-styling.md

# Sheet styling

### General styling

If you want to change the general styling of your sheet (not cell or range specific), you can use the `->setStyle()` method.

    // Set font with ->setStyle()`
    $sheet->setStyle(array(
        'font' => array(
            'name'      =>  'Calibri',
            'size'      =>  15,
            'bold'      =>  true
        )
    ));

### Fonts

To change the font for the current sheet use `->setFont($array)`:

    $sheet->setFont(array(
        'family'     => 'Calibri',
        'size'       => '15',
        'bold'       => true
    ));

#### Separate setters

    // Font family
    $sheet->setFontFamily('Comic Sans MS');

    // Font size
    $sheet->setFontSize(15);

    // Font bold
    $sheet->setFontBold(true);

### Borders

You can set borders for the sheet, by using:

    // Sets all borders
    $sheet->setAllBorders('thin');

    // Set border for cells
    $sheet->setBorder('A1', 'thin');

    // Set border for range
    $sheet->setBorder('A1:F10', 'thin');

> Go to the reference guide to see a list of available border styles

---

## File: 2.1/export/sheets.md

# Sheets

### Creating a sheet

To create a new sheet inside our newly created file, use `->sheet('Sheetname')` with callback of `LaravelExcelWorksheet` type parameter.

    Excel::create('Filename', function($excel) {

        $excel->sheet('Sheetname', function($sheet) {

            // Sheet manipulation

        });

    })->export('xls');


### Creating multiple sheets

You can set as many sheets as you like inside the file:

    Excel::create('Filename', function($excel) {

        // Our first sheet
        $excel->sheet('First sheet', function($sheet) {

        });

        // Our second sheet
        $excel->sheet('Second sheet', function($sheet) {

        });

    })->export('xls');

### Changing properties

There are a couple of properties we can change inside the closure. Most of them are set to the config values by default. See `app/config/packages/maatwebsite/excel/config.php`.

    Excel::create('Filename', function($excel) {

        $excel->sheet('Sheetname', function($sheet) {

            $sheet->setOrientation('landscape');

        });

    })->export('xls');

> Go to the reference guide to see a list of available properties.

### Default page margin

It's possible to set the default page margin inside the config file `excel::export.sheets`.
It accepts boolean, single value or array.

To manually set the page margin you can use: `->setPageMargin()`

    // Set top, right, bottom, left
    $sheet->setPageMargin(array(
        0.25, 0.30, 0.25, 0.30
    ));

    // Set all margins
    $sheet->setPageMargin(0.25);
    
### Password protecting a sheet
    
A sheet can be password protected with `$sheet->protect()`:

    // Default protect
    $sheet->protect('password');
    
    // Advanced protect
    $sheet->protect('password', function(\PHPExcel_Worksheet_Protection $protection) {
        $protection->setSort(true);
    });

---

## File: 2.1/export/sizing.md

# Cell size

### Set column width

To set the column width use `->setWidth($cell, $width)`.

    // Set width for a single column
    $sheet->setWidth('A', 5);

    // Set width for multiple cells
    $sheet->setWidth(array(
        'A'     =>  5,
        'B'     =>  10
    ));

### Set row height

To set the row height use `->setHeight($row, $height)`.

    // Set height for a single row
    $sheet->setHeight(1, 50);

    // Set height for multiple rows
    $sheet->setHeight(array(
        1     =>  50,
        2     =>  25
    ));

### Set cell size

To set the cell size use `->setSize($cell, $width, $height)`.

    // Set size for a single cell
    $sheet->setSize('A1', 500, 50);

    $sheet->setSize(array(
        'A1' => array(
            'width'     => 50,
            'height'    => 500
        )
    ));

---

## File: 2.1/export/store.md

# Store on server

To store the created file on the server, use `->store($ext, $path = false, $returnInfo = false)` or `->save()`.

### Normal export to default storage path

By default the file will be stored inside the `storage/exports` folder, which has been defined in the `export.php` config file.

    Excel::create('Filename', function($excel) {

        // Set sheets

    })->store('xls');

### Normal export to custom storage path

If you want to use a custom storage path (e.g. to separate the files per client), you can set the folder as the second parameter.

    ->store('xls', storage_path('excel/exports'));

### Store and export

    ->store('xls')->export('xls');

### Store and return storage info

If you want to return storage information, set the third paramter to true or change the config setting inside `export.php`.

    ->store('xls', false, true);

|Key|Explanation|
|---|-----------|
|**full**| Full path with filename
|**path**| Path without filename
|**file**| Filename
|**title**| File title
|**ext**| File extension

> Make sure your storage folder is **writable**!

---

## File: 2.1/getting-started/config.md

# Config

### Laravel 4

Laravel Excel includes several config settings for import-, export-, view- and CSV-specific settings.
Use the artisan publish command to publish the config file to your project.

    php artisan config:publish maatwebsite/excel

The config files can now be found at `app/config/packages/maatwebsite/excel`

### Laravel 5

To publish the config settings in Laravel 5 use:

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

This will add an `excel.php` config file to your config folder.

---

## File: 2.1/getting-started/contributing.md

# Contribution Guide

### Bug fixes

**ALL** bug fixes should be made to appropriate branch (e.g. `1.1` for 1.1.* bug fixes). Bug fixes should never be sent to the `master` branch.

### Pull Requests

Every pull request should pass the unit tests. If you include new functionality, make sure you include a test. Pull requests will be evaluated and possibly added to the next stable release.

### Feature Requests

If you have an idea for a new feature you would like to see added to Laravel Excel, you may create an issue on GitHub with `[Request]` in the title. The feature request will then be reviewed by @SpartnerNL.

### Coding Guidelines

Laravel, and therefore Spartner's Laravel Excel follows the [PSR-0](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md) and [PSR-1](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md) coding standards. In addition to these standards, below is a list of other coding standards that should be followed:

- Namespace declarations should be on the same line as `<?php`.
- Class opening `{` should be on the same line as the class name.
- Function and control structure opening `{` should be on a separate line.
- Interface and Trait names are suffixed with `Interface` (`FooInterface`) and `Trait` (`FooTrait`) respectively.

---

## File: 2.1/getting-started/index.md

# Installation

Require this package in your `composer.json` and update composer. This will download the package and PHPExcel of PHPOffice.

#### Laravel 4

    "maatwebsite/excel": "~1.3"
    
#### Laravel 5

    "maatwebsite/excel": "~2.1.0"

After updating composer, add the ServiceProvider to the providers array in `app/config/app.php`

    Maatwebsite\Excel\ExcelServiceProvider::class,

You can use the facade for shorter code. Add this to your aliasses:

    'Excel' => Maatwebsite\Excel\Facades\Excel::class,

The class is binded to the ioC as `excel`

    $excel = App::make('excel');

---

## File: 2.1/getting-started/license.md

# License

This package is licensed under LGPL. You are free to use it in personal and commercial projects. The code can be forked and modified, but the original copyright author should always be included!

---

## File: 2.1/getting-started/requirements.md

# Requirements

- PHP version >= 5.3.7
- Laravel >= 4.1
- PHPOffice PHPExcel >= 1.8.0 (included by composer.json)
- PHP extension php_zip enabled (required if you need PHPExcel to handle .xlsx .ods or .gnumeric files)
- PHP extension php_xml enabled
- PHP extension php_gd2 enabled (optional, but required for exact column width autocalculation)

---

## File: 2.1/import/batch.md

# Batch import

### Import a folder

To import an entire folder (only XLS, XLSX and CSV files will be imported), set the folder as the first parameter.

    Excel::batch('app/storage/uploads', function($rows, $file) {

        // Explain the reader how it should interpret each row,
        // for every file inside the batch
        $rows->each(function($row) {

            // Example: dump the firstname
            dd($row->firstname);

        });

    });

### Import multiple files

It's also possible to provide an array of files to import.

    $files = array(
        'file1.xls',
        'file2.xls'
    );

    Excel::batch($files, function($rows, $file) {

    });

### Import a folder and multiple sheets

When your files contain multiple sheets, you should also loop the sheets

    Excel::batch('app/storage/uploads', function($sheets, $file) {

        $sheets->each(function($sheet) {

        });

    });

---

## File: 2.1/import/cache.md

# Caching and Cell caching

### Cell caching

You can enable cell caching inside the config `excel.php`. You can choose between a couple of drivers and change a couple of settings. By default the caching is **enabled** and will use **in memory** caching.

### Remembering results

If you want to remember the results you can use `->remember($minutes)`. Next time you will load the same file (if it's still inside the cache), it will return the cached results.

    // Remember for 10 minutes
    $results = $reader->remember(10)->get();

---

## File: 2.1/import/calculation.md

# Calculate formulas

By default formulas inside the file are being calculated and it's result will be returned. Inside `import.php` config you can change the default behaviour by setting `calculate` to the desired preference.

If you want to enable/disable it for a single import, you can use `->calculate($boolean)`

    // Enable calculation
    $reader->calculate();

    // Disable calculation
    $reader->calculate(false);

---

## File: 2.1/import/chunk.md

# Chunk importer

When dealing with big files, it's better to import the data in big chunks. You can enable this with `filter('chunk')`;
To import it into chunks you can use `chunk($size, $callback)` instead of the normal `get()`. The first parameter is the size of the chunk. The second parameter is a closure which will return the results.

    Excel::filter('chunk')->load('file.csv')->chunk(250, function($results)
    {
            foreach($results as $row)
            {
                // do stuff
            }
    });

## ExcelFile class example:

When working with ExcelFile injections (in the constructor or as method injection), you can enable the chunk filter inside the ExcelFile class

    class UserListImport extends \Maatwebsite\Excel\Files\ExcelFile {

        public function getFile()
        {
            return 'file.csv';
        }

        public function getFilters()
        {
            return [
                'chunk'
            ];
        }

    }

Injected ExcelFile example:

    public function importUserList(UserListImport $import)
    {
        $import->chunk(250, function($results)
        {
            // do stuff
            // or return true if you want to stop importing.
        });
    }

## Queued chunks

We automatically queue every chunk for you, if you have enabled the queue driver in your config. 

If you want to by-pass the behaviour, you can pass `false` as the third parameter of `chunk($size, $callback, $shouldQueue)`.

A non-default job queue may be specified by passing its name as the third parameter of `chunk($size, $callback, $shouldQueue)`.

---

## File: 2.1/import/config.md

# Import by Config

When using advanced Excel files (e.g. without any heading columns), it can be complicated to import these.
`->byConfig()` will help you handle this problem.

Inside `excel::import.sheets` config you can find an example.

    Excel::load('file.xls')->byConfig('excel::import.sheets', function($sheet) {

        // The firstname getter will correspond with a cell coordinate set inside the config
        $firstname = $sheet->firstname;

    });

> **Note:** if you are using multiple sheets. `->byConfig` will loop through all sheets. If these getters are only exist on one sheet, you can always use `->selectSheets()`.

---

## File: 2.1/import/convert.md

# Converting

You can convert from one filetype to another by using `->convert()`

    Excel::load('file.csv', function($file) {

        // modify stuff

    })->convert('xls');

---

## File: 2.1/import/dates.md

# Dates

By default the dates will be parsed as a **[Carbon object](https://github.com/briannesbitt/Carbon)**. You can disable date formatting completly inside `import.php` by setting `dates.enabled` to `false`.

To enable/disable date formatting for a single import, use `->formatDates($boolean, $format)`

    // Format the dates
    $reader->formatDates(true);

    // Disable date formatting
    $reader->formatDates(false);

    // Format dates + set date format
    $reader->formatDates(true, 'Y-m-d');

### Format dates

By default the dates are **not formatted**, but returned as a Carbon object. There are a couple of options to format them.

#### Formatting results after ->get()

Inside your loop you can utilise the Carbon method `->format($dateFormat)`

    $rows->each(function($row) {

        $created_at = $row->created_at->format('Y-m-d');

    });

#### Setting a default date format

Inside the config you can set a default date format. A Carbon object will no longer be returned.

Or you can use `->setDateFormat()`

    $reader->setDateFormat('Y-m-d');

### Setting custom date columns

Cells which are not Excel formatted dates will not be parsed as a date. To force this behaviour (or to use this with CSV imports), you can set these date columns manually: `->setDateColumns()`

    $reader->setDateColumns(array(
        'created_at',
        'deleted_at'
    ))->get();

---

## File: 2.1/import/edit.md

# Editing existing files

You can edit existing Excel files, by loading them and after modification exporting them.

    Excel::load('file.csv', function($file) {

        // modify stuff

    })->export('csv');

---

## File: 2.1/import/extra.md

# Extra

### Disable using first row as collection attributes

By default we will use the first row of a file as table heading (so as attribute names for the collection).
You can change the default behaviour inside `import.php` with `import.heading`.

To disable this for a single import, use `->noHeading()`.

    $reader->noHeading();

### Setting the cell name separator
By default collection attribute names will be set by looking at the first row columns. Spaces will be translated to `_`.

**E.g. Created at -> created_at**

The default behaviour can be changed inside the `import.php` config by changing `'separator'`. Or you can use `->setSeparator($separator)`.

    $reader->setSeparator('-');

### Ignoring empty cells
By default empty cells will not be ignored and presented as null inside the cell collection.

To change the default behaviour, you can change `'ignoreEmpty`' inside `import.php` or use `->ignoreEmpty()`.

    $reader->ignoreEmpty();

### Input encoding

Inside the `import.php` config you can change the input encoding. In most cases **UTF-8** will be the best solution. Hower if you dump your results make sure your HTML page has this exact same meta charset!

Optionally you can pass the input encoding inside the `->load()` method.

    // When utilising a closure, you can pass the input encoding as third parameter.
    Excel::load('filename.csv', function($reader) {

    }, 'UTF-8');

    // or without a closure, you can use it as second parameter.
    Excel::load('filename.csv', 'UTF-8');

### CSV Settings

Inside the `csv.php` config you can change the default settings, like the `delimiter`, the `enclosure` and the `line_ending`.

---

## File: 2.1/import/formatting.md

# Custom formatting values

By default Laravel Excel uses PHPExcel's default value binder to intelligently format a cells value when reading it. You may override this behavior by passing in your own value binder to suit your specific needs. Value binders must implement PHPExcel_Cell_IValueBinder and have a bindValue method. They may also extend PHPExcel_Cell_DefaultValueBinder to return the default behavior.
    
    use PHPExcel_Cell;
    use PHPExcel_Cell_DataType;
    use PHPExcel_Cell_IValueBinder;
    use PHPExcel_Cell_DefaultValueBinder;

    class MyValueBinder extends PHPExcel_Cell_DefaultValueBinder implements PHPExcel_Cell_IValueBinder
    {
        public function bindValue(PHPExcel_Cell $cell, $value = null)
        {
            if (is_numeric($value))
            {
                $cell->setValueExplicit($value, PHPExcel_Cell_DataType::TYPE_NUMERIC);

                return true;
            }
            
            // else return default behavior
            return parent::bindValue($cell, $value);
        }
    }

    $myValueBinder = new MyValueBinder;

    $reader = Excel::setValueBinder($myValueBinder)->load('file.xls');
    // Reader methods

Available PHPExcel_Cell_DataType's are TYPE_STRING, TYPE_FORMULA, TYPE_NUMERIC, TYPE_BOOL, TYPE_NULL, TYPE_INLINE and TYPE_ERROR

To reset the value binder back to default and/or before calling Laravel Excel after setting a custom value binder you need to call the resetValueBinder method.

    Excel::resetValueBinder();

---

## File: 2.1/import/index.md

# Importing a file

To start importing a file, you can use `->load($filename)`. The callback is optional.

    Excel::load('file.xls', function($reader) {

        // reader methods

    });

---

## File: 2.1/import/injection.md

# ExcelFile injections

Following the Laravel 5.0 philosophy with its new awesome FormRequest injections, we introduce you ExcelFile injections.

## ExcelFile class

This class is a wrapper for a file on your server. Inside the `getFile()` method you return the filename and it's location. Inside the `getFilters()` method you can enable filters, like the chunk filter.

    class UserListImport extends \Maatwebsite\Excel\Files\ExcelFile {

        public function getFile()
        {
            return storage_path('exports') . '/file.csv';
        }

        public function getFilters()
        {
            return [
                'chunk'
            ];
        }

    }

If you want to have the `getFile()` dynamic based on user's input, you can easily do:

    public function getFile()
    {
        // Import a user provided file
        $file = Input::file('report');
        $filename = $this->doSomethingLikeUpload($file);

        // Return it's location
        return $filename;
    }

## Usage

You can inject these ExcelFiles inside the __constructor or inside the method (when using Laravel 5.0), in e.g. the controller.

    class ExampleController extends Controller {

        public function importUserList(UserListImport $import)
        {
            // get the results
            $results = $import->get();
        }

    }

## CSV Settings

You can pass through optional CSV settings, like `$delimiter`, `$enclosure` and `$lineEnding` as protected properties of the class.

    class UserListImport extends \Maatwebsite\Excel\Files\ExcelFile {

        protected $delimiter  = ',';
        protected $enclosure  = '"';
        protected $lineEnding = '\r\n';

    }

## Import Handlers

To decouple your Excel-import code completely from the controller, you can use the import handlers.

    class ExampleController extends Controller {

        public function importUserList(UserListImport $import)
        {
            // Handle the import
            $import->handleImport();
        }

    }

The `handleImport()` method will dynamically call a handler class which is your class name appended with `Handler`

    class UserListImportHandler implements \Maatwebsite\Excel\Files\ImportHandler {

        public function handle(UserListImport $import)
        {
            // get the results
            $results = $import->get();
        }

    }

---

## File: 2.1/import/results.md

# Handling imported results

### Getting all sheets and rows

After you have loaded a file, you can `->get()` the results like so:

    Excel::load('file.xls', function($reader) {

    })->get();

or

    Excel::load('file.xls', function($reader) {

        // Getting all results
        $results = $reader->get();

        // ->all() is a wrapper for ->get() and will work the same
        $results = $reader->all();

    });

> The `->get()` and `->all()` methods will return a sheet or row collection, depending on the amount of sheets the file has. You can disable this feature inside the `import.php` config by setting `'force_sheets_collection'` to `true`. When set to true it will always return a sheet collection.

### Table heading as attributes

By default the first row of the Excel file will be used as attributes.

    // Get the firstname
    $row->firstname;

> **Note**: by default these attributes will be converted to a slug. You can change the default inside the config `excel::import.heading`. Available options are: `true|false|slugged|ascii|numeric|hashed|trans|original`

> True and slugged will be converted to ASCII as well when `excel::import.to_ascii` is set to true. You can change the default separator as well inside the config.

### Collections

Sheets, rows and cells are collections, this means after doing a `->get()` you can use all default collection methods.

    // E.g. group the results
    $reader->get()->groupBy('firstname');

### Getting the first sheet or row

To get the first sheet or row, you can utilise `->first()`.

    $reader->first();

> **Note:** depending on the config `'force_sheets_collection'` it will return the first row or sheet.

### Workbook and sheet title

It's possible to retrieve the workbook and sheet title with `->getTitle()`.

    // Get workbook title
    $workbookTitle = $reader->getTitle();

    foreach($reader as $sheet)
    {
        // get sheet title
        $sheetTitle = $sheet->getTitle();
    }

### Limiting the file reading

##### Taking rows

When you only want to return the first x rows of a sheet, you can use `->takeRows()` or `->limitRows()`.

    // You can either use ->takeRows()
    $reader->takeRows(10);

    // Or ->limitRows()
    $reader->limitRows(10);

##### Skipping rows

When you want to skip a certain amount of rows you can use `->skipRows()` or `->limitRows(false, 10)`

    // Skip 10 results
    $reader->skipRows(10);

    // Skip 10 results with limit, but return all other rows
    $reader->limitRows(false, 10);

    // Skip and take
    $reader->skipRows(10)->takeRows(10);

##### Taking columns

When you only want to return the first x columns of a sheet, you can use `->takeColumns()` or `->limitColumns()`.

    // You can either use ->takeColumns()
    $reader->takeColumns(10);

    // Or ->limitColumns()
    $reader->limitColumns(10);

##### Skipping columns

When you want to skip a certain amount of columns you can use `->skipColumns()` or `->limitColumns(false, 10)`

    // Skip 10 results
    $reader->skipColumns(10);

    // Skip 10 results with limit, but return all other columns
    $reader->limitColumns(false, 10);

    // Skip and take
    $reader->skipColumns(10)->takeColumns(10);

### Result mutators

When you want to get an array instead of an object, you can use `->toArray()`.

    $reader->toArray();

When you want an object, you can alternativly (instead of get() or all()) use `->toObject()`.

    $reader->toObject();

### Displaying results

You can dump the results to a readable output by using `->dump()` or `->dd()`.

    // Dump the results
    $reader->dump();

    // Dump results and die
    $reader->dd();

### Iterating the results

You can iterate the results by using `->each()`.

    // Loop through all sheets
    $reader->each(function($sheet) {

        // Loop through all rows
        $sheet->each(function($row) {

        });

    });

> Alternatively you can also `foreach` the results.

---

## File: 2.1/import/select.md

# Selecting sheets and columns

### Selecting one specific sheet
If you want to select a single sheet, you can use `->selectSheets($name)`. Only that sheet will be loaded.

    Excel::selectSheets('sheet1')->load();

### Selecting multiple sheets
If you want to select multiple sheets inside your file, you can pass an array as the parameter;

    Excel::selectSheets('sheet1', 'sheet2')->load();

### Selecting sheets by index

    // First sheet
    Excel::selectSheetsByIndex(0)->load();

    // First and second sheet
    Excel::selectSheetsByIndex(0, 1)->load();

### Selecting columns

If you want to select only a couple of columns, you can use `->select($columns)` or pass an array as the first parameter of `->get($columns)`.

    // Select
    $reader->select(array('firstname', 'lastname'))->get();

    // Or
    $reader->get(array('firstname', 'lastname'));

> All get methods (like all(), first(), dump(), toArray(), ...) accept an array of columns.

---

## File: 2.1/reference-guide/borders.md

# Available border styles

| Style name  | PHPExcel class reference|
| ------------- |-----------------|
|none|PHPExcel_Style_Border::BORDER_NONE
|dashDot|PHPExcel_Style_Border::BORDER_DASHDOT
| dashDotDot|PHPExcel_Style_Border::BORDER_DASHDOTDOT
| dashed |PHPExcel_Style_Border::BORDER_DASHED
| dotted |PHPExcel_Style_Border::BORDER_DOTTED
| double |PHPExcel_Style_Border::BORDER_DOUBLE
| hair |PHPExcel_Style_Border::BORDER_HAIR
| medium |PHPExcel_Style_Border::BORDER_MEDIUM
| mediumDashDot |PHPExcel_Style_Border::BORDER_MEDIUMDASHDOT
| mediumDashDotDot |PHPExcel_Style_Border::BORDER_MEDIUMDASHDOTDOT
| mediumDashed |PHPExcel_Style_Border::BORDER_MEDIUMDASHED
| slantDashDot |PHPExcel_Style_Border::BORDER_SLANTDASHDOT
|  thick|PHPExcel_Style_Border::BORDER_THICK
|  thin|PHPExcel_Style_Border::BORDER_THIN

---

## File: 2.1/reference-guide/closures.md

# Closures

| Method  | Closure class |
| ------------- |-------------|
| create()      | Maatwebsite\Excel\Writers\LaravelExcelWriter |
| load()     | Maatwebsite\Excel\Readers\LaravelExcelReader    |
| batch | Maatwebsite\Excel\Readers\Batch     |
| sheet() | Maatwebsite\Excel\Classes\LaravelExcelWorksheet     |
| cells() | Maatwebsite\Excel\Writers\CellWriter     |
| row() | Maatwebsite\Excel\Writers\CellWriter    |

---

## File: 2.1/reference-guide/css-styles.md

# Available CSS styles

Styles that can be used inside an external CSS file or as inline CSS.

| Style name  | Example Value |
| ------------- |-------------|
| background(-color)      | #000000 |
| color     | #FFFFFF     |
| font-weight | bold     |
| font-style | italic     |
| font-weight | bold     |
| font-size | 20px     |
| font-family | Open Sans     |
| text-decoration | underline     |
| text-align | center    |
| vertical-align | middle     |
| border(-*) | 1px dashed #CCC     |
| width | 100(px)    |
| height | 1100(px) |

---

## File: 2.1/reference-guide/file-properties.md

# Available file properties

Properties that can be set with `$excel->set{$property}()`

| Property name  |
| ------------- |
|creator
|lastModifiedBy
|title
|description
|subject
|keywords
|category
|manager
|company

---

## File: 2.1/reference-guide/formatting.md

# Available column formatting

| Format name  | PHPExcel class reference|
| ------------- |-----------------|
|General|PHPExcel_Style_NumberFormat::FORMAT_GENERAL
|@|PHPExcel_Style_NumberFormat::FORMAT_TEXT
|0|PHPExcel_Style_NumberFormat::FORMAT_NUMBER
|0.00|PHPExcel_Style_NumberFormat::FORMAT_NUMBER_00
|#,##0.00|PHPExcel_Style_NumberFormat::FORMAT_NUMBER_COMMA_SEPARATED1
|#,##0.00_-|PHPExcel_Style_NumberFormat::FORMAT_NUMBER_COMMA_SEPARATED2
|0%|PHPExcel_Style_NumberFormat::FORMAT_PERCENTAGE
|0.00%|PHPExcel_Style_NumberFormat::FORMAT_PERCENTAGE_00
|yyyy-mm-dd|PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDD2
|yy-mm-dd|PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDD
|dd/mm/yy|PHPExcel_Style_NumberFormat::FORMAT_DATE_DDMMYYYY
|d/m/y|PHPExcel_Style_NumberFormat::FORMAT_DATE_DMYSLASH
|d-m-y|PHPExcel_Style_NumberFormat::FORMAT_DATE_DMYMINUS
|d-m|PHPExcel_Style_NumberFormat::FORMAT_DATE_DMMINUS
|m-y|PHPExcel_Style_NumberFormat::FORMAT_DATE_MYMINUS
|mm-dd-yy|PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX14
|d-mmm-yy|PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX15
|d-mmm|PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX16
|mmm-yy|PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX17
|m/d/yy h:mm|PHPExcel_Style_NumberFormat::FORMAT_DATE_XLSX22
|d/m/y h:mm|PHPExcel_Style_NumberFormat::FORMAT_DATE_DATETIME
|h:mm AM/PM|PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME1
|h:mm:ss AM/PM|PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME2
|h:mm|PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME3
|h:mm:ss|PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME4
|mm:ss|PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME5
|h:mm:ss|PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME6
|i:s.S|PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME7
|h:mm:ss;@|PHPExcel_Style_NumberFormat::FORMAT_DATE_TIME8
|yy/mm/dd;@|PHPExcel_Style_NumberFormat::FORMAT_DATE_YYYYMMDDSLASH
|"$"#,##0.00_-|PHPExcel_Style_NumberFormat::FORMAT_CURRENCY_USD_SIMPLE
|$#,##0_-|PHPExcel_Style_NumberFormat::FORMAT_CURRENCY_USD
|[$EUR ]#,##0.00_-|PHPExcel_Style_NumberFormat::FORMAT_CURRENCY_EUR_SIMPLE

---

## File: 2.1/reference-guide/sheet-properties.md

# Available sheet properties

Properties that can be set with `$sheet->set{$property}()`

| Property name  | Possible value|
| ------------- |-----------------|
|orientation| string
|paperSize| integer
|scale| integer
|fitToPage| boolean/int *
|fitToHeight| boolean/int *
|fitToWidth| boolean/int *
|columnsToRepeatAtLeft| array
|rowsToRepeatAtTop| array
|horizontalCentered| boolean
|verticalCentered| boolean
|printArea| range
|firstPageNumber| integer

* See [PHPExcel's Page Setup: Scaling options](https://github.com/PHPOffice/PHPExcel/blob/develop/Documentation/markdown/Overview/08-Recipes.md#page-setup-scaling-options) for more information

---

## File: 3.0/index.md

<meta http-equiv="refresh" content="0;url=/3.0/getting-started/" />

---

## File: 3.0/exports/collection.md

# Exporting collections

The easiest way to start an export is to create a custom export class. We'll use an invoices export as example.

Create a new class called `InvoicesExport` in `app/Exports`:

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\FromCollection;

class InvoicesExport implements FromCollection
{
    public function collection()
    {
        return Invoice::all();
    }
}
```

In your controller we can now download this export:

```php
public function export() 
{
    return Excel::download(new InvoicesExport, 'invoices.xlsx');
}
```

Or store it on a (e.g. s3) disk:

```php
public function storeExcel() 
{
    return Excel::store(new InvoicesExport, 'invoices.xlsx', 's3');
}
```

:bulb: More about storing exports can be found in the [storing exports on disk page](/3.0/exports/store.html).

### Dependency injection

In case your export needs dependencies, you can inject the export class:

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\FromCollection;

class InvoicesExport implements FromCollection
{
    public function __construct(InvoicesRepository $invoices)
    {
        $this->invoices = $invoices;
    }

    public function collection()
    {
        return $this->invoices->all();
    }
}
```

```php
public function export(Excel $excel, InvoicesExport $export) 
{
    return $excel->download($export, 'invoices.xlsx');
}
```

### Strict null comparisons

If you want your `0` values to be actual `0` values in your excel sheet instead of `null` (empty cells), you can use `WithStrictNullComparison`.

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithStrictNullComparison;

class InvoicesExport implements FromCollection, WithStrictNullComparison
{
    public function __construct(InvoicesRepository $invoices)
    {
        $this->invoices = $invoices;
    }

    public function collection()
    {
        return $this->invoices->all();
    }
}
```

### Collection macros

The package provides some macro to Laravel's collection class to easily download or store a collection.

#### Downloading a collection as Excel

```php
(new Collection([[1, 2, 3], [1, 2, 3]]))->downloadExcel(
    $filePath,
    $writerType = null,
    $headings = false
)
```

#### Storing a collection on disk

```php
(new Collection([[1, 2, 3], [1, 2, 3]]))->storeExcel(
    $filePath,
    $disk = null,
    $writerType = null,
    $headings = false
)
```

---

## File: 3.0/exports/column-formatting.md

# Formatting columns

You can easily format an entire column, by using `WithColumnFormatting`.
In case you want something more custom, it's suggested to use the `AfterSheet` event to directly interact with the underlying `Worksheet` class.

```php
namespace App\Exports;

use PhpOffice\PhpSpreadsheet\Shared\Date;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
use Maatwebsite\Excel\Concerns\WithColumnFormatting;
use Maatwebsite\Excel\Concerns\WithMapping;

class InvoicesExport implements WithColumnFormatting, WithMapping
{
    public function map($invoice): array
    {
        return [
            $invoice->invoice_number,
            Date::dateTimeToExcel($invoice->created_at),
            $invoice->total
        ];
    }
    
    /**
     * @return array
     */
    public function columnFormats(): array
    {
        return [
            'B' => NumberFormat::FORMAT_DATE_DDMMYYYY,
            'C' => NumberFormat::FORMAT_CURRENCY_EUR_INTEGER,
        ];
    }
}
```

### Dates

When working with dates, it's recommended to use `\PhpOffice\PhpSpreadsheet\Shared\Date::dateTimeToExcel()` in your mapping
to ensure correct parsing of dates.

### Auto size

If you want Laravel Excel to perform an automatic width calculation, use the following code. 

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\ShouldAutoSize;

class InvoicesExport implements ShouldAutoSize
{
    ...
}
```

---

## File: 3.0/exports/concerns.md

# Export concerns

| Interface | Explanation |
|---- |----|
|`Maatwebsite\Excel\Concerns\FromCollection`| Use a Laravel Collection to populate the export. |
|`Maatwebsite\Excel\Concerns\FromQuery`| Use an Eloquent query to populate the export. | 
|`Maatwebsite\Excel\Concerns\FromView`| Use a (Blade) view to populate the export. |
|`Maatwebsite\Excel\Concerns\WithTitle`| Set the Workbook or Worksheet title. |
|`Maatwebsite\Excel\Concerns\WithHeadings`| Prepend a heading row. |
|`Maatwebsite\Excel\Concerns\WithMapping`| Format the row before it's written to the file. |
|`Maatwebsite\Excel\Concerns\WithColumnFormatting`| Format certain columns. |
|`Maatwebsite\Excel\Concerns\WithMultipleSheets`| Enable multi-sheet support. Each sheet can have its own concerns (except this one). |
|`Maatwebsite\Excel\Concerns\ShouldAutoSize`| Auto-size the columns in the worksheet. |
|`Maatwebsite\Excel\Concerns\WithStrictNullComparison`| Uses strict comparisions when testing cells for null value. |
|`Maatwebsite\Excel\Concerns\WithEvents`| Register events to hook into the PhpSpreadsheet process. |
|`Maatwebsite\Excel\Concerns\WithCustomQuerySize`| Allows Exportables that implement the FromQuery concern, to provide their own custom query size. |
|`Maatwebsite\Excel\Concerns\WithCustomCsvSettings`| Allows to run custom Csv settings for this specific exportable. |
|`Maatwebsite\Excel\Concerns\WithCharts`| Allows to run one or multiple PhpSpreadsheet Chart instances. |
|`Maatwebsite\Excel\Concerns\WithDrawings`| Allows to run one or multiple PhpSpreadsheet (Base)Drawing instances. |
|`Maatwebsite\Excel\Concerns\WithCustomStartCell`| Allows to specify a custom start cell. Do note that this is only supported for FromCollection exports. |

### Traits

| Trait | Explanation |
|---- |----|
|`Maatwebsite\Excel\Concerns\Exportable` | Add download/store abilities right on the export class itself.
|`Maatwebsite\Excel\Concerns\RegistersEventListeners` | Auto-register the available event listeners. |

---

## File: 3.0/exports/export-formats.md

# Export formats

By default the export format is determined by the extension of the file, however if you want 
to explicitly configured this, you can pass through the export format as 2nd parameter. 

## XLSX

```php
(new InvoicesExport)->download('invoices.xlsx', \Maatwebsite\Excel\Excel::XLSX);
```

## CSV

```php
(new InvoicesExport)->download('invoices.csv', \Maatwebsite\Excel\Excel::CSV);
```

## TSV

```php
(new InvoicesExport)->download('invoices.tsv', \Maatwebsite\Excel\Excel::TSV);
```

## ODS

```php
(new InvoicesExport)->download('invoices.ods', \Maatwebsite\Excel\Excel::ODS);
```

## XLS

```php
(new InvoicesExport)->download('invoices.xls', \Maatwebsite\Excel\Excel::XLS);
```

## SLK

```php
(new InvoicesExport)->download('invoices.slk', \Maatwebsite\Excel\Excel::SLK);
```

## XML

```php
(new InvoicesExport)->download('invoices.xml', \Maatwebsite\Excel\Excel::XML);
```

## GNUMERIC

```php
(new InvoicesExport)->download('invoices.gnumeric', \Maatwebsite\Excel\Excel::GNUMERIC);
```

## HTML

```php
(new InvoicesExport)->download('invoices.html', \Maatwebsite\Excel\Excel::HTML);
```

## MPDF

```php
(new InvoicesExport)->download('invoices.pdf', \Maatwebsite\Excel\Excel::MPDF);
```

## DOMPDF

```php
(new InvoicesExport)->download('invoices.pdf', \Maatwebsite\Excel\Excel::DOMPDF);
```

## TCPDF

```php
(new InvoicesExport)->download('invoices.pdf', \Maatwebsite\Excel\Excel::TCPDF);
```

---

## File: 3.0/exports/exportables.md

# Exportables

In the previous example, we used the `Excel::download` facade to start an export. 

Laravel Excel also provides a `Maatwebsite\Excel\Concerns\Exportable` trait, to make export classes exportable.

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\Exportable;

class InvoicesExport implements FromCollection
{
    use Exportable;

    public function collection()
    {
        return Invoice::all();
    }
}
```

We can now download the export without the need for the facade:

```php
return (new InvoicesExport)->download('invoices.xlsx');
```

Or store it on a disk:

```php
return (new InvoicesExport)->store('invoices.xlsx', 's3');
```

### Responsable

The previous example can be made even shorter when adding Laravel's `Responsable` interface to the export class:

```php
namespace App\Exports;

use Illuminate\Contracts\Support\Responsable;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\Exportable;

class InvoicesExport implements FromCollection, Responsable
{
    use Exportable;
    
    /**
    * It's required to define the fileName within
    * the export class when making use of Responsable.
    */
    private $fileName = 'invoices.xlsx';

    public function collection()
    {
        return Invoice::all();
    }
}
```

You can now easily return the export class, without the need of calling `->download()`.

```php
return new InvoicesExport();
```

---

## File: 3.0/exports/extending.md

# Extending

[[toc]]

## Events

The export process has a few events you can leverage to interact with the underlying 
classes to add custom behaviour to the export.

You are able to hook into the parent package by using events.
No need to use convenience methods like "query" or "view", if you need full control over the export.

The events will be activated by adding the `WithEvents` concern. Inside the `registerEvents` method, you 
will have to return an array of events. The key is the Fully Qualified Name (FQN) of the event and the value is a callable event listener.
This can either be a closure, array-callable or invokable class.

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Events\BeforeExport;
use Maatwebsite\Excel\Events\BeforeWriting;
use Maatwebsite\Excel\Events\BeforeSheet;

class InvoicesExport implements WithEvents
{
    /**
     * @return array
     */
    public function registerEvents(): array
    {
        return [
            // Handle by a closure.
            BeforeExport::class => function(BeforeExport $event) {
                $event->writer->getProperties()->setCreator('Patrick');
            },
            
            // Array callable, refering to a static method.
            BeforeWriting::class => [self::class, 'beforeWriting'],
            
            // Using a class with an __invoke method.
            BeforeSheet::class => new BeforeSheetHandler()
        ];
    }
    
    public static function beforeWriting(BeforeWriting $event) 
    {
        //
    }
}
```

Do note that using a `Closure` will not be possible in combination with queued exports, as PHP cannot serialize the closure.
In those cases it might be better to use the `RegistersEventListeners` trait.

### Auto register event listeners

By using the `RegistersEventListeners` trait you can auto-register the event listeners,
without the need of using the `registerEvents`. The listener will only be registered if the method is created. 

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Concerns\RegistersEventListeners;
use Maatwebsite\Excel\Events\BeforeExport;
use Maatwebsite\Excel\Events\BeforeWriting;
use Maatwebsite\Excel\Events\BeforeSheet;
use Maatwebsite\Excel\Events\AfterSheet;

class InvoicesExport implements WithEvents
{
    use Exportable, RegistersEventListeners;
    
    public static function beforeExport(BeforeExport $event)
    {
        //
    }

    public static function beforeWriting(BeforeWriting $event)
    {
        //
    }

    public static function beforeSheet(BeforeSheet $event)
    {
        //
    }

    public static function afterSheet(AfterSheet $event)
    {
        //
    }
}
```

### Global event listeners

Event listeners can also be configured globally, if you want to perform the same actions on all exports in your app.
You can add them to e.g. your `AppServiceProvider` in the `register()` method.

```php
Writer::listen(BeforeExport::class, function () {
    //
});

Writer::listen(BeforeWriting::class, function () {
    //
});

Sheet::listen(BeforeSheet::class, function () {
    //
});

Sheet::listen(AfterSheet::class, function () {
    //
});
```

### Available events

| Event name | Payload | Explanation |
|---- |----| ----|
|`Maatwebsite\Excel\Events\BeforeExport` | `$event->writer : Writer` | Event gets raised at the start of the process. | 
| `Maatwebsite\Excel\Events\BeforeWriting` | `$event->writer : Writer` | Event gets raised before the download/store starts. |
| `Maatwebsite\Excel\Events\BeforeSheet` | `$event->sheet : Sheet` | Event gets raised just after the sheet is created. |
| `Maatwebsite\Excel\Events\AfterSheet` | `$event->sheet : Sheet` | Event gets raised at the end of the sheet process. |

## Custom Concerns

You can add custom concerns to your app. This can be useful if you want to share some concerns over a few projects or want to open source your custom concerns.

Let's add a `WithCustomProperties` concern to your app. You could add these concerns to `app/Exports/Concerns`, but any location will do as long as it can be auto-loaded by composer.

```php
namespace App\Exports\Concerns;

interface WithCustomProperties
{
    /**
     *
     * @return string
     */
    public function description(): string;
}
```

Next to this concern we will create a concern handler. `WithCustomerPropertiesHandler`. This class can also be added to `app/Exports/Concerns`, but is again completely free of choice. 
A concern handler is basically just an invokable class. It receives your exportable object and either a `Writer` or `Sheet` object, depending on the choosen event.

```php
namespace App\Exports\Concerns;

use App\Exports\Concerns\WithCustomProperties;
use Maatwebsite\Excel\Writer;

class WithCustomPropertiesHandler
{
    /**
     * @param WithCustomProperties $exportable
     * @param Writer               $writer
     */
    public function __invoke(WithCustomProperties $exportable, Writer $writer)
    {
        $writer
            ->getDelegate()
            ->getProperties()
            ->setDescription(
                $exportable->description()
            );
    }
}
```

We then will register this concern in a service provider. You could use `app/Providers/AppServiceProvider` for this.

```php
public function register()
{
    Excel::extend(WithCustomProperties::class, new WithCustomPropertiesHandler);
}
```

:bulb: `::extend` accepts a callable as second parameter. It's also possible to pass a closure.

```php
public function register()
{
    Excel::extend(WithCustomProperties::class, function(WithCustomProperties $exportable, Writer $writer) {
        $writer->getDelegate()->getProperties()->setDescription($exportable->description());
    });
}
```

You can also bind concern handlers to different hooks. By default a concern handler is always bound to the `BeforeWriting` event. You can easily customize this, by supplying a 3rd parameter.

```php
public function register()
{
    Excel::extend(WithCustomProperties::class, new WithCustomPropertiesHandler, BeforeExport::class);
}
```

## Macroable

Both `Writer` and `Sheet` are "macroable" which means they can easily be extended to fit your needs. 
Both Writer and Sheet have a `->getDelegate()` method which returns the underlying PhpSpreadsheet class. 
This will allow you to add custom macros as shortcuts to PhpSpreadsheet methods that are not available in this package. 

### Writer

```php
use \Maatwebsite\Excel\Writer;

Writer::macro('setCreator', function (Writer $writer, string $creator) {
    $writer->getDelegate()->getProperties()->setCreator($creator);
});
```

### Sheet

```php
use \Maatwebsite\Excel\Sheet;

Sheet::macro('setOrientation', function (Sheet $sheet, $orientation) {
    $sheet->getDelegate()->getPageSetup()->setOrientation($orientation);
});
```

### Customize  
You can create your own macro to add custom methods to a spreadsheet instance. 

For example, to add styling to a cell, we first create a macro, let's call it `styleCells`:


```php
use \Maatwebsite\Excel\Sheet;

Sheet::macro('styleCells', function (Sheet $sheet, string $cellRange, array $style) {
    $sheet->getDelegate()->getStyle($cellRange)->applyFromArray($style);
});
```

Once the macro is created, it can be used inside the `registerEvents()` method as such:

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Events\BeforeExport;
use Maatwebsite\Excel\Events\AfterSheet;

class InvoicesExport implements WithEvents
{
    /**
     * @return array
     */
    public function registerEvents(): array
    {
        return [
            BeforeExport::class  => function(BeforeExport $event) {
                $event->writer->setCreator('Patrick');
            },
            AfterSheet::class    => function(AfterSheet $event) {
                $event->sheet->setOrientation(\PhpOffice\PhpSpreadsheet\Worksheet\PageSetup::ORIENTATION_LANDSCAPE);

                $event->sheet->styleCells(
                    'B2:G8',
                    [
                        'borders' => [
                            'outline' => [
                                'borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THICK,
                                'color' => ['argb' => 'FFFF0000'],
                            ],
                        ]
                    ]
                );
            },
        ];
    }
}
```

Feel free to use the above macro, or be creative and invent your own!

For PhpSpreadsheet methods, please refer to their documentation: https://phpspreadsheet.readthedocs.io/

---

## File: 3.0/exports/from-query.md

# From Query

In the previous example, we did the query inside the export class. 
While this is a good solution for small exports, 
for bigger exports this will come at a hefty performance price.

By using the `FromQuery` concern, we can prepare a query for an export. Behind the scenes this query is executed in chunks.

In the `InvoicesExport` class, add the `FromQuery` concern, and return a query. Be sure to not `->get()` the results!

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\Exportable;

class InvoicesExport implements FromQuery
{
    use Exportable;

    public function query()
    {
        return Invoice::query();
    }
}
```

We can still download the export in the same way:

```php
return (new InvoicesExport)->download('invoices.xlsx');
```

### Customizing the query

It's easy to pass custom parameters to the query, 
by simply passing them as dependencies to the export class.

#### As constructor param

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\Exportable;

class InvoicesExport implements FromQuery
{
    use Exportable;

    public function __construct(int $year)
    {
        $this->year = $year;
    }

    public function query()
    {
        return Invoice::query()->whereYear('created_at', $this->year);
    }
}
```

The year can now be passed as dependency to the export class:

```php
return (new InvoicesExport(2018))->download('invoices.xlsx');
```

#### As setter

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\Exportable;

class InvoicesExport implements FromQuery
{
    use Exportable;

    public function forYear(int $year)
    {
        $this->year = $year;
        
        return $this;
    }

    public function query()
    {
        return Invoice::query()->whereYear('created_at', $this->year);
    }
}
```

We can adjust the year by using the `forYear` method:

```php
return (new InvoicesExport)->forYear(2018)->download('invoices.xlsx');
```

---

## File: 3.0/exports/from-view.md

# From View

Exports can be created from a Blade view, by using the `FromView` concern.

```php
namespace App\Exports;

use Illuminate\Contracts\View\View;
use Maatwebsite\Excel\Concerns\FromView;

class InvoicesExport implements FromView
{
    public function view(): View
    {
        return view('exports.invoices', [
            'invoices' => Invoice::all()
        ]);
    }
}
```

It will convert an HTML table into an Excel spreadsheet. For example; `users.blade.php`:

```
<table>
    <thead>
    <tr>
        <th>Name</th>
        <th>Email</th>
    </tr>
    </thead>
    <tbody>
    @foreach($users as $user)
        <tr>
            <td>{{ $user->name }}</td>
            <td>{{ $user->email }}</td>
        </tr>
    @endforeach
    </tbody>
</table>
```

---

## File: 3.0/exports/index.md

## :rocket: 5 minute quick start

:muscle: Create an export class in `app/Exports`

You may do this by using the `make:export` command.

```
php artisan make:export UsersExport --model=User
```

If you prefer to create the export manually, you can create the following in `app/Exports`:

```php
<?php

namespace App\Exports;

use App\User;
use Maatwebsite\Excel\Concerns\FromCollection;

class UsersExport implements FromCollection
{
    public function collection()
    {
        return User::all();
    }
}
```

:fire: In your controller you can call this export now:

```php

use App\Exports\UsersExport;
use Maatwebsite\Excel\Facades\Excel;
use App\Http\Controllers\Controller;

class UsersController extends Controller 
{
    public function export() 
    {
        return Excel::download(new UsersExport, 'users.xlsx');
    }
}
```

:page_facing_up: Find your `users.xlsx` in your downloads folder!

---

## File: 3.0/exports/mapping.md

# Mapping data

### Mapping rows

By adding `WithMapping` you map the data that needs to be added as row. This way you have control over the actual source for each column.
In case of using the Eloquent query builder: 

```php

use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithMapping;

class InvoicesExport implements FromQuery, WithMapping
    
    /**
    * @var Invoice $invoice
    */
    public function map($invoice): array
    {
        return [
            $invoice->invoice_number,
            Date::dateTimeToExcel($invoice->created_at),
        ];
    }
}
```

### Adding a heading row

A heading row can easily be added by adding the `WithHeadings` concern. The heading row will be added
as very first row of the sheet.

```php

use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;

class InvoicesExport implements FromQuery, WithHeadings
    
    public function headings(): array
    {
        return [
            '#',
            'Date',
        ];
    }
}
```

---

## File: 3.0/exports/multiple-sheets.md

# Multiple Sheets

To allow the export to have multiple sheets, the `WithMultipleSheets` concern should be used. 
The `sheets()` method expects an array of sheet export objects to be returned.

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\WithMultipleSheets;

class InvoicesExport implements WithMultipleSheets
{
    use Exportable;

    protected $year;
    
    public function __construct(int $year)
    {
        $this->year = $year;
    }

    /**
     * @return array
     */
    public function sheets(): array
    {
        $sheets = [];

        for ($month = 1; $month <= 12; $month++) {
            $sheets[] = new InvoicesPerMonthSheet($this->year, $month);
        }

        return $sheets;
    }
}
```

The `InvoicesPerMonthSheet` can implement concerns like `FromQuery`, `FromCollection`, ... 

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithTitle;

class InvoicesPerMonthSheet implements FromQuery, WithTitle
{
    private $month;
    private $year;

    public function __construct(int $year, int $month)
    {
        $this->month = $month;
        $this->year  = $year;
    }

    /**
     * @return Builder
     */
    public function query()
    {
        return Invoice
            ::query()
            ->whereYear('created_at', $this->year)
            ->whereMonth('created_at', $this->month);
    }

    /**
     * @return string
     */
    public function title(): string
    {
        return 'Month ' . $this->month;
    }
}
```

This will now download an xlsx of all invoices in 2018, with 12 worksheets representing each month of the year.

```php
public function download() 
{
    return (new InvoicesExport(2018))->download('invoices.xlsx');
}
```

---

## File: 3.0/exports/queued.md

# Queued

In case you are working with a lot of data, it might be wise to queue the entire process. 

Given we have the following export class:

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromQuery;

class InvoicesExport implements FromQuery
{
    use Exportable;

    public function query()
    {
        return Invoice::query();
    }
}
```

It's as easy as calling `->queue()` now.

```php
(new InvoicesExport)->queue('invoices.xlsx');

return back()->withSuccess('Export started!');
```

Behind the scenes the query will be chunked and multiple jobs will be chained. These jobs will be executed in the correct order,
and will only execute if none of the previous have failed. 

### Implicit Export queueing

You can also mark an export implicitly as a queued export. You can do this by using Laravel's `ShouldQueue` contract.

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromQuery;
use Illuminate\Contracts\Queue\ShouldQueue;

class InvoicesExport implements FromQuery, ShouldQueue
{
    use Exportable;

    public function query()
    {
        return Invoice::query();
    }
}
```

In your controller you can now call the normal `->store()` method. 
Based on the presence of the `ShouldQueue` contract, the export will be queued.

```php
(new InvoicesExport)->store('invoices.xlsx');
```

### Appending jobs

The `queue()` method returns an instance of Laravel's `PendingDispatch`. This means you can chain extra jobs that will be added to the end of the queue and only executed if all export jobs are correctly executed.

```php
(new InvoicesExport)->queue('invoices.xlsx')->chain([
    new NotifyUserOfCompletedExport(request()->user()),
]);
```

```php
namespace App\Jobs;

use App\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\SerializesModels;

class NotifyUserOfCompletedExport implements ShouldQueue
{
    use Queueable, SerializesModels;
    
    public $user;
    
    public function __construct(User $user)
    {
        $this->user = $user;
    }

    public function handle()
    {
        $this->user->notify(new ExportReady());
    }
}
```

### Custom queues

Because `PendingDispatch` is returned, we can also change the queue that should be used.

```php
(new InvoicesExport)->queue('invoices.xlsx')->allOnQueue('exports');
```

---

## File: 3.0/exports/store.md

# Storing exports on disk

Exports can easily be stored on any [filesystem](https://laravel.com/docs/5.6/filesystem) that Laravel supports.

```php
public function storeExcel() 
{
    // Store on default disk
    Excel::store(new InvoicesExport(2018), 'invoices.xlsx');
    
    // Store on a different disk (e.g. s3)
    Excel::store(new InvoicesExport(2018), 'invoices.xlsx', 's3');
    
    // Store on a different disk with a defined writer type. 
    Excel::store(new InvoicesExport(2018), 'invoices.xlsx', 's3', Excel::XLSX);
}
```

---

## File: 3.0/exports/testing.md

# Testing

The Excel facade can be used to swap the exporter to a fake.

### Testing downloads

```php
/**
* @test
*/
public function user_can_download_invoices_export() 
{
    Excel::fake();

    $this->actingAs($this->givenUser())
         ->get('/invoices/download/xlsx');

    Excel::assertDownloaded('filename.xlsx', function(InvoicesExport $export) {
        // Assert that the correct export is downloaded.
        return $export->collection()->contains('#2018-01');
    });
}
```

### Testing storing exports

```php
/**
* @test
*/
public function user_can_store_invoices_export() 
{
    Excel::fake();

    $this->actingAs($this->givenUser())
         ->get('/invoices/store/xlsx');

    Excel::assertStored('filename.xlsx', 'diskName');
    
    Excel::assertStored('filename.xlsx', 'diskName', function(InvoicesExport $export) {
        return true;
    });
    
    // When passing the callback as 2nd param, the disk will be the default disk.
    Excel::assertStored('filename.xlsx', function(InvoicesExport $export) {
        return true;
    });
}
```

### Testing queuing exports

```php
/**
* @test
*/
public function user_can_queue_invoices_export() 
{
    Excel::fake();

    $this->actingAs($this->givenUser())
         ->get('/invoices/queue/xlsx');

    Excel::assertQueued('filename.xlsx', 'diskName');
    
    Excel::assertQueued('filename.xlsx', 'diskName', function(InvoicesExport $export) {
        return true;
    });
    
    // When passing the callback as 2nd param, the disk will be the default disk.
    Excel::assertQueued('filename.xlsx', function(InvoicesExport $export) {
        return true;
    });
}
```

---

## File: 3.0/getting-started/contributing.md

# Contributing

[[toc]]

Please read and understand the contribution guide before creating an issue or pull request.

## Important Links

- [Docs](https://docs.laravel-excel.com)
- [Issue tracker](https://github.com/SpartnerNL/Laravel-Excel/issues)
- [Support](/3.0/getting-started/support.html)

## Etiquette

This project is an open source project, and as such, the maintainers use their free time to build and maintain it.
The code is freely available and can be used, forked and modified. 

Please be considerate towards maintainers when raising issues or presenting pull requests. 

It's the duty of the maintainer to ensure that all submissions to the project are of sufficient
quality to benefit the project. Many developers have different skill sets, strengths, and weaknesses. Respect the maintainer's decision, and do not be upset or abusive if your submission is not used.

## Viability

When requesting or submitting new features, first consider whether it might be useful to others. Open
source projects are used by many developers, who may have entirely different needs to your own. Think about
whether or not your feature is likely to be used by other users of the project.

## How to submit changes?

- Check the codebase to ensure that your feature doesn't already exist.
- Check the pull requests to ensure that another person hasn't already submitted the feature or fix.
- Use the [pull request template](https://github.com/SpartnerNL/Laravel-Excel/blob/3.0/.github/PULL_REQUEST_TEMPLATE.md).

## How to report a bug?

- Attempt to replicate the problem, to ensure that it wasn't a coincidental incident.
- Check to make sure your bug report isn't already present within the project.
- Check the pull requests tab to ensure that the bug doesn't have a fix in progress.
- Check the pull requests tab to ensure that the feature isn't already in progress.
- Use the [issue template](https://github.com/SpartnerNL/Laravel-Excel/blob/3.0/.github/ISSUE_TEMPLATE.md).

## Requirements

- **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)**. - Style will get automatically fixed by StyleCI.
- **Add tests backing up your change!** - You can run the test by running `vendor/bin/phpunit`
- **Document any change in behaviour** - Documentation is located in the [https://github.com/SpartnerNL/laravel-excel-docs](https://github.com/SpartnerNL/laravel-excel-docs)
- **One feature per Pull Request**
- **Add meaningful commit messages**

---

## File: 3.0/getting-started/index.md

# Introduction

:rocket: Laravel Excel is intended at being Laravel-flavoured PhpSpreadsheet: a simple, but elegant wrapper around PhpSpreadsheet with the goal of simplifying
exports. 

:fire: [PhpSpreadsheet](https://phpspreadsheet.readthedocs.io/) is a library written in pure PHP and providing a set of classes that allow you to read from and to write to different spreadsheet file formats, like Excel and LibreOffice Calc.

Laravel Excel features:

* Easily export collections to Excel
* Export queries with automatic chunking for better performance
* Queue exports for better performance
* Easily export Blade views to Excel

---

## File: 3.0/getting-started/installation.md

# Installation

## Requirements

* PHP: `^7.0`
* Laravel: `^5.5`
* PhpSpreadsheet: `^1.2`
* PHP extension `php_zip` enabled
* PHP extension `php_xml` enabled
* PHP extension `php_gd2` enabled

## Installation

Require this package in the `composer.json` of your Laravel project. This will download the package and PhpSpreadsheet.

```
composer require maatwebsite/excel
```

The `Maatwebsite\Excel\ExcelServiceProvider` is __auto-discovered__ and registered by default, but if you want to register it yourself:

Add the ServiceProvider in `config/app.php`:

```php
'providers' => [
    /*
     * Package Service Providers...
     */
    Maatwebsite\Excel\ExcelServiceProvider::class,
]
```

The `Excel` facade is also __auto-discovered__, but if you want to add it manually:

Add the Facade in `config/app.php`:

```php
'aliases' => [
    ...
    'Excel' => Maatwebsite\Excel\Facades\Excel::class,
]
```

To publish the config, run the vendor publish command:

```
php artisan vendor:publish
```

This will create a new config file named `config/excel.php`.

## Usage

Laravel Excel can be used in a various of ways. I'm sure you will find your prefered of using it. This can be either via dependency injection or if you prefer you can even use a facade.

### Via dependency injection

You can inject the `Excel` manager class into your class, either via constructor injection or method injection in case of a controller.

```php
use App\YourExport;
use Maatwebsite\Excel\Excel;

class YourController
{
    private $excel;

    public function __construct(Excel $excel)
    {
        $this->excel = $excel;
    }
    
    public function export()
    {
        return $this->excel->download(new YourExport);
    }
}
```

### Via Exporter interface

You can also use the `Maatwebsite\Excel\Exporter` to decouple more from the concrete Excel manager implementation.

```php
use App\YourExport;
use Maatwebsite\Excel\Exporter;

class YourController
{
    private $exporter;

    public function __construct(Exporter $exporter)
    {
        $this->exporter = $exporter;
    }
    
    public function export()
    {
        return $this->exporter->download(new YourExport);
    }
}
```

### Via the Facade

If you prefer facades, you can you use the `Maatwebsite\Excel\Facades\Excel` facade or if you use the alias the `Excel` facade alias.

```php
use App\YourExport;
use Maatwebsite\Excel\Facades\Excel;

class YourController
{
    public function export()
    {
        return Excel::download(new YourExport);
    }
}
```

### Via container binding

If you want to bind the `Excel` manager to your own class via a container binding, you can use the `excel` container binding.

```php
$this->app->bind(YourCustomExporter::class, function() {
    return new YourCustomExporter($this->app['excel']);
});
```

---

## File: 3.0/getting-started/license.md

# License

Our software is open source and licensed under the [MIT license](https://choosealicense.com/licenses/mit/). According to the [postcardware](https://en.wikipedia.org/wiki/Postcardware) concept, if you use the software for your project(s) we would appreciate to receive a postcard of your hometown. Please send it to:

**Spartner**  
Florijnruwe 111-2  
6218 CA Maastricht  
The Netherlands  

You are free to use the software as you like. The code can be forked and modified, but the original copyright author should always be included!

::: warning Support
We hold no liability and will provide support on a best effort basis. For more information about support please see [support](/3.0/getting-started/support).
:::

:rocket: If you use the software commercially and need support urgently, we can offer this on a commercial basis. Please contact  or phone +31 (0)10 744 9312.

---

## File: 3.0/getting-started/support.md

# Support

[[toc]]

Our software is free and open source, meaning that the use of our software is optional. We hold no liability and there is no obligation to support. We will provide support on a best effort basis. 

If you use the software commercially and need elaborate support or need it urgently, we can offer this on a commercial basis. Please contact  or via phone +31 (0)10 744 9312.

## Supported Versions

Versions will be supported for a limited amount of time.

| Version | Laravel Version | Php Version | Support |
|---- |----|----|----|
| 2.1 | <=5.6 | <=7.0 | EOL since 15-05-2018 |
| 3.0 | ^5.5 |  ^7.0 | New features |

::: warning PHP version support
Support for PHP versions will only be maintained for a period of six months beyond the end-of-life of that PHP version.
:::


## Requesting support
Before you request support, please check the following:
* Attempt to replicate the problem, to ensure that it wasn't a coincidental incident.
* Check to make sure your support request isn't already present within the project.
* Check the pull requests tab to ensure that the bug doesn't have a fix in progress.
* Use the [issue template](https://github.com/SpartnerNL/Laravel-Excel/blob/3.0/.github/ISSUE_TEMPLATE.md).

Filling out the template is required. Issues that do not include enough information might not  be picked up. Please write in English (or Dutch).

Please prefix your issue with one of the following: [BUG] [PROPOSAL] [QUESTION].

And please be considerate towards maintainers when raising issues.

---

## File: 3.0/getting-started/upgrade.md

# Upgrade Guide

[[toc]]

## Upgrading to 3.0 from 2.1

Version 3.0 is not backwards compatible with 2.*. It's not possible to provide a step-by-step migration guide as it's a complete paradigm shift.

__New dependencies__

3.0 introduces some new dependencies.

* Requires PHP 7.0 or higher.
* Requires Laravel 5.5 (or higher).
* Requires PhpSpreadsheet instead of PHPExcel.

__Deprecations__

ALL Laravel Excel 2.* methods are deprecated and will not be able to use in 3.0 . 

- Excel::load() is removed and will not be re-added until 3.1
- Excel::create() is removed and replaced by Excel::download/Excel::store($yourExport)
- 3.0 provides no convenience methods for styling, you are encouraged to use PhpSpreadsheets native methods.

---

## File: 3.1/index.md

<meta http-equiv="refresh" content="0;url=/3.1/getting-started/" />

---

## File: 3.1/architecture/concerns.md

# Concerns

[[toc]]

Most of the export/import configuration is done by using **Concerns**. 

## Contracts

Concerns are basically just simple interfaces. Implementing them will make the object adhere to a 
certain contract. This contract can request specific methods that e.g. data can be passed through.

For instance, the `FromCollection` requests the Export object to implement a `collection` method, that needs to return a `Collection` instance.

```php
namespace App\Exports;

use App\User;
use Maatwebsite\Excel\Concerns\FromCollection;

class UsersExport implements FromCollection
{
    public function collection()
    {
        return User::all();
    }
}
```

## Pointer interface

In other cases it might not ask for any methods to be implemented, but merely functions as a pointer interface.

For instance, the `ShouldAutoSize` concern doesn't pass on any specific information, but does tell the Export process that the columns need to be automatically sized.

```php
namespace App\Exports;

use App\User;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;

class UsersExport implements ShouldAutoSize
{

}
```

---

## File: 3.1/architecture/index.md

# Lifecycle

[[toc]]

## Introduction

When using a package in your application, it's good to understand how the package functions behind the scenes. 
Understanding the behind-the-scenes will make you feel more comfortable and confident using the maximum potential of the tool.

The goal of this page is to give you a high-level overview of how Laravel Excel works. 

## Exports Lifecycle Overview

This section will try to give you an overview of how the export works behind the scenes.

### Export Object

Everything starts with the `Export` object. This object **encapsulates** your entire export logic. 
It both configures and handles the export logic.

A simple example of an export object is:

```php
<?php

namespace App\Exports;

use App\User;
use Maatwebsite\Excel\Concerns\FromCollection;

class UsersExport implements FromCollection
{
    public function collection()
    {
        return User::all();
    }
}
```

If you want to read more about export objects, go to the architecture page of [export objects](/3.1/architecture/objects.html).

### Passing on the Export object

Next the Export object will be passed on to the Laravel Excel package. The main entry point for this is the `Maatwebsite/Excel/Excel` class. This class can be called in multiple ways.

#### Facade

The easiest way to work with the `Excel` class is to use the `Maatwebsite\Excel\Facades\Excel` facade. 
If you use [auto-discovery](https://laravel.com/docs/packages#package-discovery), you can use the alias `\Excel` directly instead of using the fully qualified namespace.

#### Dependency injection

You can inject the `Maatwebsite/Excel/Excel` manager class into your class, either via constructor injection 
or method injection in case of a controller.

```php
<?php
use App\Exports\UsersExport;
use Maatwebsite\Excel\Excel;

class ExportController
{
    private $excel;

    public function __construct(Excel $excel)
    {
        $this->excel = $excel;
    }
    
    public function exportViaConstructorInjection()
    {
        return $this->excel->download(new UsersExport, 'users.xlsx');
    }
    
    public function exportViaMethodInjection(Excel $excel)
    {
        return $excel->download(new UsersExport, 'users.xlsx');
    }
}
```

#### Contract

You can also use the `Maatwebsite\Excel\Exporter` interface to decouple more from the concrete Excel manager implementation. The contract offers the same methods as the `Excel` class. 
It will make it easier to e.g. stub out the Exporter in your unit tests. The `Exporter` contract can be either injected via the constructor or a method in a controller.

```php
use App\Exports\UsersExport;
use Maatwebsite\Excel\Exporter;

class ExportsController
{
    private $exporter;

    public function __construct(Exporter $exporter)
    {
        $this->exporter = $exporter;
    }
    
    public function export()
    {
        return $this->exporter->download(new UsersExport, 'users.xlsx');
    }
}
```

#### Container binding

If you want to bind the `Maatwebsite\Excel\Excel` manager to your own class via a container binding, you can use the `excel` container binding.

```php
$this->app->bind(YourCustomExporter::class, function() {
    return new YourCustomExporter($this->app['excel']);
});
```

#### Exportable trait

If you prefer a sprinkle of magic, you can use the `Maatwebsite\Excel\Concerns\Exportable` trait in your `Export` object. This trait will expose a couple of methods that will make it possible to directly export an `Export` object.

```php
namespace App\Exports;

use App\User;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\Exportable;

class UsersExport implements FromCollection
{
    use Exportable;

    public function collection()
    {
        return User::all();
    }
}
```

You can now download the export without the need for the `facade` or `Excel` manager.

```php
return (new UsersExport)->download('users.xlsx');
```

Read more about the exportable trait in the [exportables](/3.1/exports/exportables.html) docs.

### Handling the Export object

#### Writer type detection

After using one of the above methods to pass on the `Export` object to the `Excel` manager, it will try to figure out what export it needs to be generated to. 
This will be either based on the extension of the file, the explicitly passed writer type. You can find the extension to writer type mapping in the `excel.php` config, in the `extension_detector` section. 
In case no writer type can be detected, a `Maatwebsite\Excel\Exceptions\NoTypeDetectedException` exception is thrown and the export process will be stopped.

#### Starting the Writing process

The `Excel` manager will then delegate the handling to the `Maatwebsite\Excel\Writer`. The first action of the `Writer` is to register the event listeners that are registered. 
Next it will create a new `PhpOffice\PhpSpreadsheet\Spreadsheet` instance that we will use to convert our `Export` object to.

The first event raised is the `BeforeExport` event. This is raised just after the `Spreadsheet` instance is created and allows early access to it.

#### Multiple sheets

Next the `Writer` will determine if multiple sheets are configured, by checking for the `Maatwebsite\Excel\Concerns\WithMultipleSheets` concern.

Then it will delegate the further handling of each sheet to the `Maatwebsite\Excel\Sheet` class.

#### Processing the sheets

In the `Sheet` class, the most heavy lifting happens. It first will create a `PhpOffice\PhpSpreadsheet\Worksheet\Worksheet` instance. Then it will raise the `BeforeSheet` event which allows you to hook into the moment just before the sheet handling starts.

Then it will determine what kind of export we are dealing with: `FromQuery`, `FromArray`, `FromCollection` or `FromView`. Based on that it will start the connected export process.

- `FromView` will pass on the rendered `Blade` view to PhpSpreadsheet's `Html` Reader. That Reader will turn the table html into Excel cells. It also handles some inline styles (color and background color) and col/rowspans.
- The **Query** passed with the `FromQuery` will automatically be chunked and each chunk will be appended to the Sheet. The chunking is done to limit the amount of Eloquent objects it needs to keep in memory. It greatly reduces memory usage.
- The entire array of Collection will directly be appended to the Sheet. 

When the `Sheet` starts appending records, it will first call the `map()` method if the `WithMapping` concern is used. This allows the `Export` object to format the data before it is inserted.

Then it will handle column formatting (`WithColumnFormatting` concern) and cell autosizing (`ShouldAutoSize`).

To close off the Sheet processing, it will raise a `AfterSheet` event.

### Passing on to PhpSpreadsheet

After the sheets are processed, the writing process will start. The writing process is started by raising the `BeforeWriting` event; this allows you to hook into the process of writing.
Next we will create a new `PhpSpreadsheet Writer` based on the writer type that was determined. Then it will save it to a temporary file and return that filepath to the `Excel` manager.

### Creating a Response

The `Excel` manager basically has 2 types of responses, it either starts the **download** process or it will **store** the file to disk.

#### Download the file

We will take the temporary file that was returned by the `Writer` and use Laravel's `ResponseFactory` to create a `Symfony\Component\HttpFoundation\BinaryFileResponse`. When returning this response in your controller, it will start a download.

#### Storing the file

The storing of the file will be handled by Laravel's `Filesystem`. By default the file will be stored on your `default` disk, but you can also pass a custom disk via the `Excel::store()` method.

## Imports Lifecycle Overview

This section will try to give you an overview of how the import works behind the scenes.

### Import Object

Everything starts with the `Import` object. This object **encapsulates** your entire import logic. 
It both configures and handles the import logic.

A simple example of an import object is:

```php
namespace App\Imports;

use App\User;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\ToCollection;

class UsersImport implements ToCollection
{
    public function collection(Collection $rows)
    {
        foreach ($rows as $row) 
        {
            User::create([
                'name' => $row[0],
            ]);
        }
    }
}
```

If you want to read more about imports objects, go to the architecture page of [imports objects](/3.1/architecture/objects.html).

### Passing on the Import object

Next the Import object will be passed on to the Laravel Excel package. The main entry point for this is the `Maatwebsite/Excel/Excel` class. This class can be called in the same way as outlined in the Export lifecycle.

#### Contract

You can also use the `Maatwebsite\Excel\Importer` interface to decouple more from the concrete Excel manager implementation. The contract offers the same methods as the `Excel` class. 
It will make it easier to e.g. stub out the Importer in your unit tests. The `Importer` contract can be either injected via the constructor or the method of a controller.

```php
use App\Imports\UsersImport;
use Maatwebsite\Excel\Importer;

class ImportsController
{
    private $importer;

    public function __construct(Importer $importer)
    {
        $this->importer = $importer;
    }
    
    public function import()
    {
        return $this->importer->import(new UsersImport, 'users.xlsx');
    }
}
```

#### Importable trait

If you prefer a sprinkle of magic, you can use the `Maatwebsite\Excel\Concerns\Importable` trait in your `Import` object. This trait will expose a couple of methods that will make it possible to directly import an `Import` object.

```php
namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\ToCollection;
use Maatwebsite\Excel\Concerns\Importable;

class UsersImport implements ToCollection
{
    use Importable;

    ...
}
```

You can now import without the need for the `facade` or `Excel` manager.

```php
(new UsersImport)->import('users.xlsx');
```

Read more about the importable trait in the [importables](/3.1/imports/importables.html) docs.

### Handling the Import object

#### Reader type detection

After using one of the above methods to pass on the `Import` object to the `Excel` manager, it will try to figure out what reader type it is . 
This will be either based on the extension of the file or the explicitly passed reader type. You can find the extension to reader type mapping in the `excel.php` config, in the `extension_detector` section. 
In case no reader type can be detected, a `Maatwebsite\Excel\Exceptions\NoTypeDetectedException` exception is thrown and the import process will be stopped.

#### Starting the Reading process

The `Excel` manager will then delegate the handling to the `Maatwebsite\Excel\Reader`. The first action of the `Reader` is to register the event listeners that are registered. 
It will copy the file from Laravel's `Filesystem` to the local filesystem, so PhpSpreadsheet can read it. 
Next it will create a PhpSpreadsheet `Reader` based on the reader type that was given and load the file into a `PhpOffice\PhpSpreadsheet\Spreadsheet` instance.

Next it will create a new `PhpOffice\PhpSpreadsheet\Spreadsheet` instance that we will use to read our `Import` object from.

The first event that is raised, is the `BeforeImport` event. This is raised just after the `Spreadsheet` instance is loaded and allows early access to it.

#### Multiple sheets

Next we will determine if we are dealing with multiple sheets. This is done based on the `WithMultipleSheets` concern.

#### Processing the sheets

Then each Sheet gets processed. This process gets started off by raising the `BeforeSheet` event. 
Then it will either import it to a Collection, an array or handle each row as an Eloquent model.

- When using `ToModel`, each returned model will be persisted via Eloquent. When using this in combination with `WithBatchInserts`, it will defer the persistence till the batch is complete and then insert them as one batch in the database.
- When using `ToCollection` or `ToArray`, the entire dataset will be passed to the Import method and the user can determine itself how to use it.

The sheet handling is ended by raising the `AfterSheet` event.

---

## File: 3.1/architecture/objects.md

# Import & Export Objects

[[toc]]

The entire Laravel Excel philosophy evolves around having `Export` and/or `Import` objects.

## Directory structure

The location of these Import and Exports classes could be as follows:

::: vue
.
├── app
│   ├── `Exports` _(**Groups all exports in your app**)_
│   │   ├── UsersExport.php
│   │   ├── ProductsExport.php
│   │   └── `Sheets` _(**You can group sheets together**)_
│   │      ├── InactiveUsersSheet.php
│   │      └── ActiveUsersSheet.php
|   |
│   ├── `Imports` _(**Groups all imports in your app**)_
│   │   ├── UsersImport.php
│   │   ├── ProductsImport.php
│   │   └── `Sheets` _(**You can group sheets together**)_
│   │      ├── OutOfStockProductsSheet.php
│   │      └── ProductsOnSaleSheet.php
│ 
└── composer.json
:::

## Encapsulation

These objects encapsulate the entire export or import process. 
The idea behind it is that you can neatly use these objects in controllers, services, jobs, event listeners or commands. 
In all of theses cases, the entire logic of how the export/import needs to happen is kept within this object. 

## Data transfer object

The import/export objects are in essence simple data transfer objects (DTO). 
This means they will transfer the information you want to export/import to the Excel writer/reader. 
This information is not only the actual data you want to export, but also additional information like 
the styling of the file, the name of the worksheet, the number format of the cell etc.

In most cases, this means that your code doesn't need to have direct exposure to the actual read/write process.

## Plain Old PHP Object

Besides being a DTO, the import/export objects are also just Plain Old PHP Objects (POPO). This means that you can do anything with them that you can do with normal PHP objects. 

### Constructor

For instance, you can simply inject data through the constructor of the export object.

```php
class UsersExport implements FromCollection {
    private $year;

    public function __construct(int $year) 
    {
        $this->year = $year;
    }
    
    public function collection()
    {
        return Users::whereYear('created_at', $this->year)->get();
    }
}
```

```php
Excel::download(new UsersExport(2019), 'users.xlsx');
```

### Setters

Another option is to add setters for data that you want to pass.

```php
class UsersExport implements FromCollection {
    private $year;

    public function setYear(int $year)
    {
        $this->year = $year;
    }
    
    public function collection()
    {
        return Users::whereYear('created_at', $this->year)->get();
    }
}
```

```php
$export = new UsersExport();
$export->setYear(2019);

Excel::download($export, 'users.xlsx');
```

### Getters

In similar fashion to setters, you can also add getters. This can potentially be useful if you want to keep a state of your export/import.

For instance, you can keep a row count in your users import.

```php
namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\ToModel;

class UsersImport implements ToModel
{
    private $rows = 0;

    public function model(array $row)
    {
        ++$this->rows;
    
        return new User([
            'name' => $row[0],
        ]);
    }
    
    public function getRowCount(): int
    {
        return $this->rows;
    }
}
```

After doing the import, we can request the state with the getter.

```php
$import = new UsersImport;
Excel::import($import, 'users.xlsx');

dd('Row count: ' . $import->getRowCount()); 
```

## Concerns

Most of the export/import configuration is done by using **Concerns**. Concerns are basically just simple interfaces. 
Implementing them will make the object adhere to a certain contract. This contract can request specific methods that e.g. data can be passed through.
In other cases it might not ask for any methods to be implemented, but merely functions as a pointer interface.

Read more about Concerns in the [concerns documentation](/3.1/architecture/concerns.html).

## Hooks

In more complex cases you might want to hook into certain moments of the read/write process. This can be done by using Events.
To register these events in your import/export object, you need to implement the `Maatwebsite\Excel\Concerns\WithEvents` concern.

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Events\BeforeExport;

class UsersExport implements WithEvents
{
    /**
     * @return array
     */
    public function registerEvents(): array
    {
        return [
            // Handle by a closure.
            BeforeExport::class => function(BeforeExport $event) {
                // Do something before the export process starts.
            },
        ];
    }
}
```

Alternatively, you can also configure these listeners globally if you want it to happen to any export.

```php
Writer::listen(BeforeExport::class, function () {
    // Do something before any export process starts.
});
```

---

## File: 3.1/exports/charts.md

# Charts

[[toc]]

By using the `WithCharts` concern, you can add one or multiple charts to your worksheet.

## Instantiating a chart
You first have to instantiate a new `PhpOffice\PhpSpreadsheet\Worksheet\Chart`, passing the name, title, legend and plot in the constructor.

```php
$label      = [new DataSeriesValues('String', 'Worksheet!$B$1', null, 1)];
$categories = [new DataSeriesValues('String', 'Worksheet!$B$2:$B$5', null, 4)];
$values     = [new DataSeriesValues('Number', 'Worksheet!$A$2:$A$5', null, 4)];

$series = new DataSeries(DataSeries::TYPE_PIECHART, DataSeries::GROUPING_STANDARD,
    range(0, \count($values) - 1), $label, $categories, $values);
$plot   = new PlotArea(null, [$series]);

$legend = new Legend();
$chart  = new Chart('chart name', new Title('chart title'), $legend, $plot);

$chart->setTopLeftPosition('D1');
$chart->setBottomRightPosition('K12');
```

You can view all available properties for Charts on the [PhpSpreadsheet docs](https://phpoffice.github.io/PhpSpreadsheet/namespaces/phpoffice-phpspreadsheet-chart.html).

## Adding a single chart
When you've instantiated the chart, you can add the `WithCharts` concern to your export class and return the Chart instance in the `charts` method.

```php
<?php

namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithCharts;
use PhpOffice\PhpSpreadsheet\Worksheet\Chart;

class InvoicesExport implements WithCharts
{
    public function charts()
    {
        $label      = [new DataSeriesValues('String', 'Worksheet!$B$1', null, 1)];
        $categories = [new DataSeriesValues('String', 'Worksheet!$B$2:$B$5', null, 4)];
        $values     = [new DataSeriesValues('Number', 'Worksheet!$A$2:$A$5', null, 4)];

        $series = new DataSeries(DataSeries::TYPE_PIECHART, DataSeries::GROUPING_STANDARD,
            range(0, \count($values) - 1), $label, $categories, $values);
        $plot   = new PlotArea(null, [$series]);

        $legend = new Legend();
        $chart  = new Chart('chart name', new Title('chart title'), $legend, $plot);

        $chart->setTopLeftPosition('D1');
        $chart->setBottomRightPosition('K12');

        return $chart;
    }
}
```

## Adding multiple charts
You can add multiple charts to the worksheet by returning an array in the `charts` method.

```php
<?php

namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithCharts;
use PhpOffice\PhpSpreadsheet\Worksheet\Chart;

class InvoicesExport implements WithCharts
{
    public function charts()
    {
        $label      = [new DataSeriesValues('String', 'Worksheet!$B$1', null, 1)];
        $categories = [new DataSeriesValues('String', 'Worksheet!$B$2:$B$5', null, 4)];
        $values     = [new DataSeriesValues('Number', 'Worksheet!$A$2:$A$5', null, 4)];

        $series = new DataSeries(DataSeries::TYPE_PIECHART, DataSeries::GROUPING_STANDARD,
            range(0, \count($values) - 1), $label, $categories, $values);
        $plot   = new PlotArea(null, [$series]);

        $legend = new Legend();

        $chart  = new Chart('chart name', new Title('chart title'), $legend, $plot);
        $chart->setTopLeftPosition('D1');
        $chart->setBottomRightPosition('K12');

        $chart2 = new Chart('chart 2 name', new Title('chart 2 title'), $legend, $plot);
        $chart2->setTopLeftPosition('D13');
        $chart2->setBottomRightPosition('K24');

        return [$chart, $chart2];
    }
}
```

---

## File: 3.1/exports/collection.md

# Exporting collections

[[toc]]

The easiest way to start an export is to create a custom export class. We'll use an invoices export as example.

Create a new class called `InvoicesExport` in `app/Exports`:

```php
namespace App\Exports;

use App\Invoice;
use Maatwebsite\Excel\Concerns\FromCollection;

class InvoicesExport implements FromCollection
{
    public function collection()
    {
        return Invoice::all();
    }
}
```

In your controller we can now download this export:

```php
public function export() 
{
    return Excel::download(new InvoicesExport, 'invoices.xlsx');
}
```

Optionally you can pass in whether or not to output headers and custom response headers:

```php
public function export() 
{
    return Excel::download(new InvoicesExport, 'invoices.xlsx', true, ['X-Vapor-Base64-Encode' => 'True']);
}
```


Or store it on a disk, (e.g. s3):

```php
public function storeExcel() 
{
    return Excel::store(new InvoicesExport, 'invoices.xlsx', 's3');
}
```

:bulb: More about storing exports can be found in the [storing exports on disk page](/3.1/exports/store.html).

:::tip
If you want to use relationships in Collection, combine with [Mapping Data](/3.1/exports/mapping.html)
:::

## Using custom structures

If you are not using Eloquent or having another datasource (e.g. an API, MongoDB, Cache, ...) you can also return a custom collection:

```php
namespace App\Exports;

use App\Invoice;
use Maatwebsite\Excel\Concerns\FromCollection;

class InvoicesExport implements FromCollection
{
    public function collection()
    {
        return new Collection([
            [1, 2, 3],
            [4, 5, 6]
        ]);
    }
}
```

## Using arrays

If you prefer to use plain arrays over Collections, you can use the `FromArray` concern:

```php
namespace App\Exports;

use App\Invoice;
use Maatwebsite\Excel\Concerns\FromArray;

class InvoicesExport implements FromArray
{
    public function array(): array
    {
        return [
            [1, 2, 3],
            [4, 5, 6]
        ];
    }
}
```

If you need to pass data from the controller to your export, you can use the constructor to do so:

```php
namespace App\Exports;

use App\Invoice;
use Maatwebsite\Excel\Concerns\FromArray;

class InvoicesExport implements FromArray
{
    protected $invoices;

    public function __construct(array $invoices)
    {
        $this->invoices = $invoices;
    }

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

In your controller you can now use the constructor of the export class:

```php
public function export() 
{
    $export = new InvoicesExport([
        [1, 2, 3],
        [4, 5, 6]
    ]);

    return Excel::download($export, 'invoices.xlsx');
}
```

## Dependency injection

In case your export needs dependencies, you can inject the export class:

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\FromCollection;

class InvoicesExport implements FromCollection
{
    protected $invoices;

    public function __construct(InvoicesRepository $invoices)
    {
        $this->invoices = $invoices;
    }

    public function collection()
    {
        return $this->invoices->all();
    }
}
```

```php
public function export(Excel $excel, InvoicesExport $export) 
{
    return $excel->download($export, 'invoices.xlsx');
}
```

## Strict null comparisons

If you want your `0` values to be actual `0` values in your Excel sheet instead of `null` (empty cells), you can use `WithStrictNullComparison`.

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithStrictNullComparison;

class InvoicesExport implements FromCollection, WithStrictNullComparison
{
    public function __construct(InvoicesRepository $invoices)
    {
        $this->invoices = $invoices;
    }

    public function collection()
    {
        return $this->invoices->all();
    }
}
```

## Custom start cell
The default start cell is _A1_. Implementing the `WithCustomStartCell` concern in your export class allows you to specify a custom start cell.

```php
namespace App\Exports;

use App\Invoice;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithCustomStartCell;

class InvoicesExport implements FromCollection, WithCustomStartCell
{
    public function collection()
    {
        return Invoice::all();
    }

    public function startCell(): string
    {
        return 'B2';
    }
}
```

:::warning
`WithCustomStartCell` is only supported for `FromCollection` exports.
:::

## Storing raw contents

If you want to receive the raw contents of the exported file, you can use the `raw()` method:

```php
$contents = Excel::raw(new InvoicesExport, \Maatwebsite\Excel\Excel::XLSX);
```

## Collection macros

The package provides some macro to Laravel's collection class to easily download or store a collection.

### Downloading a collection as Excel

```php
User::all()->downloadExcel(
    $filePath,
    $writerType = null,
    $headings = false
)
```

It doesn't have to be an Eloquent collection to work:


```php
(new Collection([[1, 2, 3], [1, 2, 3]]))->downloadExcel(
    $filePath,
    $writerType = null,
    $headings = false
)
```

### Storing a collection on disk

```php
User::all()->storeExcel(
    $filePath,
    $disk = null,
    $writerType = null,
    $headings = false
)
```

---

## File: 3.1/exports/column-formatting.md

# Customizing columns

[[toc]]

## Formatting columns

You can easily format an entire column, by using `WithColumnFormatting`.
In case you want something more custom, it's suggested to use the `AfterSheet` event to directly interact with the underlying `Worksheet` class.

```php
namespace App\Exports;

use PhpOffice\PhpSpreadsheet\Shared\Date;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
use Maatwebsite\Excel\Concerns\WithColumnFormatting;
use Maatwebsite\Excel\Concerns\WithMapping;

class InvoicesExport implements WithColumnFormatting, WithMapping
{
    public function map($invoice): array
    {
        return [
            $invoice->invoice_number,
            Date::dateTimeToExcel($invoice->created_at),
            $invoice->total
        ];
    }
    
    public function columnFormats(): array
    {
        return [
            'B' => NumberFormat::FORMAT_DATE_DDMMYYYY,
            'C' => NumberFormat::FORMAT_CURRENCY_EUR_INTEGER,
        ];
    }
}
```

### Dates

When working with dates, it's recommended to use `\PhpOffice\PhpSpreadsheet\Shared\Date::dateTimeToExcel()` in your mapping
to ensure correct parsing of dates.

### Value binders

By default Laravel Excel uses PhpSpreadsheet's default value binder to intelligently format a cell's value when reading it. You may override this behavior by implementing the `WithCustomValueBinder` concern and the `bindValue` method. Your export class may also extend `DefaultValueBinder` to return the default behavior.

```php
namespace App\Exports;

use PhpOffice\PhpSpreadsheet\Cell\Cell;
use Maatwebsite\Excel\Concerns\ToModel;
use PhpOffice\PhpSpreadsheet\Cell\DataType;
use Maatwebsite\Excel\Concerns\WithCustomValueBinder;
use PhpOffice\PhpSpreadsheet\Cell\DefaultValueBinder;

class UsersExport extends DefaultValueBinder implements WithCustomValueBinder
{
    public function bindValue(Cell $cell, $value)
    {
        if (is_numeric($value)) {
            $cell->setValueExplicit($value, DataType::TYPE_NUMERIC);

            return true;
        }

        // else return default behavior
        return parent::bindValue($cell, $value);
    }
}
```

#### Available DataTypes 

* `PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_STRING`
* `PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_FORMULA`
* `PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_NUMERIC`
* `PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_BOOL`
* `PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_NULL`
* `PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_INLINE`
* `PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_ERROR`

### Disable intelligent formatting

If you want to disable the intelligent formatting of values, you can extend your export class with  `\PhpOffice\PhpSpreadsheet\Cell\StringValueBinder`. In this case all values are passed on as strings.

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithCustomValueBinder;

class UsersExport extends \PhpOffice\PhpSpreadsheet\Cell\StringValueBinder implements WithCustomValueBinder
{

}
```

### Default Value Binder

If you want to use one value binder for all your exports, you can configure the default value binder in the config.

In `config/excel.php`:

```php
'value_binder' => [
    'default' => Maatwebsite\Excel\DefaultValueBinder::class,
],
```

## Auto size

If you want Laravel Excel to perform an automatic width calculation, you need to implement the `ShouldAutoSize` interface, like the following code. 

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\ShouldAutoSize;

class InvoicesExport implements ShouldAutoSize
{
    ...
}
```

## Column widths

In some cases you might want more control over the actual column width instead of relying on autosizing. You can do so with the `WithColumnWidths` concerns. It accepts an array of columns (alphabetic representation: A, B, C) and a numeric width.

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithColumnWidths;

class InvoicesExport implements WithColumnWidths
{
    public function columnWidths(): array
    {
        return [
            'A' => 55,
            'B' => 45,            
        ];
    }
}
```

Can be used together with `ShouldAutoSize`. Only the columns with explicit widths won't be autosized. 

## Styling

The `WithStyles` (available after `v3.1.21`) concerns allows styling columns, cells and rows. This might be useful when you want to make the heading row bold.

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithStyles;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;

class InvoicesExport implements WithStyles
{
    public function styles(Worksheet $sheet)
    {
        return [
            // Style the first row as bold text.
            1    => ['font' => ['bold' => true]],

            // Styling a specific cell by coordinate.
            'B2' => ['font' => ['italic' => true]],

            // Styling an entire column.
            'C'  => ['font' => ['size' => 16]],
        ];
    }
}
```

For the contents of the styles array, please refer to the [PhpSpreadsheet docs](https://phpspreadsheet.readthedocs.io/en/latest/topics/recipes/#valid-array-keys-for-style-applyfromarray)

If you prefer the fluent syntax for styling cells, you can do it as follows:

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithStyles;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;

class InvoicesExport implements WithStyles
{
    public function styles(Worksheet $sheet)
    {
        $sheet->getStyle('B2')->getFont()->setBold(true);
    }
}
```

## Default styles

The `WithDefaultStyles` (available after `v3.1.40`) concerns allows styling the entire workbook.

```php
namespace App\Exports;

use PhpOffice\PhpSpreadsheet\Style\Fill;
use PhpOffice\PhpSpreadsheet\Style\Style;
use PhpOffice\PhpSpreadsheet\Style\Color;
use Maatwebsite\Excel\Concerns\WithDefaultStyles;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;

class InvoicesExport implements WithDefaultStyles
{
    public function defaultStyles(Style $defaultStyle)
    {
        // Configure the default styles
        return $defaultStyle->getFill()->setFillType(Fill::FILL_SOLID);
    
        // Or return the styles array
        return [
            'fill' => [
                'fillType'   => Fill::FILL_SOLID,
                'startColor' => ['argb' => Color::RED],
            ],
        ];
    }
}
```

## Workbook background color

The `WithBackgroundColor` (available after `v3.1.40`) concerns adds support to configure the background color of the entire workbook

```php
namespace App\Exports;

use PhpOffice\PhpSpreadsheet\Style\Fill;
use PhpOffice\PhpSpreadsheet\Style\Style;
use PhpOffice\PhpSpreadsheet\Style\Color;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use Maatwebsite\Excel\Concerns\WithBackgroundColor;

class InvoicesExport implements WithBackgroundColor
{
    public function backgroundColor()
    {
        // Return RGB color code.
        return '000000';
    
        // Return a Color instance. The fill type will automatically be set to "solid"
        return new Color(Color::COLOR_BLUE);
    
        // Or return the styles array
        return [
             'fillType'   => Fill::FILL_GRADIENT_LINEAR,
             'startColor' => ['argb' => Color::COLOR_RED],
        ];
    }
}
```

##  Full Styling Map

The full styling map can be taken from the PhpSpreadsheet Styles class as follows:

```php
/**
 * Apply styles from array.
 */
$spreadsheet->getActiveSheet()->getStyle('B2')->applyFromArray(
    [
        'font' => [
            'name' => 'Arial',
            'bold' => true,
            'italic' => false,
            'underline' => Font::UNDERLINE_DOUBLE,
            'strikethrough' => false,
            'color' => [
                'rgb' => '808080'
            ]
        ],
        'borders' => [
            'bottom' => [
                'borderStyle' => Border::BORDER_DASHDOT,
                'color' => [
                    'rgb' => '808080'
                ]
            ],
            'top' => [
                'borderStyle' => Border::BORDER_DASHDOT,
                'color' => [
                    'rgb' => '808080'
                ]
            ]
        ],
        'alignment' => [
            'horizontal' => Alignment::HORIZONTAL_CENTER,
            'vertical' => Alignment::VERTICAL_CENTER,
            'wrapText' => true,
        ],
        'quotePrefix'    => true
    ]
);
```

---

## File: 3.1/exports/concerns.md

---
pageClass: no-toc
---

# Export concerns

| Interface | Explanation | Documentation |
|---- |----|----|
|`Maatwebsite\Excel\Concerns\FromArray`| Use an array to populate the export. | [Exporting collections](/3.1/exports/collection.html#using-arrays) |
|`Maatwebsite\Excel\Concerns\FromCollection`| Use a Laravel Collection to populate the export. | [Exporting collections](/3.1/exports/collection.html) |
|`Maatwebsite\Excel\Concerns\FromGenerator`| Use a generator to populate the export. | [From Generator](/3.1/exports/from-generator.html) |
|`Maatwebsite\Excel\Concerns\FromIterator`| Use an iterator to populate the export. | |
|`Maatwebsite\Excel\Concerns\FromQuery`| Use an Eloquent query to populate the export. | [From Query](/3.1/exports/from-query.html) | 
|`Maatwebsite\Excel\Concerns\FromView`| Use a (Blade) view to populate the export. | [From View](/3.1/exports/from-view.html) |
|`Maatwebsite\Excel\Concerns\HasReferencesToOtherSheets`| Allows precalculated values where one sheet has references to another sheet. | [References to other sheets](/3.1/exports/multiple-sheets.html#making-calculations-work-when-referencing-between-sheets) |
|`Maatwebsite\Excel\Concerns\ShouldAutoSize`| Auto-size the columns in the worksheet. | [Auto size](/3.1/exports/column-formatting.html#auto-size) |
|`Maatwebsite\Excel\Concerns\WithCharts`| Allows to run one or multiple PhpSpreadsheet Chart instances. | [Charts](/3.1/exports/charts.html) |
|`Maatwebsite\Excel\Concerns\WithColumnFormatting`| Format certain columns. | [Formatting columns](/3.1/exports/column-formatting.html) |
|`Maatwebsite\Excel\Concerns\WithColumnWidths`| Set Column widths. | [Column widths](/3.1/exports/column-formatting.html#styling) |
|`Maatwebsite\Excel\Concerns\WithCustomChunkSize`| Allows Exportables to define their chunk size. | |
|`Maatwebsite\Excel\Concerns\WithCustomCsvSettings`| Allows to run custom Csv settings for this specific exportable. | [Custom CSV Settings](/3.1/exports/settings.html) |
|`Maatwebsite\Excel\Concerns\WithCustomQuerySize`| Allows Exportables that implement the FromQuery concern to provide their own custom query size. | [Custom Query Size](/3.1/exports/queued.html#custom-query-size) |
|`Maatwebsite\Excel\Concerns\WithCustomStartCell`| Allows to specify a custom start cell. Do note that this is only supported for FromCollection exports. | [Custom start cell](/3.1/exports/collection.html#custom-start-cell) |
|`Maatwebsite\Excel\Concerns\WithCustomValueBinder`| Allows to specify a custom value binder. | [Custom Value Binder](/3.1/exports/column-formatting.html#value-binders) |
|`Maatwebsite\Excel\Concerns\WithDrawings`| Allows to run one or multiple PhpSpreadsheet (Base)Drawing instances. | [Drawings](/3.1/exports/drawings.html) |
|`Maatwebsite\Excel\Concerns\WithEvents`| Register events to hook into the PhpSpreadsheet process. | [Events](/3.1/exports/extending.html#events) |
|`Maatwebsite\Excel\Concerns\WithHeadings`| Prepend a heading row. | [Adding a heading row](/3.1/exports/mapping.html#adding-a-heading-row) |
|`Maatwebsite\Excel\Concerns\WithMapping`| Format the row before it's written to the file. | [Mapping data](/3.1/exports/mapping.html) |
|`Maatwebsite\Excel\Concerns\WithMultipleSheets`| Enable multi-sheet support. Each sheet can have its own concerns (except this one). | [Multiple Sheets](/3.1/exports/multiple-sheets.html) |
|`Maatwebsite\Excel\Concerns\WithPreCalculateFormulas`| Forces PhpSpreadsheet to recalculate all formulae in a workbook when saving, so that the pre-calculated values are immediately available to MS Excel or other office spreadsheet viewer when opening the file. | |
|`Maatwebsite\Excel\Concerns\WithProperties`| Allows setting properties on the document.| [Properties](/3.1/exports/settings.html#properties) |
|`Maatwebsite\Excel\Concerns\WithStrictNullComparison`| Uses strict comparisons when testing cells for null value. | [Strict null comparisons](/3.1/exports/collection.html#strict-null-comparisons) |
|`Maatwebsite\Excel\Concerns\WithStyles`| Allows setting styles on worksheets. | [Styles](/3.1/exports/column-formatting.html#styling) |
|`Maatwebsite\Excel\Concerns\WithTitle`| Set the Workbook or Worksheet title. | [Multiple Sheets](/3.1/exports/multiple-sheets.html) |

### Traits

| Trait | Explanation | Documentation |
|---- |----|----|
|`Maatwebsite\Excel\Concerns\Exportable` | Add download/store abilities right on the export class itself. | [Exportables](/3.1/exports/exportables.html) |
|`Maatwebsite\Excel\Concerns\RegistersEventListeners` | Auto-register the available event listeners. | [Auto register event listeners](/3.1/exports/extending.html#auto-register-event-listeners) |

---

## File: 3.1/exports/drawings.md

# Drawings

[[toc]]

By using the `WithDrawings` concern, you can add one or multiple drawings to your worksheet.

## Instantiating a drawing
You first have to instantiate a new `\PhpOffice\PhpSpreadsheet\Worksheet\Drawing`, and assign its properties a meaningful value.

```php
$drawing = new \PhpOffice\PhpSpreadsheet\Worksheet\Drawing();
$drawing->setName('Logo');
$drawing->setDescription('This is my logo');
$drawing->setPath(public_path('/img/logo.jpg'));
$drawing->setHeight(90);
```

You can view all available properties for Drawing on the [PhpSpreadsheet docs](https://phpspreadsheet.readthedocs.io/en/latest/topics/recipes/#add-a-drawing-to-a-worksheet).

## Adding a single drawing
When you've instantiated the drawing, you can add the `WithDrawings` concern to your export class. Return the Drawing instance in the `drawings` method.

```php
<?php

namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithDrawings;
use PhpOffice\PhpSpreadsheet\Worksheet\Drawing;

class InvoicesExport implements WithDrawings
{
    public function drawings()
    {
        $drawing = new Drawing();
        $drawing->setName('Logo');
        $drawing->setDescription('This is my logo');
        $drawing->setPath(public_path('/img/logo.jpg'));
        $drawing->setHeight(90);
        $drawing->setCoordinates('B3');

        return $drawing;
    }
}
```

## Adding multiple drawings
You can add multiple drawings to the worksheet by returning an array in the `drawings` method.

```php
<?php

namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithDrawings;
use PhpOffice\PhpSpreadsheet\Worksheet\Drawing;

class InvoicesExport implements WithDrawings
{
    public function drawings()
    {
        $drawing = new Drawing();
        $drawing->setName('Logo');
        $drawing->setDescription('This is my logo');
        $drawing->setPath(public_path('/img/logo.jpg'));
        $drawing->setHeight(50);
        $drawing->setCoordinates('B3');

        $drawing2 = new Drawing();
        $drawing2->setName('Other image');
        $drawing2->setDescription('This is a second image');
        $drawing2->setPath(public_path('/img/other.jpg'));
        $drawing2->setHeight(120);
        $drawing2->setCoordinates('G2');

        return [$drawing, $drawing2];
    }
}
```

## Adding a drawing of remote image
You can instantiate a new drawing from `\PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing`, and create a string containing the binary image data, or from an external url by `imagecreatefromstring(file_get_contents($url))`, then assign it to `setImageResource`. Return the Drawing instance in the `drawings` method.

```php
<?php

namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithDrawings;
use PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing;

class InvoicesExport implements WithDrawings
{
    public function drawings()
    {
        if (!$imageResource = @imagecreatefromstring(file_get_contents('http://example.jpg'))) {
            throw new \Exception('The image URL cannot be converted into an image resource.');
        }

        $drawing = new MemoryDrawing();
        $drawing->setName('Logo');
        $drawing->setDescription('This is my logo');
        $drawing->setImageResource($imageResource);
        $drawing->setHeight(90);
        $drawing->setCoordinates('B3');

        return $drawing;
    }
}
```

---

## File: 3.1/exports/export-formats.md

# Export formats

[[toc]]

By default, the export format is determined by the extension of the file. If you want 
to explicitly configure the export format, you can pass it through as 2nd parameter. 

## XLSX

```php
return Excel::download(new InvoicesExport, 'invoices.xlsx', \Maatwebsite\Excel\Excel::XLSX);
```

## CSV

```php
return Excel::download(new InvoicesExport, 'invoices.csv', \Maatwebsite\Excel\Excel::CSV);
```

By default the CSV is download with Content Type `text/plain`, if you want to customize the Content-Type header, you can do so by passing it as 3rd parameter.

```php
return Excel::download(new InvoicesExport, 'invoices.csv', \Maatwebsite\Excel\Excel::CSV, [
      'Content-Type' => 'text/csv',
]);
```

:::tip Laravel CSV
You may have a look at our [Laravel CSV](/csv/1.0/getting-started/) package as well.
:::

## TSV

```php
return Excel::download(new InvoicesExport, 'invoices.tsv', \Maatwebsite\Excel\Excel::TSV);
```

## ODS

```php
return Excel::download(new InvoicesExport, 'invoices.ods', \Maatwebsite\Excel\Excel::ODS);
```

## XLS

```php
return Excel::download(new InvoicesExport, 'invoices.xls', \Maatwebsite\Excel\Excel::XLS);
```

## HTML

```php
return Excel::download(new InvoicesExport, 'invoices.html', \Maatwebsite\Excel\Excel::HTML);
```

::: warning Exporting to PDF
If you'd like to export to PDF, you must now install a PDF rendering library yourself. Please refer to the [PhpSpreadsheet Documentation](https://phpspreadsheet.readthedocs.io/en/latest/topics/reading-and-writing-to-file/#pdf) for more information.
:::

## MPDF

```php
return Excel::download(new InvoicesExport, 'invoices.pdf', \Maatwebsite\Excel\Excel::MPDF);
```

## DOMPDF

```php
return Excel::download(new InvoicesExport, 'invoices.pdf', \Maatwebsite\Excel\Excel::DOMPDF);
```

## TCPDF

```php
return Excel::download(new InvoicesExport, 'invoices.pdf', \Maatwebsite\Excel\Excel::TCPDF);
```

---

## File: 3.1/exports/exportables.md

# Exportables

[[toc]]

In the previous example, we used the `Excel::download` facade to start an export. 

Laravel Excel also provides a `Maatwebsite\Excel\Concerns\Exportable` trait, to make export classes exportable.

```php
namespace App\Exports;

use App\Invoice;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\Exportable;

class InvoicesExport implements FromCollection
{
    use Exportable;

    public function collection()
    {
        return Invoice::all();
    }
}
```

We can now download the export without the need for the facade:

```php
return (new InvoicesExport)->download('invoices.xlsx');
```

You can also pass the Writer Type and optional headers to the download method:

```php
return (new InvoicesExport)->download('invoices.csv', Excel::CSV, ['Content-Type' => 'text/csv']);
```

Or store it on a disk:

```php
return (new InvoicesExport)->store('invoices.xlsx', 's3');
```

You can also pass options to the disk if you like:

```php
return (new InvoicesExport)->store('invoices.xlsx', 's3', null, 'private');
```

## Responsable

The previous (download) example can be made even shorter when adding Laravel's `Responsable` interface to the export class:

```php
namespace App\Exports;

use App\Invoice;
use Maatwebsite\Excel\Excel;
use Illuminate\Contracts\Support\Responsable;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\Exportable;

class InvoicesExport implements FromCollection, Responsable
{
    use Exportable;
    
    /**
    * It's required to define the fileName within
    * the export class when making use of Responsable.
    */
    private $fileName = 'invoices.xlsx';
    
    /**
    * Optional Writer Type
    */
    private $writerType = Excel::XLSX;
    
    /**
    * Optional headers
    */
    private $headers = [
        'Content-Type' => 'text/csv',
    ];

    public function collection()
    {
        return Invoice::all();
    }
}
```

You can now easily return the export class, without the need of calling `->download()`.

```php
return new InvoicesExport();
```

---

## File: 3.1/exports/extending.md

# Extending

[[toc]]

## Events

The export process has a few events you can leverage to interact with the underlying 
classes to add custom behaviour to the export.

You are able to hook into the parent package by using events.
No need to use convenience methods like "query" or "view", if you need full control over the export.

The events will be activated by adding the `WithEvents` concern. Inside the `registerEvents` method, you 
will have to return an array of events. The key is the Fully Qualified Name (FQN) of the event and the value is a callable event listener.
This can either be a closure, array-callable or invokable class.

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Events\BeforeExport;
use Maatwebsite\Excel\Events\BeforeWriting;
use Maatwebsite\Excel\Events\BeforeSheet;

class InvoicesExport implements WithEvents
{
    /**
     * @return array
     */
    public function registerEvents(): array
    {
        return [
            // Handle by a closure.
            BeforeExport::class => function(BeforeExport $event) {
                $event->writer->getProperties()->setCreator('Patrick');
            },
            
            // Array callable, refering to a static method.
            BeforeWriting::class => [self::class, 'beforeWriting'],
            
            // Using a class with an __invoke method.
            BeforeSheet::class => new BeforeSheetHandler()
        ];
    }
    
    public static function beforeWriting(BeforeWriting $event) 
    {
        //
    }
}
```

Do note that using a `Closure` will not be possible in combination with queued exports, as PHP cannot serialize the closure.
In those cases it might be better to use the `RegistersEventListeners` trait.

### Auto register event listeners

By using the `RegistersEventListeners` trait you can auto-register the event listeners,
without the need of using the `registerEvents`. The listener will only be registered if the method is created. 

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Concerns\RegistersEventListeners;
use Maatwebsite\Excel\Events\BeforeExport;
use Maatwebsite\Excel\Events\BeforeWriting;
use Maatwebsite\Excel\Events\BeforeSheet;
use Maatwebsite\Excel\Events\AfterSheet;

class InvoicesExport implements WithEvents
{
    use Exportable, RegistersEventListeners;
    
    public static function beforeExport(BeforeExport $event)
    {
        //
    }

    public static function beforeWriting(BeforeWriting $event)
    {
        //
    }

    public static function beforeSheet(BeforeSheet $event)
    {
        //
    }

    public static function afterSheet(AfterSheet $event)
    {
        //
    }
}
```

### Global event listeners

Event listeners can also be configured globally, if you want to perform the same actions on all exports in your app.
You can add them to e.g. your `AppServiceProvider` in the `register()` method.

```php
Writer::listen(BeforeExport::class, function () {
    //
});

Writer::listen(BeforeWriting::class, function () {
    //
});

Sheet::listen(BeforeSheet::class, function () {
    //
});

Sheet::listen(AfterSheet::class, function () {
    //
});
```

### Available events

| Event name | Payload | Explanation |
|---- |----| ----|
|`Maatwebsite\Excel\Events\BeforeExport` | `$event->writer : Writer` | Event gets raised at the start of the process. | 
| `Maatwebsite\Excel\Events\BeforeWriting` | `$event->writer : Writer` | Event gets raised before the download/store starts. |
| `Maatwebsite\Excel\Events\BeforeSheet` | `$event->sheet : Sheet` | Event gets raised just after the sheet is created. |
| `Maatwebsite\Excel\Events\AfterSheet` | `$event->sheet : Sheet` | Event gets raised at the end of the sheet process. |

## Custom Concerns

You can add custom concerns to your app. This can be useful if you want to share some concerns over a few projects or want to open source your custom concerns.

Let's add a `WithCustomProperties` concern to your app. You could add these concerns to `App/Exports/Concerns`, but any location will do as long as it can be autoloaded by Composer.

```php
namespace App\Exports\Concerns;

interface WithCustomProperties
{
    /**
     *
     * @return string
     */
    public function description(): string;
}
```

Next to this concern we will create a concern handler `WithCustomPropertiesHandler`. This class can also be added to `App/Exports/Concerns`, but is again completely free of choice. 
A concern handler is basically just an invokable class. It receives your exportable object and either a `Writer` or `Sheet` object, depending on the chosen event.

```php
namespace App\Exports\Concerns;

use App\Exports\Concerns\WithCustomProperties;
use Maatwebsite\Excel\Writer;

class WithCustomPropertiesHandler
{
    /**
     * @param WithCustomProperties $exportable
     * @param Writer               $writer
     */
    public function __invoke(WithCustomProperties $exportable, Writer $writer)
    {
        $writer
            ->getDelegate()
            ->getProperties()
            ->setDescription(
                $exportable->description()
            );
    }
}
```

We will then register this concern in a service provider. You could use `App/Providers/AppServiceProvider` for this.

```php
public function register()
{
    Excel::extend(WithCustomProperties::class, new WithCustomPropertiesHandler);
}
```

:bulb: `::extend` accepts a callable as second parameter. It's also possible to pass a closure.

```php
public function register()
{
    Excel::extend(WithCustomProperties::class, function(WithCustomProperties $exportable, Writer $writer) {
        $writer->getDelegate()->getProperties()->setDescription($exportable->description());
    });
}
```

You can also bind concern handlers to different hooks. By default a concern handler is always bound to the `BeforeWriting` event. You can easily customize this, by supplying a 3rd parameter.

```php
public function register()
{
    Excel::extend(WithCustomProperties::class, new WithCustomPropertiesHandler, BeforeExport::class);
}
```

## Macroable

Both `Writer` and `Sheet` are "macroable" which means they can easily be extended to fit your needs. 
Both Writer and Sheet have a `->getDelegate()` method which returns the underlying PhpSpreadsheet class. 
This will allow you to add custom macros as shortcuts to PhpSpreadsheet methods that are not available in this package. 

### Writer

```php
use \Maatwebsite\Excel\Writer;

Writer::macro('setCreator', function (Writer $writer, string $creator) {
    $writer->getDelegate()->getProperties()->setCreator($creator);
});
```

### Sheet

```php
use \Maatwebsite\Excel\Sheet;

Sheet::macro('setOrientation', function (Sheet $sheet, $orientation) {
    $sheet->getDelegate()->getPageSetup()->setOrientation($orientation);
});
```

### Customize  
You can create your own macro to add custom methods to a spreadsheet instance. 

For example, to add styling to a cell, we first create a macro, let's call it `styleCells`:


```php
use \Maatwebsite\Excel\Sheet;

Sheet::macro('styleCells', function (Sheet $sheet, string $cellRange, array $style) {
    $sheet->getDelegate()->getStyle($cellRange)->applyFromArray($style);
});
```

Once the macro is created, it can be used inside the `registerEvents()` method as such:

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Events\BeforeExport;
use Maatwebsite\Excel\Events\AfterSheet;

class InvoicesExport implements WithEvents
{
    /**
     * @return array
     */
    public function registerEvents(): array
    {
        return [
            BeforeExport::class  => function(BeforeExport $event) {
                $event->writer->setCreator('Patrick');
            },
            AfterSheet::class    => function(AfterSheet $event) {
                $event->sheet->setOrientation(\PhpOffice\PhpSpreadsheet\Worksheet\PageSetup::ORIENTATION_LANDSCAPE);

                $event->sheet->styleCells(
                    'B2:G8',
                    [
                        'borders' => [
                            'outline' => [
                                'borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THICK,
                                'color' => ['argb' => 'FFFF0000'],
                            ],
                        ]
                    ]
                );
            },
        ];
    }
}
```
### RTL (Right to Left) Sheets

To change the Excel sheet direction you can use `setRightToLeft(true)` as in the below example

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Events\BeforeExport;
use Maatwebsite\Excel\Events\AfterSheet;

class InvoicesExport implements WithEvents
{
    /**
     * @return array
     */
    public function registerEvents(): array
    {
        return [
            AfterSheet::class    => function(AfterSheet $event) {
                $event->sheet->getDelegate()->setRightToLeft(true);
            },
        ];
    }
}
```

Feel free to use the above macro, or be creative and invent your own!

For PhpSpreadsheet methods, please refer to [their documentation](https://phpspreadsheet.readthedocs.io/).

---

## File: 3.1/exports/from-generator.md

---
pageClass: no-toc
---

# From Generator

Exports can be created from a PHP [generator](https://www.php.net/manual/en/class.generator.php) class, by using the `FromGenerator` concern.

A generator allows you to write code that uses foreach to iterate over a set of data without needing to build an array in memory.

```php
namespace App\Exports;

use Generator;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromGenerator;

class DataExport implements FromGenerator
{
    use Exportable;

    public function generator(): Generator
    {
        for ($i = 1; $i <= 100; $i++) {
            yield [$i, $i+1, $i+2];
        }
    }
}
```

You can download the export in your controller:

```php
public function export() 
{
    return (new DataExport)->download('data.xlsx');
}
```

:::tip Using Queue with FromGenerator is not supported. In case a queue is desired, we recommend wrapping the export file in a job, then using `->store` :::

---

## File: 3.1/exports/from-query.md

# From Query

[[toc]]

In the previous example, we did the query inside the export class. 
While this is a good solution for small exports, 
for bigger exports this will come at a hefty performance price.

By using the `FromQuery` concern, we can prepare a query for an export. Behind the scenes this query is executed in chunks.

In the `InvoicesExport` class, add the `FromQuery` concern and return a query. Be sure to **not** `->get()` the results!

```php
namespace App\Exports;

use App\Invoice;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\Exportable;

class InvoicesExport implements FromQuery
{
    use Exportable;

    public function query()
    {
        return Invoice::query();
    }
}
```

We can still download the export in the same way:

```php
return (new InvoicesExport)->download('invoices.xlsx');
```

## Customizing the query

It's easy to pass custom parameters to the query, 
by simply passing them as dependencies to the export class.

### As constructor parameter

```php
namespace App\Exports;

use App\Invoice;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\Exportable;

class InvoicesExport implements FromQuery
{
    use Exportable;

    public function __construct(int $year)
    {
        $this->year = $year;
    }

    public function query()
    {
        return Invoice::query()->whereYear('created_at', $this->year);
    }
}
```

The year can now be passed as dependency to the export class:

```php
return (new InvoicesExport(2018))->download('invoices.xlsx');
```

### As setter

```php
namespace App\Exports;

use App\Invoice;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\Exportable;

class InvoicesExport implements FromQuery
{
    use Exportable;

    public function forYear(int $year)
    {
        $this->year = $year;
        
        return $this;
    }

    public function query()
    {
        return Invoice::query()->whereYear('created_at', $this->year);
    }
}
```

We can adjust the year by using the `forYear` method:

```php
return (new InvoicesExport)->forYear(2018)->download('invoices.xlsx');
```

### Macro's and Mixins

The Eloquent Builder/Model has a macro to directly download an Eloquent query to Excel.

```php
User::query()->where('name', 'Patrick')->downloadExcel('query-download.xlsx');
```

If you want to include header row, you can pass `true` as third parameter:

```php
User::query()->downloadExcel('query-download.xlsx', Excel::XLSX, true);
```

Similarly, you can store the results of a query:

```php
User::query()->storeExcel('query-store.xlsx', 'your-disk');
```

---

## File: 3.1/exports/from-view.md

---
pageClass: no-toc
---

# From View

Exports can be created from a Blade view, by using the `FromView` concern.

```php
namespace App\Exports;

use App\Invoice;
use Illuminate\Contracts\View\View;
use Maatwebsite\Excel\Concerns\FromView;

class InvoicesExport implements FromView
{
    public function view(): View
    {
        return view('exports.invoices', [
            'invoices' => Invoice::all()
        ]);
    }
}
```

It will convert an HTML table into an Excel spreadsheet. For example; `invoices.blade.php`:

```html
<table>
    <thead>
    <tr>
        <th>Name</th>
        <th>Email</th>
    </tr>
    </thead>
    <tbody>
    @foreach($invoices as $invoice)
        <tr>
            <td>{{ $invoice->name }}</td>
            <td>{{ $invoice->email }}</td>
        </tr>
    @endforeach
    </tbody>
</table>
```

Attribute in tag html support:

|Attributes|Description
|-----------|-------------
|bgcolor| set background color to cell ``
|colspan| merge column cell
|rowspan| merge row cell
|width| set width to cell
|height| set height to cell
|data-format| set format `PhpOffice\PhpSpreadsheet\Style::NumberFormat`
|data-type| set type `PhpOffice\PhpSpreadsheet\Cell`
|align| set text align to cell
|valign| set vertical align to cell
|style| set style to cell

Style inline support
- background
- background-color
- color
- border|border-top|border-bottom|border-left|border-right
- font-size|font-weight|font-sytle|font-family
- text-decoration: underline|line-through
- text-align
- vertical-align
- width|height
- word-wrap
- text-indent

You can download the export in your controller:

```php
public function export() 
{
    return Excel::download(new InvoicesExport, 'invoices.xlsx');
}
```

---

## File: 3.1/exports/headings.md

# Headings

[[toc]]

## Adding a heading row

A heading row can easily be added by adding the `WithHeadings` concern. The heading row will be added
as very first row of the sheet.

```php

use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;

class InvoicesExport implements FromQuery, WithHeadings
{
    public function headings(): array
    {
        return [
            '#',
            'User',
            'Date',
        ];
    }
}
```

If you need to have multiple heading rows, you can return multiple rows from the `headings()` method:


```php

use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;

class InvoicesExport implements FromQuery, WithHeadings
{
    public function headings(): array
    {
        return [
           ['First row', 'First row'],
           ['Second row', 'Second row'],
        ];
    }
}
```

---

## File: 3.1/exports/index.md

---
pageClass: no-toc
---

# :rocket: 5 minute quick start

[[toc]]

:muscle: Create an export class in `app/Exports`

You may do this by using the `make:export` command.

```
php artisan make:export UsersExport --model=User
```

The file can be found in `app/Exports`:

::: vue
.
├── app
│   ├── `Exports` 
│   │   ├── UsersExport.php
│ 
└── composer.json
:::

If you prefer to create the export manually, you can create the following in `app/Exports`:

```php
<?php

namespace App\Exports;

use App\Models\User;
use Maatwebsite\Excel\Concerns\FromCollection;

class UsersExport implements FromCollection
{
    public function collection()
    {
        return User::all();
    }
}
```

:fire: In your controller you can call this export now:

```php
<?php

namespace App\Http\Controllers;

use App\Exports\UsersExport;
use Maatwebsite\Excel\Facades\Excel;

class UsersController extends Controller 
{
    public function export() 
    {
        return Excel::download(new UsersExport, 'users.xlsx');
    }
}
```

And finally add a route to be able to access the export:
```php
Route::get('users/export/', [UsersController::class, 'export']);
```


:page_facing_up: Find your `users.xlsx` in your downloads folder!

---

## File: 3.1/exports/mapping.md

# Mapping data

[[toc]]

## Mapping rows

By adding `WithMapping` you map the data that needs to be added as row. This way you have control over the actual source for each column.
In case of using the Eloquent query builder: 

```php

use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithMapping;
use PhpOffice\PhpSpreadsheet\Shared\Date;

class InvoicesExport implements FromQuery, WithMapping
{    
    /**
    * @param Invoice $invoice
    */
    public function map($invoice): array
    {
        return [
            $invoice->invoice_number,
            $invoice->user->name,
            Date::dateTimeToExcel($invoice->created_at),
        ];
    }
}
```


### Multiple rows

You can also return multiple rows inside the map function:

```php

use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithMapping;
use PhpOffice\PhpSpreadsheet\Shared\Date;

class InvoicesExport implements FromQuery, WithMapping
{    
    /**
    * @param Invoice $invoice
    */
    public function map($invoice): array
    {
        // This example will return 3 rows.
        // First row will have 2 column, the next 2 will have 1 column
        return [
            [
                $invoice->invoice_number,
                Date::dateTimeToExcel($invoice->created_at),
            ],
            [
                $invoice->lines->first()->description,
            ],
            [
                $invoice->lines->last()->description,
            ]
        ];
    }
}
```

## Prepare rows

If you need to prepare rows before appending these rows to sheet, you can add method `prepareRows` to your export class. This method will be called before flattening the query output and calling `map()`.

```php

use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;

class UsersExport implements FromQuery, WithHeadings
{   
    public function prepareRows($rows)
    {
        return $rows->transform(function ($user) {
            $user->name .= ' (prepared)';

            return $user;
        });
    }
}
```

---

## File: 3.1/exports/multiple-sheets.md

# Multiple Sheets

[[toc]]

To allow the export to have multiple sheets, the `WithMultipleSheets` concern should be used. 
The `sheets()` method expects an array of sheet export objects to be returned.

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\WithMultipleSheets;

class InvoicesExport implements WithMultipleSheets
{
    use Exportable;

    protected $year;
    
    public function __construct(int $year)
    {
        $this->year = $year;
    }

    /**
     * @return array
     */
    public function sheets(): array
    {
        $sheets = [];

        for ($month = 1; $month <= 12; $month++) {
            $sheets[] = new InvoicesPerMonthSheet($this->year, $month);
        }

        return $sheets;
    }
}
```

## Sheet classes

The `InvoicesPerMonthSheet` can implement concerns like `FromQuery`, `FromCollection`, `FromView`, ... 

_Note: The WithTitle concern is needed in order to name each sheet using the `title()` method_
```php
namespace App\Exports\Sheets;

use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithTitle;

class InvoicesPerMonthSheet implements FromQuery, WithTitle
{
    private $month;
    private $year;

    public function __construct(int $year, int $month)
    {
        $this->month = $month;
        $this->year  = $year;
    }

    /**
     * @return Builder
     */
    public function query()
    {
        return Invoice
            ::query()
            ->whereYear('created_at', $this->year)
            ->whereMonth('created_at', $this->month);
    }

    /**
     * @return string
     */
    public function title(): string
    {
        return 'Month ' . $this->month;
    }
}
```

The code below can be implemented in any class in order to download an xlsx of all invoices from the current year, with 12 worksheets representing each month of the year.

```php
public function downloadInvoices() 
{
    return (new InvoicesExport(2018))->download('invoices.xlsx');
}
```

---

## File: 3.1/exports/queued.md

# Queued

[[toc]]

In case you are working with a lot of data, it might be wise to queue the entire process. 

Given we have the following export class:

```php
namespace App\Exports;

use App\Invoice;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromQuery;

class InvoicesExport implements FromQuery
{
    use Exportable;

    public function query()
    {
        return Invoice::query();
    }
}
```

It's as easy as calling `->queue()` now.

```php
(new InvoicesExport)->queue('invoices.xlsx');

return back()->withSuccess('Export started!');
```

Behind the scenes the query will be chunked and multiple jobs will be chained. These jobs will be executed in the correct order,
and will only execute if none of the previous have failed. 

## Implicit Export queueing

You can also mark an export implicitly as a queued export. You can do this by using Laravel's `ShouldQueue` contract.

```php
namespace App\Exports;

use App\Invoice;
use Illuminate\Contracts\Queue\ShouldQueue;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromQuery;

class InvoicesExport implements FromQuery, ShouldQueue
{
    use Exportable;

    public function query()
    {
        return Invoice::query();
    }
}
```

In your controller you can now call the normal `->store()` method. 
Based on the presence of the `ShouldQueue` contract, the export will be queued.

```php
(new InvoicesExport)->store('invoices.xlsx');
```

## Appending jobs

The `queue()` method returns an instance of Laravel's `PendingDispatch`. This means you can chain extra jobs that will be added to the end of the queue and only executed if all export jobs are correctly executed.

```php
(new InvoicesExport)->queue('invoices.xlsx')->chain([
    new NotifyUserOfCompletedExport(request()->user()),
]);
```

```php
namespace App\Jobs;

use App\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\SerializesModels;

class NotifyUserOfCompletedExport implements ShouldQueue
{
    use Queueable, SerializesModels;
    
    public $user;
    
    public function __construct(User $user)
    {
        $this->user = $user;
    }

    public function handle()
    {
        $this->user->notify(new ExportReady());
    }
}
```

## Handling failures in queued exports

When queuing exports you might want a way to handle failed exports. You can do this by adding `failed` method to your export class.

```php

use Throwable;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;

class UsersExport implements FromQuery, WithHeadings
{   
    public function failed(Throwable $exception): void
    {
        // handle failed export
    }
}
```


## Custom queues

Because `PendingDispatch` is returned, we can also change the queue that should be used.

For Laravel 8+:

```php
(new InvoicesExport)->queue('invoices.xlsx')->onQueue('exports');
```
For older versions of Laravel:

```php
(new InvoicesExport)->queue('invoices.xlsx')->allOnQueue('exports');
```

## Multi-server setup

If you are dealing with a multi-server setup (using e.g. a loadbalancer), you might want to make sure the temporary file that is used to store each chunk of data on, is the same for each job. You can achieve this by configuring a remote temporary file in the config.

In `config/excel.php`

```php
'temporary_files' => [
    'remote_disk' => 's3',
],
```

## Job Middleware

If you are using Laravel 6, [job middleware](https://laravel.com/docs/6.x/queues#job-middleware) can be attached to the export class using the `middleware` method:

```php
namespace App\Exports;

use App\Jobs\Middleware\RateLimited;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\FromQuery;

class ExportClass implements FromQuery
{
    use Exportable;
    
    public function middleware()
    {
        return [new RateLimited];
    }

    public function query()
    {
        // ...
    }
}
```

## Localizing Queued Export

If you want to localize your queued export you should implement `HasLocalePreference` contract on your export:

```php
namespace App\Exports;

use Illuminate\Contracts\Translation\HasLocalePreference;
use Maatwebsite\Excel\Concerns\Exportable;

class ExportClass implements HasLocalePreference
{
    use Exportable;
    
    public function __construct(string $locale)
    {
        $this->locale = $locale;
    }
    
    public function preferredLocale()
    {
        return $this->locale;
    }
}
```

## Custom Query Size
Queued exportables are processed in chunks; each chunk being a job pushed to the queue by the `QueuedWriter`.
In case of exportables that implement the [FromQuery](/3.1/exports/from-query.html) concern, the number of jobs is calculated by dividing the `$query->count()` by the chunk size.

### When to use
Depending on the implementation of the `query()` method (e.g. when using a `groupBy` clause), the calculation mentioned before might not be correct.

If this is the case, you should use the `WithCustomQuerySize` concern to provide a custom calculation of the query size.

---

## File: 3.1/exports/settings.md

# Settings

[[toc]]

## Properties

By default the Worksheet properties get configured in `config/excel.php`. You can configure a default title, description, creator, etc.

If you want to overrule on a per export basis, you can use the `WithProperties` concern.

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithProperties;

class InvoicesExport implements WithProperties
{    
    public function properties(): array
    {
        return [
            'creator'        => 'Patrick Brouwers',
            'lastModifiedBy' => 'Patrick Brouwers',
            'title'          => 'Invoices Export',
            'description'    => 'Latest Invoices',
            'subject'        => 'Invoices',
            'keywords'       => 'invoices,export,spreadsheet',
            'category'       => 'Invoices',
            'manager'        => 'Patrick Brouwers',
            'company'        => 'Spartner',
        ];
    }
}
```

It's not required to return all properties, you can ommit the keys you don't want to overrule.

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithProperties;

class InvoicesExport implements WithProperties
{    
    public function properties(): array
    {
        return [
            'creator'        => 'Patrick Brouwers',
        ];
    }
}
```

## Custom CSV Settings

By default Laravel Excel uses the defaults from the config (`config/excel.php`). You can change this by adding the `WithCustomCsvSettings` interface.

```php
namespace App\Exports;

use Maatwebsite\Excel\Concerns\WithCustomCsvSettings;

class InvoicesExport implements WithCustomCsvSettings
{    
    public function getCsvSettings(): array
    {
        return [
            'delimiter' => ';',
            'use_bom' => false,
            'output_encoding' => 'ISO-8859-1',
        ];
    }
}
```

### Available csv settings

* `delimiter`
* `enclosure`
* `line_ending`
* `use_bom`
* `include_separator_line`
* `excel_compatibility`
* `output_encoding`

## Cell caching

By default PhpSpreadsheet keeps all cell values in memory, however when dealing with large files, this might result into memory issues. If you want to mitigate that, you can configure a cell caching driver here.

When using the illuminate driver, it will store each value in the cache store. This can slow down the process, because it needs to store each value. However it will use less memory.
It will automatically use your default cache store. However if you prefer to have the cell cache on a separate store, you can configure the store name here. You can use any store defined in your cache config. When leaving at "null" it will use the default store.

You can use the "batch" store if you want to only persist to the store when the memory limit is reached. You can tweak the memory limit in the config.

Cells written to the cache store expire after `cache.default_ttl` seconds (set it to `null` to keep them indefinitely).

::: warning
`default_ttl` is only applied when the cache is called without a TTL argument. An explicit `null` TTL stores the cell forever. If you wrap or extend the `batch` driver (for example with `CacheManager::extend()`), don't forward a `null` TTL to it: leave the argument out, or pass `$ttl ?? config('excel.cache.default_ttl')`. Otherwise, the cells of any export that fails before PhpSpreadsheet releases them stay in the cache store permanently.
:::

---

## File: 3.1/exports/store.md

# Storing exports on disk

[[toc]]

Exports can easily be stored on any [filesystem](https://laravel.com/docs/master/filesystem) that Laravel supports.


## Default disk

```php
public function storeExcel() 
{
    // Store on default disk
    Excel::store(new InvoicesExport(2018), 'invoices.xlsx');
}
```

## Custom disks

```php
public function storeExcel() 
{
    // Store on a different disk (e.g. s3)
    Excel::store(new InvoicesExport(2018), 'invoices.xlsx', 's3');
    
    // Store on a different disk with a defined writer type. 
    Excel::store(new InvoicesExport(2018), 'invoices.xlsx', 's3', Excel::XLSX);
}
```

## Disk options

If you want to pass some options to the disk, pass them to Excel::store() as the fifth parameter.

```php
public function storeExcel() 
{
    Excel::store(new InvoicesExport(2018), 'invoices.xlsx', 's3', null, [
        'visibility' => 'private',
    ]);
}
```

Laravel has a shortcut for private files:

```php
public function storeExcel() 
{
    Excel::store(new InvoicesExport(2018), 'invoices.xlsx', 's3', null, 'private');
}
```

::: warning File names cannot include certain characters: 
- `<` (less than)
- `>` (greater than)
- `:` (colon)
- `"` (double quote)
- `/` (forward slash)
- `\` (backslash)
- `|` (vertical bar or pipe)
- `?` (question mark)
- `*` (asterisk)
:::

## Note about queuing
If you are storing the export using `Excel::queue()` or using the `ShouldQueue` interface, make sure to have a look at the [queuing docs](https://docs.laravel-excel.com/3.1/exports/queued.html)

---

## File: 3.1/exports/testing.md

# Testing

[[toc]]

The Excel facade can be used to swap the exporter to a fake.

## Testing downloads

```php
/**
* @test
*/
public function user_can_download_invoices_export() 
{
    Excel::fake();

    $this->actingAs($this->givenUser())
         ->get('/invoices/download/xlsx');

    Excel::assertDownloaded('filename.xlsx', function(InvoicesExport $export) {
        // Assert that the correct export is downloaded.
        return $export->collection()->contains('#2018-01');
    });
}
```

## Testing storing exports

```php
/**
* @test
*/
public function user_can_store_invoices_export() 
{
    Excel::fake();

    $this->actingAs($this->givenUser())
         ->get('/invoices/store/xlsx');

    Excel::assertStored('filename.xlsx', 'diskName');
    
    Excel::assertStored('filename.xlsx', 'diskName', function(InvoicesExport $export) {
        return true;
    });
    
    // When passing the callback as 2nd param, the disk will be the default disk.
    Excel::assertStored('filename.xlsx', function(InvoicesExport $export) {
        return true;
    });
}
```

## Testing queuing exports

```php
/**
* @test
*/
public function user_can_queue_invoices_export() 
{
    Excel::fake();

    $this->actingAs($this->givenUser())
         ->get('/invoices/queue/xlsx');

    Excel::assertQueued('filename.xlsx', 'diskName');
    
    Excel::assertQueued('filename.xlsx', 'diskName', function(InvoicesExport $export) {
        return true;
    });
    
    // When passing the callback as 2nd param, the disk will be the default disk.
    Excel::assertQueued('filename.xlsx', function(InvoicesExport $export) {
        return true;
    });
    
    // Assert that the export was queued with a specific chain of other jobs.
    Excel::assertQueuedWithChain([
        new NotifyUsers(),
    ])
}
```

## Testing exports with dynamic file name/path

If you have dynamic naming for files or paths, you can use a regular expression to represent those while testing:

 ```php
/**
* @test
*/
public function user_can_store_invoices_export() 
{
    Excel::fake();
    
    $this->actingAs($this->givenUser())
         ->get('/invoices/store/xlsx');
    
    // Tells the mock to use regular expressions
    Excel::matchByRegex(); 
    // For a given dynamic named file 'invoices_2019.xlsx'
    Excel::assertStored('/invoices_\d{4}\.xlsx/', 'diskName');
}
```
Please note that your expression must match only one file/path. If more than one match is found, the test will fail.

---

## File: 3.1/getting-started/contributing.md

# Contributing

[[toc]]

Please read and understand the contribution guide before creating an issue or pull request.

## Important Links

- [Docs](https://docs.laravel-excel.com/)
- [Issue tracker](https://github.com/SpartnerNL/Laravel-Excel/issues)
- [Support](/3.1/getting-started/support.html)

## Etiquette

This project is an open source project, and as such, the maintainers use their free time to build and maintain it.
The code is freely available and can be used, forked and modified. 

Please be considerate towards maintainers when raising issues or presenting pull requests. 

It's the duty of the maintainer to ensure that all submissions to the project are of sufficient
quality to benefit the project. Many developers have different skill sets, strengths, and weaknesses. Respect the maintainer's decision, and do not be upset or abusive if your submission is not used.

## Viability

When requesting or submitting new features, first consider whether it might be useful to others. Open
source projects are used by many developers, who may have entirely different needs to your own. Think about
whether or not your feature is likely to be used by other users of the project.

## How to submit changes?

- Check the codebase to ensure that your feature doesn't already exist.
- Check the pull requests to ensure that another person hasn't already submitted the feature or fix.
- Use the [pull request template](https://github.com/SpartnerNL/Laravel-Excel/blob/3.1/.github/PULL_REQUEST_TEMPLATE.md).

## How to report a bug?

- Attempt to replicate the problem, to ensure that it wasn't a coincidental incident.
- Check to make sure your bug report isn't already present within the project.
- Check the pull requests tab to ensure that the bug doesn't have a fix in progress.
- Check the pull requests tab to ensure that the feature isn't already in progress.
- Use the [issue template](https://github.com/SpartnerNL/Laravel-Excel/blob/3.1/.github/ISSUE_TEMPLATE.md).

## PR Requirements
- The PR **must** apply to [PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md). StyleCI help you detect code style issues.
- The PR **must** be as clean as possible. Try to remove all inline TODOs and unneeded comments. They are noise and distraction for the reviewer. Use Github's (inline) comment system to start a discussion about a change.
- The existing tests **must** not fail after your changes. This would indicate that existing functionality is broken and should be addressed before a review is started. You can run the test by running `vendor/bin/phpunit`
- The changes **must** be backed-up with tests. 
- The PR **must** only have one feature. Split up multiple features in multiple PRs, so they can be individually reviewed and merged.
- The PR **must** be accompanied by a PR to the docs in case of new features. Documentation is located in the [https://github.com/SpartnerNL/laravel-excel-docs](https://github.com/SpartnerNL/laravel-excel-docs) repository.
- The PR should contain meaningful commit messages.

---

## File: 3.1/getting-started/index.md

---
pageClass: no-toc
---

# Introduction

:rocket: Laravel Excel is intended at being Laravel-flavoured PhpSpreadsheet: a simple, but elegant wrapper around PhpSpreadsheet with the goal of simplifying
exports and imports. 

:fire: [PhpSpreadsheet](https://phpspreadsheet.readthedocs.io/) is a library written in pure PHP and providing a set of classes that allow you to read from and to write to different spreadsheet file formats, like Excel and LibreOffice Calc.

## Laravel Excel Features

* Easily export collections to Excel.
* Export queries with automatic chunking for better performance.
* Queue exports for better performance.
* Easily export Blade views to Excel.
* Easily import to collections.
* Read the Excel file in chunks.
* Handle the import inserts in batches.

---

## File: 3.1/getting-started/installation.md

# Installation

[[toc]]

## Requirements

* PHP: `^7.2\|^8.0`
* Laravel: `^5.8`
* PhpSpreadsheet: `^1.21`
* PHP extension `php_zip` enabled
* PHP extension `php_xml` enabled
* PHP extension `php_gd2` enabled
* PHP extension `php_iconv` enabled
* PHP extension `php_simplexml` enabled
* PHP extension `php_xmlreader` enabled
* PHP extension `php_zlib` enabled

## Installation

Require this package in the `composer.json` of your Laravel project. This will download the package and _PhpSpreadsheet_.

```
composer require "maatwebsite/excel:^3.1"
```

If installing your receive the following error 

```
  Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - Root composer.json requires maatwebsite/excel 3.1 -> satisfiable by maatwebsite/excel[3.1.0].
    - maatwebsite/excel 3.1.0 requires php ^7.0 -> your php version (8.2.8) does not satisfy that requirement.
```

You can try simply to install without the caret

```
composer require maatwebsite/excel
```

If you don't get the latest version or run into more composer errors, please make sure you have installed all required PHP extensions like zip, gd, etc.

The `Maatwebsite\Excel\ExcelServiceProvider` is __auto-discovered__ and registered by default.

If you want to register it yourself, add the ServiceProvider in `config/app.php`:

```php
'providers' => [
    /*
     * Package Service Providers...
     */
    Maatwebsite\Excel\ExcelServiceProvider::class,
]
```

The `Excel` facade is also __auto-discovered__.

If you want to add it manually, add the Facade in `config/app.php`:

```php
'aliases' => [
    ...
    'Excel' => Maatwebsite\Excel\Facades\Excel::class,
]
```

To publish the config, run the vendor publish command:

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

This will create a new config file named `config/excel.php`.

---

## File: 3.1/getting-started/license.md

# License

[[toc]]

## MIT
Our software is open source and licensed under the [MIT license](https://choosealicense.com/licenses/mit/). You are free to use the software as you like. The code can be forked and modified, but the original copyright author should always be included!

## Postcardware
According to the [postcardware](https://en.wikipedia.org/wiki/Postcardware) concept, if you use the software for your project(s) we would appreciate to receive a postcard of your hometown. Please send it to:

**Spartner**  
Markt 2   
6231 LS Meerssen  
The Netherlands  

## Created by Spartner (formerly Maatwebsite)

We are a strategic development partner, creating web-based custom built software from Laravel. In need of a digital solution for your challenge? Give us a call. 

[https://spartner.software](https://spartner.software)  
[info@spartner.nl](mailto:info@spartner.nl)  
+31 (0) 10 - 7449312  

## Support

::: warning Support
We hold no liability and will provide support on a best effort basis. For more information about support please see [support](https://docs.laravel-excel.com/3.1/getting-started/support.html).
:::

:::tip Commercial Support
:rocket: If you use the software commercially and need support urgently, we can offer this on a commercial basis. Please contact  or phone +31 (0)10 744 9312.
:::

---

## File: 3.1/getting-started/support.md

# Support

[[toc]]

Our software is free and open source, meaning that the use of our software is optional. We hold no liability and there is no obligation to support. We will provide support on a best effort basis.

:::tip Commercial Support
If you use the software commercially and need elaborate support or need it urgently, we can offer this on a commercial basis. Please contact  or via phone +31 (0)10 744 9312.
:::

## Supported Versions

Versions will be supported for a limited amount of time.

| Version | Laravel Version                     | Php Version | Support                      |
|---------|-------------------------------------|-------------|------------------------------|
| 2.1     | <=5.6                               | <=7.0       | Unsupported since 15-5-2018  |
| 3.0     | ^5.5                                | ^7.0        | Unsupported since 31-12-2018 |
| 3.1     | ^5.8\|^6.0\|^7.0\|^8.0\|^9.0\|^10.0 | ^7.2\|^8.0  | No active support, CVE only  |

::: warning PHP version support
Support for PHP versions will only be maintained for a period of six months beyond the end-of-life of that PHP version.
:::

## Requesting support
Before you request support, please check the following:
* Attempt to replicate the problem, to ensure that it wasn't a coincidental incident.
* Check to make sure your support request isn't already present within the project.
* Check the pull requests tab to ensure that the bug doesn't have a fix in progress.
* Use one of the [issue templates](https://github.com/SpartnerNL/Laravel-Excel/tree/3.1/.github/ISSUE_TEMPLATE).

Filling out the template is required. Issues that do not include enough information might not  be picked up. Please write in English (or Dutch).

Please prefix your issue with one of the following: [BUG] [PROPOSAL] [QUESTION].

And please be considerate towards maintainers when raising issues.

---

## File: 3.1/getting-started/upgrade.md

# Upgrade Guide

[[toc]]

## Upgrading to 3.1 from 3.0

Version 3.1 is backwards compatible with 3.0. Only features were added in this release.

__Additions__

* Imports feature.
* ChunkReading
* BatchInserts
* Queued imports
* ToArray concern for Exports.
* Custom value binders for Imports and Exports.

__Removals__

* `Excel::filter('chunk')` method is removed, chunk filter is automatically added when using chunk reading.

## Upgrading to 3.* from 2.1

Version 3.* is not backwards compatible with 2.*. It's not possible to provide a step-by-step migration guide as it's a complete paradigm shift.

__New dependencies__

3.* introduces some new dependencies.

* Requires PHP 7.0 or higher.
* Requires Laravel 5.5 (or higher).
* Requires PhpSpreadsheet instead of PHPExcel.

__Deprecations__

ALL Laravel Excel 2.* methods are deprecated and will not be able to use in 3.0 . 

- `Excel::load()` is removed and replaced by `Excel::import($yourImport)`
- `Excel::create()` is removed and replaced by `Excel::download/Excel::store($yourExport)`
- `Excel::create()->string('xlsx')` is removed an replaced by `Excel::raw($yourExport, Excel::XLSX)`
- 3.0 provides no convenience methods for styling, you are encouraged to use PhpSpreadsheets native methods.

You can find an example upgrade for an export here: [https://github.com/SpartnerNL/Laravel-Excel/issues/1799](https://github.com/SpartnerNL/Laravel-Excel/issues/1799)

---

## File: 3.1/imports/basics.md

## Importing basics

[[toc]]

If you have followed the 5 minute quick start, you'll already have a `UsersImport` class.

```php
<?php

namespace App\Imports;

use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Maatwebsite\Excel\Concerns\ToModel;

class UsersImport implements ToModel
{
    /**
     * @param array $row
     *
     * @return User|null
     */
    public function model(array $row)
    {
        return new User([
           'name'     => $row[0],
           'email'    => $row[1],
           'password' => Hash::make($row[2]),
        ]);
    }
}
```

## Importing from default disk

Passing the UsersImport object to the `Excel::import()` method will tell the package how to import the file that is passed as second parameter. 
The file is expected to be located in your default filesystem disk (see `config/filesystems.php`).

```php
Excel::import(new UsersImport, 'users.xlsx');
```

### Importing from another disk

You can specify another disk with the third parameter like your Amazon s3 disk. (see `config/filesystems.php`)

```php
Excel::import(new UsersImport, 'users.xlsx', 's3');
```

## Importing uploaded files

If you let your user upload the document, you can also just pass the uploaded file directly.

```php
Excel::import(new UsersImport, request()->file('your_file'));
```

### Importing full path 

If you want to specifiy the path where your file is, without having to move it to a disk, you can directly pass that file path to the import method.

```php
Excel::import(new UsersImport, storage_path('users.xlsx'));
```

## Importing to array or collection

If you want to bypass the `ToArray` or `ToCollection` concerns and want to have an array of imported data in your controller (beware of performance!), you can use the `::toArray()` or `::toCollection()` method.

```php
$array = Excel::toArray(new UsersImport, 'users.xlsx');

$collection = Excel::toCollection(new UsersImport, 'users.xlsx');
```

## Specifying a reader type

If the reader type is not detectable by the file extension, you can specify a reader type by passing it as fourth parameter.

```php
Excel::import(new UsersImport, 'users.xlsx', 's3', \Maatwebsite\Excel\Excel::XLSX);
```

---

## File: 3.1/imports/batch-inserts.md

# Batch inserts

[[toc]]

Importing a large file to Eloquent models, might quickly become a bottleneck as every row results into an insert query. 

With the `WithBatchInserts` concern you can limit the amount of queries done by specifying a batch size. This batch size will determine how many models will be inserted into the database in one time. This will drastically reduce the import duration.

```php
namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithBatchInserts;

class UsersImport implements ToModel, WithBatchInserts
{
    public function model(array $row)
    {
        return new User([
            'name' => $row[0],
        ]);
    }
    
    public function batchSize(): int
    {
        return 1000;
    }
}
```

:::warning ToModel
This concern **only** works with the `ToModel` concern.
:::

:::tip Batch Size
A batch size of `1000` will not be the most optimal situation for your import. Play around with this number to find the sweet spot.
:::

## Batch upserts

For batch upserts, you can additionally implement the `WithUpserts` concern.

```php
class UsersImport implements ToModel, WithBatchInserts, WithUpserts
{
    public function model(array $row)
    {
        return new User([
            'name' => $row[0],
        ]);
    }
    
    public function batchSize(): int
    {
        return 1000;
    }

    public function uniqueBy()
    {
        return 'email';
    }
}
```

In the example above, if a user already exists with the same email, the row will be updated instead. Behind the scenes, this feature uses the Laravel `upsert` method and the `uniqueBy` method is used for the second argument of the `upsert` method, which lists the column(s) that uniquely identify records within the associated table.

:::warning
All databases except SQL Server require the `uniqueBy` columns to have a "primary" or "unique" index.
:::

## Skipping duplicate rows

For skipping duplicate models, you can additionally implement the `WithSkipDuplicates` concern.

```php
class UsersImport implements ToModel, WithBatchInserts, WithSkipDuplicates
{
    public function model(array $row)
    {
        return new User([
            'name' => $row[0],
        ]);
    }
    
    public function batchSize(): int
    {
        return 1000;
    }
}
```

In the example above, if a user already exists with the same primary or unique key, the row will be ignored. Behind the scenes, this feature uses the Laravel `insertOrIgnore` method to insert records while ignoring duplicates, preventing any errors that would normally occur due to duplicate entries.

---

## File: 3.1/imports/chunk-reading.md

# Chunk reading

[[toc]]

Importing a large file can have a huge impact on the memory usage, as the library will try to load the entire sheet into memory.

To mitigate this increase in memory usage, you can use the `WithChunkReading` concern. This will read the spreadsheet in chunks and keep the memory usage under control.

```php
namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithChunkReading;

class UsersImport implements ToModel, WithChunkReading
{
    public function model(array $row)
    {
        return new User([
            'name' => $row[0],
        ]);
    }
    
    public function chunkSize(): int
    {
        return 1000;
    }
}
```

::: warning
A chunk size of `1000` will not be the most optimal situation for your import. Play around with this number to find the sweet spot.
:::

## Using it together with Batch Inserts

The most ideal situation (regarding time and memory consumption) you will find when combining batch inserts and chunk reading.

```php
namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithBatchInserts;
use Maatwebsite\Excel\Concerns\WithChunkReading;

class UsersImport implements ToModel, WithBatchInserts, WithChunkReading
{
    public function model(array $row)
    {
        return new User([
            'name' => $row[0],
        ]);
    }
    
    public function batchSize(): int
    {
        return 1000;
    }
    
    public function chunkSize(): int
    {
        return 1000;
    }
}
```

## Keep Track of the Row number

If you need the row number you can use the `RemembersRowNumber` Trait.

```php
namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\RemembersRowNumber;
use Maatwebsite\Excel\Concerns\WithChunkReading;

class UsersImport implements ToModel, WithChunkReading
{
    use RemembersRowNumber;

    public function model(array $row)
    {
        $currentRowNumber = $this->getRowNumber();

        return new User([
            'name' => $row[0],
        ]);
    }
    
    public function chunkSize(): int
    {
        return 1000;
    }
}
```

::: warning
Remembering row numbers is only intended for ToModel imports.
:::

If you only need the information about the offset of the chunk you can use the `RemembersChunkOffset` Trait.

```php
namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\RemembersChunkOffset;
use Maatwebsite\Excel\Concerns\WithChunkReading;

class UsersImport implements ToModel, WithChunkReading
{
    use RemembersChunkOffset;

    public function model(array $row)
    {
        $chunkOffset = $this->getChunkOffset();

        return new User([
            'name' => $row[0],
        ]);
    }
    
    public function chunkSize(): int
    {
        return 1000;
    }
}
```

---

## File: 3.1/imports/collection.md

---
pageClass: no-toc
---

# Importing to collections

[[toc]]

The easiest way to start an import is to create a custom import class. We'll use a user import as example.

Create a new class called `UsersImport` in `app/Imports`:

```php
namespace App\Imports;

use App\User;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\ToCollection;

class UsersImport implements ToCollection
{
    public function collection(Collection $collection)
    {
        foreach ($collection as $row) 
        {
            User::create([
                'name' => $row[0],
            ]);
        }
    }
}
```

The collection method will receive a collection of rows. A row is an array filled with the cell values. 

In case of the file having multiple sheets, the `collection()` method will be called multiple times.

In your controller we can now import this:

```php
public function import() 
{
    Excel::import(new UsersImport, 'users.xlsx');
}
```

:::warning
Whatever you return in the `collection()` method will **not** be returned to the controller.
:::

---

## File: 3.1/imports/concerns.md

---
pageClass: no-toc
---

# Import concerns

| Interface | Explanation | Documentation |
|---- |----|----|
|`Maatwebsite\Excel\Concerns\ToCollection`| Import to a collection. | [Importing to collections](/3.1/imports/collection.html) |
|`Maatwebsite\Excel\Concerns\ToArray`| Import to an array. | |
|`Maatwebsite\Excel\Concerns\ToModel`| Import each row to a model. | [Importing to models](/3.1/imports/model.html) |
|`Maatwebsite\Excel\Concerns\OnEachRow`| Handle each row manually. | |
|`Maatwebsite\Excel\Concerns\WithBatchInserts`| Insert models in batches. | [Batch inserts](/3.1/imports/batch-inserts.html) |
|`Maatwebsite\Excel\Concerns\WithChunkReading`| Read the sheet in chunks. | [Chunk reading](/3.1/imports/chunk-reading.html) |
|`Maatwebsite\Excel\Concerns\WithHeadingRow`| Define a row as heading row. | [Heading row](/3.1/imports/heading-row.html) |
|`Maatwebsite\Excel\Concerns\WithGroupedHeadingRow`| Allows columns sharing the same header key to group values in array | [Heading row](/3.1/imports/heading-row.html#grouping-values-of-multiple-columns-sharing-same-header) |
|`Maatwebsite\Excel\Concerns\WithLimit`| Define a limit of the amount of rows that need to be imported. |
|`Maatwebsite\Excel\Concerns\WithCustomValueBinder`| Define a custom value binder. | [Custom Formatting Values](/3.1/imports/custom-formatting-values.html) |
|`Maatwebsite\Excel\Concerns\WithMappedCells`| Define a custom cell mapping. | [Mapped Cells](/3.1/imports/mapped-cells.html) |
|`Maatwebsite\Excel\Concerns\WithMapping`| Map the row before being called in ToModel/ToCollection. | |
|`Maatwebsite\Excel\Concerns\WithMultipleSheets`| Enable multi-sheet support. Each sheet can have its own concerns (except this one). | [Multiple Sheets](/3.1/imports/multiple-sheets.html) |
|`Maatwebsite\Excel\Concerns\WithCalculatedFormulas`| Calculates the formulas when importing. By default this is disabled. | |
|`Maatwebsite\Excel\Concerns\WithEvents`| Register events to hook into the PhpSpreadsheet process. | [Events](/3.1/imports/extending.html#events) |
|`Maatwebsite\Excel\Concerns\WithCustomCsvSettings`| Allows to run custom Csv settings for this specific importable. | [Custom CSV Settings](/3.1/imports/custom-csv-settings.html) |
|`Maatwebsite\Excel\Concerns\WithStartRow`| Define a custom start row. | |
|`Maatwebsite\Excel\Concerns\WithProgressBar`| Shows a progress bar when uploading via the console. | [Progress Bar](/3.1/imports/progress-bar.html) |
|`Maatwebsite\Excel\Concerns\WithUpserts`| Allows to upsert models. | [Upserting models](/3.1/imports/model.html#upserting-models) |
|`Maatwebsite\Excel\Concerns\WithUpsertColumns`| Allows upsert columns definition. | [Upserting with specific columns](/3.1/imports/model.html#upserting-with-specific-columns) |
|`Maatwebsite\Excel\Concerns\WithValidation`| Validates each row against a set of rules. | [Row Validation](/3.1/imports/validation.html) |
|`Maatwebsite\Excel\Concerns\SkipsEmptyRows`| Skips empty rows. | [Row Validation](/3.1/imports/validation.html#skipping-empty-rows) |
|`Maatwebsite\Excel\Concerns\SkipsOnFailure`| Skips on validation errors. | [Row Validation](/3.1/imports/validation.html#skipping-failures) |
|`Maatwebsite\Excel\Concerns\SkipsOnError`| Skips on database exceptions. | [Row Validation](/3.1/imports/validation.html#skipping-errors) |
|`Maatwebsite\Excel\Concerns\WithColumnLimit` | Allows setting an end column ||
|`Maatwebsite\Excel\Concerns\WithReadFilter` | Allows defining a custom read filter ||


### Traits

| Trait | Explanation | Documentation |
|---- |----|----|
|`Maatwebsite\Excel\Concerns\Importable` | Add import/queue abilities right on the import class itself. | [Importables](/3.1/imports/importables.html) |
|`Maatwebsite\Excel\Concerns\RegistersEventListeners` | Auto-register the available event listeners. | [Auto register event listeners](/3.1/imports/extending.html#auto-register-event-listeners) |

---

## File: 3.1/imports/custom-csv-settings.md

# Custom CSV Settings

[[toc]]

By default Laravel Excel uses the defaults from the config (`config/excel.php`). You can change this by adding the `WithCustomCsvSettings` interface.

```php
namespace App\Imports;

use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithCustomCsvSettings;

class UsersImport implements ToModel, WithCustomCsvSettings
{
    public function model(array $row)
    {
        return new User([
            'name' => $row['0'],
            'email' => $row['1']
        ]);
    }
    
    public function getCsvSettings(): array
    {
        return [
            'input_encoding' => 'ISO-8859-1'
        ];
    }
}
```


A CSV file stores data in rows and the values in each row is separated with a separator, also known as a delimiter. Although the file is defined as Comma Separated Values, the delimiter could be anything. Delimiter requires a single character. For Tab use `"\t"`. The most common delimiters are: a comma `,`, a semicolon `;`, a tab `\t`, a space ` `, or a pipe `|`.

```php
public function getCsvSettings(): array
{
    return [
        'delimiter' => "\t"
    ];
}
```

## Available settings

* `delimiter`
* `enclosure`
* `escape_character`
* `contiguous`
* `input_encoding`

---

## File: 3.1/imports/custom-formatting-values.md

# Custom Formatting Values

[[toc]]

## Value Binder

By default Laravel Excel uses PhpSpreadsheet's default value binder to intelligently format a cell's value when reading it. You may override this behavior by implementing the `WithCustomValueBinder` concern and the `bindValue` method. Your import class may also extend `DefaultValueBinder` to return the default behavior.

```php
namespace App\Imports;

use PhpOffice\PhpSpreadsheet\Cell\Cell;
use Maatwebsite\Excel\Concerns\ToModel;
use PhpOffice\PhpSpreadsheet\Cell\DataType;
use Maatwebsite\Excel\Concerns\WithCustomValueBinder;
use PhpOffice\PhpSpreadsheet\Cell\DefaultValueBinder;

class UsersImport extends DefaultValueBinder implements WithCustomValueBinder, ToModel
{
    public function bindValue(Cell $cell, $value)
    {
        if (is_numeric($value)) {
            $cell->setValueExplicit($value, DataType::TYPE_NUMERIC);

            return true;
        }

        // else return default behavior
        return parent::bindValue($cell, $value);
    }
}
```

## Available DataTypes

* `PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_STRING`
* `PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_FORMULA`
* `PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_NUMERIC`
* `PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_BOOL`
* `PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_NULL`
* `PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_INLINE`
* `PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_ERROR`

## Disable intelligent formatting

If you want to disable the intelligent formatting of values, you can extend your import class with  `\PhpOffice\PhpSpreadsheet\Cell\StringValueBinder`. In this case all values are passed on as strings.

```php
namespace App\Imports;

use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithCustomValueBinder;

class UsersImport extends \PhpOffice\PhpSpreadsheet\Cell\StringValueBinder implements WithCustomValueBinder, ToModel
{

}
```

## Default Value Binder

If you want to use one value binder for all your imports, you can configure the default value binder in the config.

In `config/excel.php`:

```php
'value_binder' => [
    'default' => Maatwebsite\Excel\DefaultValueBinder::class,
],
```

---

## File: 3.1/imports/extending.md

# Extending

[[toc]]

## Events

The import process has a few events you can leverage to interact with the underlying 
classes to add custom behaviour to the import.

You are able to hook into the parent package by using events.

The events will be activated by adding the `WithEvents` concern. Inside the `registerEvents` method, you 
will have to return an array of events. The key is the Fully Qualified Name (FQN) of the event and the value is a callable event listener.
This can either be a closure, array-callable or invokable class.

```php
namespace App\Imports;

use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Events\BeforeImport;
use Maatwebsite\Excel\Events\AfterImport;
use Maatwebsite\Excel\Events\AfterSheet;
use Maatwebsite\Excel\Events\BeforeSheet;


class UsersImport implements WithEvents
{
    /**
     * @return array
     */
    public function registerEvents(): array
    {
        return [
            // Handle by a closure.
            BeforeImport::class => function(BeforeImport $event) {
                $creator = $event->reader->getProperties()->getCreator();
            },
			
		   
            // Using a class with an __invoke method.
            BeforeSheet::class => new BeforeSheetHandler(),
            
            // Array callable, refering to a static method.
            AfterSheet::class => [self::class, 'afterSheet'],
                        
        ];
    }
    
    public static function afterSheet(AfterSheet $event) 
    {
        //
    }
	
}
```

Do note that using a `Closure` will not be possible in combination with queued imports, as PHP cannot serialize the closure.
In those cases it might be better to use the `RegistersEventListeners` trait.

### Auto register event listeners

By using the `RegistersEventListeners` trait you can auto-register the event listeners,
without the need of using the `registerEvents`. The listener will only be registered if the method is created. 

```php
namespace App\Imports;

use Maatwebsite\Excel\Concerns\Importable;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Concerns\RegistersEventListeners;
use Maatwebsite\Excel\Events\BeforeImport;
use Maatwebsite\Excel\Events\AfterImport;
use Maatwebsite\Excel\Events\BeforeSheet;
use Maatwebsite\Excel\Events\AfterSheet;

class UsersImport implements WithEvents
{
    use Importable, RegistersEventListeners;
    
    public static function beforeImport(BeforeImport $event)
    {
        //
    }
	
    public static function afterImport(AfterImport $event)
    {
        //
    }

    public static function beforeSheet(BeforeSheet $event)
    {
        //
    }

    // From 3.1.50 onwards the methods do not need to be static, allowing use of $this
    public function afterSheet(AfterSheet $event)
    {
        //
    }
	
}
```

### Global event listeners

Event listeners can also be configured globally, if you want to perform the same actions on all exports in your app.
You can add them to e.g. your `AppServiceProvider` in the `register()` method.

```php
Reader::listen(BeforeImport::class, function () {
    //
});

Sheet::listen(AfterImport::class, function () {
    //
});

Sheet::listen(BeforeSheet::class, function () {
    //
});

Sheet::listen(AfterSheet::class, function () {
    //
});


```

### Available events

| Event name | Payload | Explanation |
|---- |----| ----|
|`Maatwebsite\Excel\Events\BeforeImport` | `$event->reader : Reader` | Event gets raised at the start of the process. | 
| `Maatwebsite\Excel\Events\AfterImport` | `$event->reader : Reader` | Event gets raised at the end of the  process. |
| `Maatwebsite\Excel\Events\ImportFailed` | `$event->getException() : Throwable` | Event gets raised on failure of the import process. |
| `Maatwebsite\Excel\Events\BeforeSheet` | `$event->sheet : Sheet` | Event gets raised just after the sheet is created. |
| `Maatwebsite\Excel\Events\AfterSheet` | `$event->sheet : Sheet` | Event gets raised at the end of the sheet process. |
| `Maatwebsite\Excel\Events\AfterChunk` | `$event->sheet : Sheet` | Event gets raised after each chunk from the import file has been processed. Only available with [chunk reading](https://docs.laravel-excel.com/3.1/imports/chunk-reading.html) |
| `Maatwebsite\Excel\Events\AfterBatch` | `$event->manager : ModelManager` | Event gets raised after each batch of model has been flushed to the database. Only available with [batch inserts](https://docs.laravel-excel.com/3.1/imports/batch-inserts.html) |


## Macroable

Both `Reader` and `Sheet` are "macroable" (which means they can easily be extended to fit your needs). 
Both Reader and Sheet have a `->getDelegate()` method which returns the underlying PhpSpreadsheet class. 
This will allow you to add custom macros as shortcuts to PhpSpreadsheet methods that are not available in this package. 

### Reader

```php
use \Maatwebsite\Excel\Reader;

Reader::macro('setCreator', function (Reader $reader, string $creator) {
    $reader->getDelegate()->getProperties()->setCreator($creator);
});
```

### Sheet

```php
use \Maatwebsite\Excel\Sheet;

Sheet::macro('setOrientation', function (Sheet $sheet, $orientation) {
    $sheet->getDelegate()->getPageSetup()->setOrientation($orientation);
});
```

For PhpSpreadsheet methods, please refer to [their documentation](https://phpspreadsheet.readthedocs.io/).

---

## File: 3.1/imports/heading-row.md

# Heading row

[[toc]]

In case your file contains a heading row (a row in which each cells indicates the purpose of that column) and you want to use those names as array keys of each row, you can implement the `WithHeadingRow` concern.

Given we have an Excel file looking like this:

| Name | Email | @ Field |
|---- |----|---|
| Patrick Brouwers | patrick@spartner.nl | Some value |

We can now reference the heading instead of a numeric array key.

```php
namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithHeadingRow;

class UsersImport implements ToModel, WithHeadingRow
{
    public function model(array $row)
    {
        return new User([
            'name'  => $row['name'],
            'email' => $row['email'],
            'at'    => $row['at_field'],
        ]);
    }
}
```

## Heading row on different row

In case your heading row is not on the first row, you can easily specify this in your import class:

```php
namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithHeadingRow;

class UsersImport implements ToModel, WithHeadingRow
{
    public function model(array $row)
    {
        return new User([
            'name'  => $row['name'],
            'email' => $row['email'],
        ]);
    }
    
    public function headingRow(): int
    {
        return 2;
    }
}
```

The 2nd row will now be used as heading row.

## Heading key formatting

By default the heading keys are formatted with the Laravel `str_slug()` helper. E.g. this means all spaces are converted to `_`.

If you want to change this behaviour, you can do so by extending the `HeadingRowFormatter`

### No formatting

If you want no formatting at all, you can use the `none` formatter. The array keys will contain the exact data that was in the heading row.

```php
use Maatwebsite\Excel\Imports\HeadingRowFormatter;

HeadingRowFormatter::default('none');

public function model(array $row)
{
    return new User([
        'name'  => $row['Name'],
        'email' => $row['Email'],
    ]);
}
```

### Custom formatter

You can define a custom formatter with `::extend()` in a service provider.

```php
HeadingRowFormatter::extend('custom', function($value, $key) {
    return 'do-something-custom' . $value; 
    
    // And you can use heading column index.
    // return 'column-' . $key; 
});
```

You can set the custom formatter in `config/excel.php`.

```php
'imports' => [
    'heading_row' => [
        'formatter' => 'custom',
    ],
],
```

Or you can then set this new formatter in a service provider.

```php
HeadingRowFormatter::default('custom');
```

## Importing only the heading row

Sometimes you might want to prefetch the heading row to do some validation. We have an easy shortcut for this: `HeadingRowImport`.

```php
use Maatwebsite\Excel\HeadingRowImport;

class UsersImportController extends Controller 
{
    public function import()
    {
        $headings = (new HeadingRowImport)->toArray('users.xlsx');
    }
}
```

The headings array contains an array of headings per sheet. 

## Grouping values of multiple columns sharing same header

Given we have an Excel file looking like this:

| Name | Email | Options | Options |
|---- |----|---|---|
| Patrick Brouwers | patrick@spartner.nl | Some value | Some other value |

We can group the values of the Options columns in an array using import concern `WithGroupedHeadingRow`. Data returned from row will be in format:
```php
[
    'name'    => 'Patrick Brouwers',
    'email'   => 'patrick@spartner.nl',
    'options' => [
        'Some value',
        'Some other value'
    ]
]
```

---

## File: 3.1/imports/import-formats.md

# Import formats

[[toc]]

By default, the import format is determined by the extension of the file. If you want 
to explicitly configure the import format, you can pass it through as 3rd parameter. 

## XLSX

```php
(new UsersImport)->import('users.xlsx', null, \Maatwebsite\Excel\Excel::XLSX);
```

## CSV

```php
(new UsersImport)->import('users.csv', null, \Maatwebsite\Excel\Excel::CSV);
```

## TSV

```php
(new UsersImport)->import('users.tsv', null, \Maatwebsite\Excel\Excel::TSV);
```

## ODS

```php
(new UsersImport)->import('users.ods', null, \Maatwebsite\Excel\Excel::ODS);
```

## XLS

```php
(new UsersImport)->import('users.xls', null, \Maatwebsite\Excel\Excel::XLS);
```

## SLK

```php
(new UsersImport)->import('users.slk', null, \Maatwebsite\Excel\Excel::SLK);
```

## XML

```php
(new UsersImport)->import('users.xml', null, \Maatwebsite\Excel\Excel::XML);
```

## GNUMERIC

```php
(new UsersImport)->import('users.gnumeric', null, \Maatwebsite\Excel\Excel::GNUMERIC);
```

## HTML

```php
(new UsersImport)->import('users.html', null, \Maatwebsite\Excel\Excel::HTML);
```

---

## File: 3.1/imports/importables.md

# Importables

[[toc]]

In the previous example, we used the `Excel::import` facade to start an import. 

Laravel Excel also provides a `Maatwebsite\Excel\Concerns\Importable` trait, to make import classes importable.

```php
namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\Importable;

class UsersImport implements ToModel
{
    use Importable;

    public function model(array $row)
    {
        return new User([
            'name' => $row[0],
        ]);
    }
}
```

## Importing

We can now import without the need for the facade:

```php
(new UsersImport)->import('users.xlsx', 'local', \Maatwebsite\Excel\Excel::XLSX);
```

## Queuing

Or queue the import:

```php
(new UsersImport)->queue('users.xlsx');
```

## To array

The import can be loaded into an array :

```php
$array = (new UsersImport)->toArray('users.xlsx');
```

## To collection

The import can be loaded into a collection:

```php
$collection = (new UsersImport)->toCollection('users.xlsx');
```

---

## File: 3.1/imports/index.md

---
pageClass: no-toc
---

## :rocket: 5 minute quick start

:muscle: Create an import class in `app/Imports`

You may do this by using the `make:import` command.

```
php artisan make:import UsersImport --model=User
```

The file can be found in `app/Imports`:

::: vue
.
├── app
│   ├── `Imports` 
│   │   ├── UsersImport.php
│ 
└── composer.json
:::

If you prefer to create the import manually, you can create the following in `app/Imports`:

```php
<?php

namespace App\Imports;

use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Maatwebsite\Excel\Concerns\ToModel;

class UsersImport implements ToModel
{
    /**
     * @param array $row
     *
     * @return User|null
     */
    public function model(array $row)
    {
        return new User([
           'name'     => $row[0],
           'email'    => $row[1], 
           'password' => Hash::make($row[2]),
        ]);
    }
}
```

:fire: In your controller you can call this import now:

```php

use App\Imports\UsersImport;
use Maatwebsite\Excel\Facades\Excel;
use App\Http\Controllers\Controller;

class UsersController extends Controller 
{
    public function import() 
    {
        Excel::import(new UsersImport, 'users.xlsx');
        
        return redirect('/')->with('success', 'All good!');
    }
}
```

:page_facing_up: Find the imported users in your database!

---

## File: 3.1/imports/mapped-cells.md

---
pageClass: no-toc
---

# Mapped Cells

In case you have a more custom spreadsheet and only want to access specific **cells**, you can implement the `WithMappedCells` concern.

You might have a speadsheet looking like this:

|name | Patrick Brouwers|
|---- |----|
| email | patrick@spartner.nl |

We can now map `name` to `B1` and `email` to `B2`. The value of those coordinates will then be available under the given array key.

```php
namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithMappedCells;

class UsersImport implements WithMappedCells, ToModel 
{
    public function mapping(): array
    {
        return [
            'name'  => 'B1',
            'email' => 'B2',
        ];
    }
    
    public function model(array $row)
    {
        return new User([
            'name' => $row['name'],
            'email' => $row['email'],
        ]);
    }
}
```

::: warning
This concern is not meant to map **columns**, only specific **cell** reference are allowed.
:::

## Multi-dimensional Mapping

In case you have repeating data in your table, e. g. a spreadsheet looking like this:

| Team 1 | | Team 2| |
|-|-|-|-|
| Max | 2 | Peter | 3 |
| Annie | 0 | Alex | 1 |

you are also able to define cell coordinates in a nested array:

```php
public function mapping(): array
{
    return [
        'team1' => [
            [
                'name' => 'A2',
                'score' => 'B2',
            ],
            [
                'name' => 'A3',
                'score' => 'B3',
            ],
        ],
        'team2' => [
            [
                'name' => 'C2',
                'score' => 'D2',
            ],
            [
                'name' => 'C3',
                'score' => 'D3',
            ],
        ],
    ];
}```

Note that an array of the same form will be returned.

---

## File: 3.1/imports/model.md

# Importing to models

[[toc]]

In case you want to import a workbook to an Eloquent model, you can use the `ToModel` concern. The concern enforces a `model()` method which accepts a model to be returned.

```php
namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\ToModel;

class UsersImport implements ToModel
{
    public function model(array $row)
    {
        return new User([
            'name' => $row[0],
        ]);
    }
}
```

The returned model will be saved for you. Each row will result into (at least) one save and will also fire model events.

:::warning
When using `ToModel` you should never save the model yourself, as that will break the batch insert functionality. If you need this, consider using `OnEachRow`.
:::

## Upserting models

In case you want to upsert models, instead of inserting, you can implement the `WithUpserts` concern. 

```php
class UsersImport implements ToModel, WithUpserts
{
    /**
     * @return string|array
     */
    public function uniqueBy()
    {
        return 'email';
    }
}
```

In the example above, if a user already exists with the same email, the row will be updated instead. Behind the scenes, this feature uses the Laravel `upsert` method and the `uniqueBy` method is used for the second argument of the `upsert` method, which lists the column(s) that uniquely identify records within the associated table.

:::warning
All databases except SQL Server require the `uniqueBy` columns to have a "primary" or "unique" index.
:::

### Upserting with specific columns

By default, `upsert`, in case of updating, will update all columns that match model's attributes. However, if you need to update only specific column(s) during `upsert`, you can also implement the `WithUpsertColumns` concern.

```php
class UsersImport implements ToModel, WithUpserts, WithUpsertColumns
{
    /**
     * @return array
     */
    public function upsertColumns()
    {
        return ['name', 'role'];
    }
}
```

In this example, if a user already exists, only "name" and "role" columns will be updated.

## Skipping duplicate rows

In case you want to skip duplicate models, you can implement the `WithSkipDuplicates` concern. 

```php
class UsersImport implements ToModel, WithSkipDuplicates
{
    // No additional methods are required for this concern
}
```

In the example above, if a user already exists with the same primary or unique key, the row will be ignored. Behind the scenes, this feature uses the Laravel `insertOrIgnore` method to insert records while ignoring duplicates, preventing any errors that would normally occur due to duplicate entries.

## Skipping specific rows

In case you want to skip a row, you can return null. 

```php
public function model(array $row)
{
    if (!isset($row[0])) {
        return null;
    }

    return new User([
        'name' => $row[0],
    ]);
}
```

## Possible column names

In case you want to import rows by several possible column names (using `WithHeadingRow`), you can use null coalescing operator (`??`). If the column with the first name (in example _client_name_) exists and is not NULL, return its value; otherwise look for second possible name (in example _client_) etc.

```php
public function model(array $row)
{
    return new User([
        'name' => $row['client_name'] ?? $row['client'] ?? $row['name'] ?? null
    ]);
}
```

## Cascading relation persistence

By default, ToModel doesn't save relations, you can enable this behaviour for `BelongsTo` and `BelongsToMany` relations by adding the `PersistRelations` concern.

```php
class UsersImport implements ToModel, PersistRelations
{
    public function model(array $row)
    {
        $user = new User([
            'name' => $row[0],
        ]);
        
        // There should be a `public function team(): BelongsTo` relation in the User model.
        $user->setRelation('team', new Team(['name' => $row[1]]));
        
        return $user;
    }
}
```

:::warning
`PersistRelations` doesn't work together with BatchInserts.
:::

## Handling persistence on your own

In some cases you might not have an import in which each row is an Eloquent model and you want more control over what happens. In those cases you can use the `OnEachRow` concern.

```php
namespace App\Imports;

use App\Group;
use App\User;
use Maatwebsite\Excel\Row;
use Maatwebsite\Excel\Concerns\OnEachRow;

class UsersImport implements OnEachRow
{
    public function onRow(Row $row)
    {
        $rowIndex = $row->getIndex();
        $row      = $row->toArray();
        
        $group = Group::firstOrCreate([
            'name' => $row[1],
        ]);
    
        $group->users()->create([
            'name' => $row[0],
        ]);
    }
}
```

:::warning
When using `OnEachRow` you cannot use batch inserts, as the model is already persisted in the `onRow` method.
:::

### Macro's and Mixins

The Eloquent Builder/Model has a macro to directly import an excel to Eloquent rows. When using this, make sure your file has a heading row with the database table column names.

```php
User::query()->import('import-users-with-headings.xlsx');
```

If you want to define the mapping yourself, you can use the `importAs` method.

```php
User::query()->importAs('import-users.xlsx', function (array $row) {
    return [
        'name'     => $row[0],
        'email'    => $row[1],
        'password' => 'secret',
    ];
});
```

---

## File: 3.1/imports/multiple-sheets.md

# Multiple Sheets

[[toc]]

When a file has multiple sheets, each sheet will go through the import object. If you want to handle each sheet separately, you'll need to implement the `WithMultipleSheets` concern.

The `sheets()` method expects an array of sheet import objects to be returned. The order of the sheets is important, the first sheet import object in the array will automatically be linked to the first worksheet in the Excel file.

```php
namespace App\Imports;

use Maatwebsite\Excel\Concerns\WithMultipleSheets;

class UsersImport implements WithMultipleSheets 
{
   
    public function sheets(): array
    {
        return [
            new FirstSheetImport()
        ];
    }
}
```

A sheet import class can import the same concerns as a normal import object. 

```php
namespace App\Imports;

use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\ToCollection;

class FirstSheetImport implements ToCollection
{
    public function collection(Collection $rows)
    {
        //
    }
}
```

## Selecting sheets by worksheet index

If you want more control over which sheets are selected and how they are mapped to specific sheet import objects, you can use the sheet index as key. Sheet indices start at 0.

```php
namespace App\Imports;

use Maatwebsite\Excel\Concerns\WithMultipleSheets;

class UsersImport implements WithMultipleSheets 
{
   
    public function sheets(): array
    {
        return [
            0 => new FirstSheetImport(),
            1 => new SecondSheetImport(),
        ];
    }
}
```

## Selecting sheets by worksheet name

If you only know the name of the worksheet and don't know the sheet index, you can also use the worksheet name as a selector. Put the worksheet name as array index to link that worksheet to your sheet import object.

```php
namespace App\Imports;

use Maatwebsite\Excel\Concerns\WithMultipleSheets;

class UsersImport implements WithMultipleSheets 
{
    public function sheets(): array
    {
        return [
            'Worksheet 1' => new FirstSheetImport(),
            'Worksheet 2' => new SecondSheetImport(),
        ];
    }
}
```

:::warning
Sheets that are not explicitly defined in the `sheet()` method, will be ignored and thus not be imported.
:::

## Skipping unknown sheets

When you have defined a sheet **name** or **index** that does not exist a `Maatwebsite\Excel\Exceptions\SheetNotFoundException` will be thrown.

If you want to ignore when a sheet does not exists, you can use the `Maatwebsite\Excel\Concerns\SkipsUnknownSheets` concern.

```php
namespace App\Imports;

use Maatwebsite\Excel\Concerns\WithMultipleSheets;
use Maatwebsite\Excel\Concerns\SkipsUnknownSheets;

class UsersImport implements WithMultipleSheets, SkipsUnknownSheets
{
    public function sheets(): array
    {
        return [
            'Worksheet 1' => new FirstSheetImport(),
            'Worksheet 2' => new SecondSheetImport(),
        ];
    }
    
    public function onUnknownSheet($sheetName)
    {
        // E.g. you can log that a sheet was not found.
        info("Sheet {$sheetName} was skipped");
    }
}
```

### Skipping only specific sheets

If you want to have 1 optional sheet and still have the others fail, you can also let the Sheet import object implement `SkipsUnknownSheets`.

```php
namespace App\Imports;

use Maatwebsite\Excel\Concerns\SkipsUnknownSheets;

class FirstSheetImport implements SkipsUnknownSheets
{
    public function onUnknownSheet($sheetName)
    {
        // E.g. you can log that a sheet was not found.
        info("Sheet {$sheetName} was skipped");
    }
}
```

Now only `FirstSheetImport` will be skipped if it's not found. Any other defined sheet will be skipped.

## Conditional sheet loading

If you want to indicate per import which sheets should be imported, you can use the `Maatwebsite\Excel\Concerns\WithConditionalSheets` trait.

```php
namespace App\Imports;

use Maatwebsite\Excel\Concerns\WithMultipleSheets;
use Maatwebsite\Excel\Concerns\WithConditionalSheets;

class UsersImport implements WithMultipleSheets 
{
    use WithConditionalSheets;

    public function conditionalSheets(): array
    {
        return [
            'Worksheet 1' => new FirstSheetImport(),
            'Worksheet 2' => new SecondSheetImport(),
            'Worksheet 3' => new ThirdSheetImport(),
        ];
    }
}
```

Now you can use the `onlySheets` method to indicate which sheets should be loaded for this import.

```php
$import = new UsersImport();
$import->onlySheets('Worksheet 1', 'Worksheet 3');

Excel::import($import, 'users.xlsx');
```

## Making calculations work when referencing between sheets

When importing you have to implement the `Maatwebsite\Excel\Concerns\WithCalculatedFormulas` concern for Laravel Excel to calculate values from formulas. However, if one sheet creates a calculation by referencing another sheet, e.g. `=Sheet1!A1`, then you also have to implement the concern `Maatwebsite\Excel\Concerns\HasReferencesToOtherSheets`. An example is given below

```php
namespace App\Imports;

use Maatwebsite\Excel\Concerns\WithMultipleSheets;

class UsersImport implements WithMultipleSheets 
{
    public function sheets(): array
    {
        return [
            new FirstSheetImport(),
            new SecondSheetImport()
        ];
    }
}
```

Then if `SecondSheetImport` contains formulas that reference `FirstSheetImport` then `FirstSheetImport` has to be defined using the `HasReferencesToOtherSheets` concern

```php
namespace App\Imports;

use Maatwebsite\Excel\Concerns\ToArray;
use Maatwebsite\Excel\Concerns\HasReferencesToOtherSheets;

class FirstSheetImport implements ToArray, HasReferencesToOtherSheets
{
    public function array(array: $row)
    {
        
    }
}
```

```php
namespace App\Imports;

use Maatwebsite\Excel\Concerns\WithCalculatedFormulas;

class SecondSheetImport implements ToArray, WithCalculatedFormulas
{
    public function array(array: $row)
    {
        
    }
}
```

---

## File: 3.1/imports/progress-bar.md

---
pageClass: no-toc
---

# Progress Bar

You can implement the `WithProgressBar` concern to display a progress bar when importing an Excel file via the console.

For example, your import class could look like this:

```php
<?php

namespace App\Imports;

use App\User;
use Illuminate\Support\Facades\Hash;
use Maatwebsite\Excel\Concerns\Importable;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithProgressBar;

class UsersImport implements ToModel, WithProgressBar
{
    use Importable;

    public function model(array $row)
    {
        return new User([
            'name'     => $row[0],
            'email'    => $row[1],
            'password' => Hash::make($row[2]),
        ]);
    }
}
```

In your console command, you'd use it as follows:

```php
<?php

namespace App\Console\Commands;

use App\Imports\UsersImport;
use Illuminate\Console\Command;

class ImportExcel extends Command
{
    protected $signature = 'import:excel';

    protected $description = 'Laravel Excel importer';

    public function handle()
    {
        $this->output->title('Starting import');
        (new UsersImport)->withOutput($this->output)->import('users.xlsx');
        $this->output->success('Import successful');
    }
}
```

By calling `php artisan import:excel` on the command line, your import will start.
You should now see the start message, the progress bar and (when completed) the success message.

---

## File: 3.1/imports/queued.md

# Queued reading

[[toc]]

## Notes
:::warning
You currently cannot queue `xls` imports. PhpSpreadsheet's Xls reader contains some non-utf8 characters, which makes it impossible to queue.
:::


## Queuing chunks

When using the `WithChunkReading` concern, you can also choose to execute each chunk into a queue job. You can do so by simply adding the `ShouldQueue` contract.

```php
namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\ToModel;
use Illuminate\Contracts\Queue\ShouldQueue;
use Maatwebsite\Excel\Concerns\WithChunkReading;

class UsersImport implements ToModel, WithChunkReading, ShouldQueue
{
    public function model(array $row)
    {
        return new User([
            'name' => $row[0],
        ]);
    }

    public function chunkSize(): int
    {
        return 1000;
    }
}
```

Each chunk of 1000 rows will now be executed into a queue job.

:::warning
`ShouldQueue` is only supported in combination with `WithChunkReading`.
:::

### Explicit queued imports

You can explicitly queue the import by using `::queueImport`.

```
Excel::queueImport(new UsersImport, 'users.xlsx');
```

When using the `Importable` trait you can use the `queue` method:

```
(new UsersImport)->queue('users.xlsx');
```

:::warning
The `ShouldQueue` is always required.
:::

### Implicit queued imports

When `ShouldQueue` is used, the import will automatically be queued.

```
Excel::import(new UsersImport, 'users.xlsx');
```

## Handling failures in queued imports

When queuing imports you might want a way to handle failed imports. You can do this by using the `ImportFailed` event.

```php
namespace App\Imports;

use App\User;
use App\Notifications\ImportHasFailedNotification;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Events\ImportFailed;
use Illuminate\Contracts\Queue\ShouldQueue;
use Maatwebsite\Excel\Concerns\WithChunkReading;

class UsersImport implements ToModel, WithChunkReading, ShouldQueue, WithEvents
{
    public function __construct(User $importedBy)
    {
        $this->importedBy = $importedBy;
    }

    public function registerEvents(): array
    {
        return [
            ImportFailed::class => function(ImportFailed $event) {
                $this->importedBy->notify(new ImportHasFailedNotification);
            },
        ];
    }
}
```

## Appending jobs

When queuing an import an instance of Laravel's `PendingDispatch` is returned. This means you can chain extra jobs that will be added to the end of the queue and only executed if all import jobs are correctly executed.

```php
(new UsersImport)->queue('users.xlsx')->chain([
    new NotifyUserOfCompletedImport(request()->user()),
]);
```

```php
namespace App\Jobs;

use App\User;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\SerializesModels;

class NotifyUserOfCompletedImport implements ShouldQueue
{
    use Queueable, SerializesModels;

    public $user;

    public function __construct(User $user)
    {
        $this->user = $user;
    }

    public function handle()
    {
        $this->user->notify(new ImportReady());
    }
}
```

## Custom queues

Because `PendingDispatch` is returned, we can also change the queue that should be used.

```php
(new UsersImport)->queue('users.xlsx')->allOnQueue('imports');
```

## Multi-server setup

If you are dealing with a multi-server setup (using e.g. a loadbalancer), you might want to make sure the temporary file is the same for each job. You can achieve this by configuring a remote temporary file in the config.

In `config/excel.php`

```php
'temporary_files' => [
    'remote_disk' => 's3',
],
```

When dealing with a multi server setup as above, it's possible for the clean up that occurs after entire queue has been run to only cleanup the server that the last AfterImportJob runs on. The rest of the server would still have the local temporary file stored on it. In this case your local storage limits can be exceeded and future imports won't be processed. To mitigate this you can set this config value to be true, so that after every queued chunk is processed the local temporary file is deleted on the server that processed it.

```php
'temporary_files' => [
    'force_resync_remote' => true,
],
```


## Job Middleware

If you are using Laravel, [job middleware](https://laravel.com/docs/7.x/queues#job-middleware) can be attached to the import class using the `middleware` method.

```php
namespace App\Imports;

use App\Jobs\Middleware\RateLimited;
use Maatwebsite\Excel\Concerns\Importable;
use Maatwebsite\Excel\Concerns\FromQuery;

class ImportClass implements FromQuery
{
    use Importable;

    public function middleware()
    {
        return [new RateLimited];
    }

    public function retryUntil()
    {
        return now()->addSeconds(5);
    }

    public function query()
    {
        // ...
    }
}
```

---

## File: 3.1/imports/start-row.md

# Start row

[[toc]]

If you want to skip a certain number of rows during an import, you can specify the starting row by implementing the `WithStartRow` concern.

```php
namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithStartRow;

class UsersImport implements ToModel, WithStartRow
{
    public function model(array $row)
    {
        return new User([
            'name' => $row[0],
        ]);
    }

    public function startRow(): int
    {
        return 2;
    }
}
```

---

## File: 3.1/imports/testing.md

# Testing

[[toc]]

The Excel facade can be used to swap the importer to a fake.

## Testing imports

```php
/**
* @test
*/
public function user_can_import_users() 
{
    Excel::fake();
    
    $this->actingAs($this->givenUser())
         ->get('/users/import/xlsx');

    Excel::assertImported('filename.xlsx', 'diskName');
    
    Excel::assertImported('filename.xlsx', 'diskName', function(UsersImport $import) {
        return true;
    });
    
    // When passing the callback as 2nd param, the disk will be the default disk.
    Excel::assertImported('filename.xlsx', function(UsersImport $import) {
        return true;
    });
}
```

## Testing queuing imports

```php
/**
* @test
*/
public function user_can_queue_the_users_import() 
{
    Excel::fake();

    $this->actingAs($this->givenUser())
         ->get('/users/queue/xlsx');

    Excel::assertQueued('filename.xlsx', 'diskName');
    
    Excel::assertQueued('filename.xlsx', 'diskName', function(UsersImport $import) {
        return true;
    });
    
    // When passing the callback as 2nd param, the disk will be the default disk.
    Excel::assertQueued('filename.xlsx', function(UsersImport $import) {
        return true;
    });
}
```

## Testing imports with dynamic file name/path

If you have dynamic naming for files or paths, you can use a regular expression to represent those while testing:

```php
/**
* @test
*/
public function user_can_import_users() 
{
    Excel::fake();
    
    $this->actingAs($this->givenUser())
         ->get('/users/import/xlsx');
    
    // Tells the mock to use regular expressions
    Excel::matchByRegex(); 
    // For a given dynamic named file 'dynamic_1234_filename.xlsx'
    Excel::assertImported('/\w{7}_\d{4}\_\w{8}\.xlsx/', 'diskName');
}
```
Please note that your expression must match only one file/path. If more than one match is found, the test will fail.

---

## File: 3.1/imports/validation.md

# Row Validation

[[toc]]

Sometimes you might want to validate each row before it's inserted into the database. 
By implementing the `WithValidation` concern, you can indicate the rules that each row need to adhere to.

The `rules()` method, expects an array with Laravel Validation rules to be returned. 

```php
<?php

namespace App\Imports;

use App\User;
use Illuminate\Validation\Rule;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\Importable;
use Maatwebsite\Excel\Concerns\WithValidation;

class UsersImport implements ToModel, WithValidation
{
    use Importable;

    public function model(array $row)
    {
        return new User([
            'name'     => $row[0],
            'email'    => $row[1],
            'password' => 'secret',
        ]);
    }

    public function rules(): array
    {
        return [
            '1' => Rule::in(['patrick@spartner.nl']),

             // Above is alias for as it always validates in batches
             '*.1' => Rule::in(['patrick@spartner.nl']),
             
             // Can also use callback validation rules
             '0' => function($attribute, $value, $onFailure) {
                  if ($value !== 'Patrick Brouwers') {
                       $onFailure('Name is not Patrick Brouwers');
                  }
              }
        ];
    }
}
```

## Validating with a heading row

When using the `WithHeadingRow` concern, you can use the heading row name as rule attribute.

```php
<?php

namespace App\Imports;

use App\User;
use Illuminate\Validation\Rule;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\Importable;
use Maatwebsite\Excel\Concerns\WithValidation;
use Maatwebsite\Excel\Concerns\WithHeadingRow;

class UsersImport implements ToModel, WithValidation, WithHeadingRow
{
    use Importable;

    public function model(array $row)
    {
        return new User([
            'name'     => $row['name'],
            'email'    => $row['email'],
            'password' => 'secret',
        ]);
    }

    public function rules(): array
    {
        return [
            'email' => Rule::in(['patrick@spartner.nl']),

             // Above is alias for as it always validates in batches
             '*.email' => Rule::in(['patrick@spartner.nl']),
        ];
    }
}
```

If your validation rules reference other field names, as in the `different`, `lt`, `lte`, `gt`, `gte`, and `same` rules, the field name must be prefixed with `*.` as in the example below, because validation is done in batches.

```php
public function rules(): array
{
    return [
        'maximum' => 'gte:*.minimum',
    ];
}
```

## Custom validation messages

By adding `customValidationMessages()` method to your import, you can specify custom messages for each failure.


```php
/**
* @return array
*/
public function rules(): array
{
    return [
        '1' => Rule::in(['patrick@spartner.nl']),
    ];
}

/**
 * @return array
 */
public function customValidationMessages()
{
    return [
        '1.in' => 'Custom message for :attribute.',
    ];
}
```

## Custom validation attributes

By adding `customValidationAttributes()` method to your import, you can specify custom attribute names for each column.

```php
/**
* @return array
*/
public function rules(): array
{
    return [
        '1' => Rule::in(['patrick@spartner.nl']),
    ];
}

/**
 * @return array
 */
public function customValidationAttributes()
{
    return ['1' => 'email'];
}
```

## Handling validation errors

### Database transactions

The entire import is automatically wrapped in a **database transaction**, that means that *every* error will rollback the entire import (even when using batch inserts).

#### Disable transactions

If you prefer to not have any database transactions around your import (or chunk import), you can change which transaction handler you want to use in the config:

In `config/excel.php`:

```php
'transactions' => [
    'handler' => 'db',
],
```

Supported handlers are currently: `null` or `db`.

#### Custom transaction handlers

If you want a custom transaction handler (for e.g. a MongoDB database), you can add your own handler:

```php
$this->app->make(\Maatwebsite\Excel\Transactions\TransactionManager::class)->extend('your_handler', function() {
    return new YourTransactionHandler();
});
```

The Handler should implement `Maatwebsite\Excel\Transactions\TransactionHandler`.

### Gathering all failures at the end

You can gather all validation failures at the end of the import, when used in conjunction with Batch Inserts. You can try-catch the `ValidationException`. On this exception you can get all failures.

Each failure is an instance of `Maatwebsite\Excel\Validators\Failure`. The `Failure` holds information about which row, which column and what the validation errors are for that cell.

```php
try {
    $import->import('import-users.xlsx');
} catch (\Maatwebsite\Excel\Validators\ValidationException $e) {
     $failures = $e->failures();
     
     foreach ($failures as $failure) {
         $failure->row(); // row that went wrong
         $failure->attribute(); // either heading key (if using heading row concern) or column index
         $failure->errors(); // Actual error messages from Laravel validator
         $failure->values(); // The values of the row that has failed.
     }
}
```

### Skipping failures

Sometimes you might want to skip failures. By using the `SkipsOnFailure` concern, you get control over what happens the moment a validation failure happens. 
When using `SkipsOnFailure` the entire import will **not** be rollbacked when a failure occurs.

```php
<?php

namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Validators\Failure;
use Maatwebsite\Excel\Concerns\Importable;
use Maatwebsite\Excel\Concerns\SkipsOnFailure;
use Maatwebsite\Excel\Concerns\WithValidation;

class UsersImport implements ToModel, WithValidation, SkipsOnFailure
{
    use Importable;

    /**
     * @param Failure[] $failures
     */
    public function onFailure(Failure ...$failures)
    {
        // Handle the failures how you'd like.
    }
}
```

If you automatically want to skip all failed rows and collect the failures at the end of the import, you can use the `Maatwebsite\Excel\Concerns\SkipsFailures` trait.

```php
<?php

namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Validators\Failure;
use Maatwebsite\Excel\Concerns\Importable;
use Maatwebsite\Excel\Concerns\SkipsOnFailure;
use Maatwebsite\Excel\Concerns\WithValidation;
use Maatwebsite\Excel\Concerns\SkipsFailures;

class UsersImport implements ToModel, WithValidation, SkipsOnFailure
{
    use Importable, SkipsFailures;
}
```

Every row that has failed the validation rules, will have been skipped. We can now collect all the failures at the end:

```php
$import = new UsersImport();
$import->import('users.xlsx');

foreach ($import->failures() as $failure) {
     $failure->row(); // row that went wrong
     $failure->attribute(); // either heading key (if using heading row concern) or column index
     $failure->errors(); // Actual error messages from Laravel validator
     $failure->values(); // The values of the row that has failed.
}
```

## Skipping empty rows

Sometimes you might want to skip empty rows, for example when using the `required` validation rule. By using the `SkipsEmptyRows` concern, empty rows will get skipped during both validation **and the import**.

```php
<?php

namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\Importable;
use Maatwebsite\Excel\Concerns\SkipsEmptyRows;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Maatwebsite\Excel\Concerns\WithValidation;

class UsersImport implements ToModel, SkipsEmptyRows, WithHeadingRow, WithValidation
{
    use Importable;
    
    public function rules(): array
    {
        return [
            'name' => [
                'required',
                'string',
            ],
        ];
    }
}
```
## Extend empty rows logic

Along with `SkipsEmptyRows` you can have your own logic to skip rows by having `isEmptyWhen` in the importer

```php
<?php

namespace App\Imports;

use Maatwebsite\Excel\Concerns\Importable;
use Maatwebsite\Excel\Concerns\ToArray;

class UsersImport implements ToArray,
{
    use Importable;
    
    public function isEmptyWhen(array $row): bool
    {
        return $row['name'] === 'John Doe';
    }
}
```

### Skipping errors

Sometimes you might want to skip **all** errors, e.g. duplicate database records. By using the `SkipsOnError` concern, you get control over what happens the moment a model import fails. 
When using `SkipsOnError` the entire import will **not** be rollbacked when an database exception occurs.

```php
<?php

namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\Importable;
use Maatwebsite\Excel\Concerns\SkipsOnError;
use Maatwebsite\Excel\Concerns\WithValidation;

class UsersImport implements ToModel, WithValidation, SkipsOnError
{
    use Importable;

    /**
     * @param \Throwable $e
     */
    public function onError(\Throwable $e)
    {
        // Handle the exception how you'd like.
    }
}
```

If you automatically want to skip all exceptions and collect them at the end of the import, you can use the `Maatwebsite\Excel\Concerns\SkipsErrors` trait.

```php
<?php

namespace App\Imports;

use App\User;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Validators\Failure;
use Maatwebsite\Excel\Concerns\Importable;
use Maatwebsite\Excel\Concerns\SkipsOnError;
use Maatwebsite\Excel\Concerns\WithValidation;
use Maatwebsite\Excel\Concerns\SkipsErrors;

class UsersImport implements ToModel, WithValidation, SkipsOnError
{
    use Importable, SkipsErrors;
}
```

Every row that has errored, will have been skipped. We can now collect all the errors at the end:

```php
$import = new UsersImport();
$import->import('users.xlsx');

dd($import->errors());
```

## Row Validation without ToModel

If you are not using the `ToModel` concern, you can very easily do row validation by just using the Laravel validator.

```php
<?php

namespace App\Imports;

use App\User;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Validator;
use Maatwebsite\Excel\Concerns\ToCollection;

class UsersImport implements ToCollection
{
    public function collection(Collection $rows)
    {
         Validator::make($rows->toArray(), [
             '*.0' => 'required',
         ])->validate();

        foreach ($rows as $row) {
            User::create([
                'name' => $row[0],
            ]);
        }
    }
}
```

## Prepare data for validation
Sometimes data may not pass validation directly, but still be valid. When this happens you may want to tweak the data slightly before sending it to the validator, to do this you may add a `prepareForValidation` method on your import, this method receives row data as well as the row number and should return the manipulated row data.

```php
class UsersImport implements WithValidation
{
    public function prepareForValidation($data, $index)
    {
        $data['email'] = $data['email'] ?? $this->myOtherWayOfFindingTheEmail($data);
        
        return $data;
    }
}
```

## Configuring the validator
If you want to add conditional validation or complex validation that cannot be expressed through rules you can configure the validator similar to how you would do this with a [Form request](https://laravel.com/docs/master/validation#form-request-validation)

:::tip Manual validation
You can use `$validator->getData()` to get access to the data under validation
:::

```php
class UsersImport implements WithValidation
{
    public function withValidator($validator)
    {
        $validator->after(function ($validator) {
            if ($this->somethingElseIsInvalid()) {
                $validator->errors()->add('field', 'Something is wrong with this field!');
            }
        });

        // or...

        $validator->sometimes('*.email', 'required', $this->someConditionalRequirement());
    }
}
```

:::tip Validation rules
For a list of all validation rules, please refer to the [Laravel document](https://laravel.com/docs/master/validation#available-validation-rules).
:::

:::tip Validating Across Multiple Rows 
Validation rules that check multiple rows (such as `distinct`) will work only when using `WithBatchInserts` or `ToCollection` concerns.
:::

---

## File: 4.x/index.md

<meta http-equiv="refresh" content="0;url=/4.x/getting-started/" />

---

## File: 4.x/architecture/concerns.md

# Concerns

[[toc]]

Most of the export/import configuration is done by using **Concerns**. 

## Contracts

Concerns are basically just simple interfaces. Implementing them will make the object adhere to a 
certain contract. This contract can request specific methods that e.g. data can be passed through.

For instance, the `FromCollection` requests the Export object to implement a `collection` method, that needs to return a `Collection` instance.

```php
namespace App\Exports;

use App\User;
use Maatwebsite\Excel\Concerns\FromCollection;

class UsersExport implements FromCollection
{
    public function collection(): Collection
    {
        return User::all();
    }
}
```

## Pointer interface

In other cases it might not ask for any methods to be implemented, but merely functions as a pointer interface.

For instance, the `ShouldAutoSize` concern doesn't pass on any specific information, but does tell the Export process that the columns need to be automatically sized.

```php
namespace App\Exports;

use App\User;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;

class UsersExport implements ShouldAutoSize
{

}
```