DEV Community

Cover image for How to Use Maatwebsite Excel in Laravel for Importing & Exporting Data
Snehal Rajeev Moon
Snehal Rajeev Moon

Posted on

How to Use Maatwebsite Excel in Laravel for Importing & Exporting Data

Hello Artisan,

This blog post will show how to implement import and export functionality in laravel applications using Maatwebsite Excel package.
So let's get started with an introduction.

Introduction

In Laravel, handling Excel files efficiently is crucial for data management tasks such as importing bulk records, generating reports, and exporting data. The Maatwebsite Excel package simplifies working with Excel files in Laravel applications. In this guide, we'll explore how to use this package to import and export data in Excel, with a small product-management application. Where we will have a list of products and each product belongs to a category.

First, we will set up our laravel project, and add products and categories, with the help of a seeder which gives us some test data.

Step 1: Install and setup laravel project

laravel new product-management
Enter fullscreen mode Exit fullscreen mode

During installation, you will be prompted with questions to set up your application. You can choose the options that best suit your preferences.
I have selected no blade file, pest for testing, and MySQL database.

Step 2: Create model, migration, factory, and seeder for Category

php artisan make:model Category -msf
Enter fullscreen mode Exit fullscreen mode

Step 3: Create a model, migration, factory, seeder, and Controller for the Product.

php artisan make:model Product -mcsf
Enter fullscreen mode Exit fullscreen mode

Step 4: Next step is to define migration and the relationship between Category and Products.

  • Open a migration file for Category and add this code
Schema::create('categories', function (Blueprint $table) {
            $table->id();
            $table->string('name')->unique();
            $table->text('description')->nullable();
            $table->timestamps();
        });
Enter fullscreen mode Exit fullscreen mode
  • Open a migration file for Product and add the below code
 Schema::create('products', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->text('description')->nullable();
            $table->decimal('price', 10, 2);
            $table->unsignedBigInteger('category_id');
            $table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade');
            $table->timestamps();
        });
Enter fullscreen mode Exit fullscreen mode

Now open a model files and add the following code:

Product.php


    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = ['name', 'description', 'price', 'category_id'];

    /**
     * Get list of categories.
     *
     * @return BelongsTo
     */
    public function category(): BelongsTo
    {
        return $this->belongsTo(Category::class);
    }
Enter fullscreen mode Exit fullscreen mode

Category.php

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = ['name', 'description'];

    /**
     * Get list of products.
     *
     * @return HasMany
     */
    public function products(): HasMany
    {
        return $this->hasMany(Product::class);
    }
Enter fullscreen mode Exit fullscreen mode

Step 5: Now we will create and add test data with the help of the seeder.

  • CategoryFactory.php
   return [
            'name' => $this->faker->word,
            'description' => $this->faker->sentence,
        ];
Enter fullscreen mode Exit fullscreen mode
  • ProductFactory.php
return [
            'name' => $this->faker->word,
            'description' => $this->faker->sentence,
            'price' => $this->faker->randomFloat(2, 5, 100),
            'category_id' => Category::factory(),
        ];
Enter fullscreen mode Exit fullscreen mode
  • CategorySeeder.php
Category::factory(5)->create(); // Creates 5 random categories
Enter fullscreen mode Exit fullscreen mode
  • ProductSeeder.php
Category::all()->each(function ($category) {
            Product::factory(5)->create(['category_id' => $category->id]); // Each category gets 5 products
        });
Enter fullscreen mode Exit fullscreen mode

Now add these seeder files to DatabaseSeeder.php to generate test data in our database within the run method.

 $this->call([
            CategorySeeder::class,
            ProductSeeder::class,
        ]);
Enter fullscreen mode Exit fullscreen mode

Step 6: Now run the migration command

php artisan migrate --seed
Enter fullscreen mode Exit fullscreen mode

Our basic and required setup is done, now we will start with how to use Maatwebsite

Step 7: Install Maatwebsite Excel Package

To install the package, run the following command:

composer require maatwebsite/excel
Enter fullscreen mode Exit fullscreen mode

After installation, the package automatically registers the service provider and facade. Now we need to publish its configuration file.

php artisan vendor:publish --provider="Maatwebsite\Excel\ExcelServiceProvider"
Enter fullscreen mode Exit fullscreen mode

Step 8: Creating an Import Class

php artisan make:import ProductsImport --model=Product
Enter fullscreen mode Exit fullscreen mode

This will create app/Imports/ProductsImport.php. Modify it as follows:

namespace App\Imports;

use App\Models\Product;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithHeadingRow;

class ProductsImport implements ToModel, WithHeadingRow
{
    /**
     * @param array $row
     *
     * @return \Illuminate\Database\Eloquent\Product|null
     */
    public function model(array $row)
    {
        // Find category by id
        $category = \App\Models\Category::where('id', $row['category_id'])->first();

        if (!$category) {
            throw new \Exception('Invalid category: ' . $row['category_id']);
        }

        return new Product([
            'name'  => $row['name'],
            'description' => $row['description'],
            'price' => is_numeric($row['price']) ? floatval($row['price']) : 0,
            'category_id' => $category->id,
        ]);
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 9: Creating an Export Class

To export data as an Excel file, create an export class:

php artisan make:export ProductsExport --model=Product
Enter fullscreen mode Exit fullscreen mode

Modify app/Exports/ProductsExport.php:

namespace App\Exports;

use App\Models\Product;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithEvents;

class ProductsExport implements FromCollection, WithHeadings, WithEvents
{
    /**
     * @return \Illuminate\Support\Collection
     */
    public function collection()
    {
        $products = collect();

        // Retrieve all products and include the related category name using eager loading
        // Chunk the results to avoid memory issues as the dataset grows
        Product::query()->with('category')->chunk(100, function ($chunk) use ($products) {
            $chunk->each(function ($product) use ($products) {
                $products->push([
                    'ID' => $product->id,
                    'Name' => $product->name,
                    'Description' => $product->description,
                    'Price' => $product->price,
                    'Category' => $product->category->name,
                    'Created At' => $product->created_at->format('Y-m-d H:i:s'),
                    'Updated At' => $product->updated_at->format('Y-m-d H:i:s'),
                ]);
            });
        });

        return $products;
    }

    /**
     * Add custom headers
     *
     * @return array
     */
    public function headings(): array
    {
        return [
            'ID',
            'Name',
            'Description',
            'Price',
            'Category',
            'Created At',
            'Updated At',
        ];
    }

    /**
     * Apply styles to the headings
     *
     * @return array
     */
    public function registerEvents(): array
    {
        return [
            \Maatwebsite\Excel\Events\AfterSheet::class => function (\Maatwebsite\Excel\Events\AfterSheet $event) {
                $headingCount = count($this->headings());
                $columnRange = 'A1:' . \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex($headingCount) . '1';
                $event->sheet->getDelegate()->getStyle($columnRange)->getFont()->setBold(true);
            },
        ];
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 10: Add export and import methods in a controller

class ProductController extends Controller
{
    public function index()
    {
        $products = Product::all();
        return view('products.index', compact('products'));
    }

    /**
     * Export products to excel file
     *
     * @return \Illuminate\Http\Response
     */
    public function export()
    {
        return Excel::download(new ProductsExport, 'products.xlsx');
    }

    /**
     * Import products from excel file
     *
     * @param Request $request
     * @return \Illuminate\Http\RedirectResponse
     */
    public function import(Request $request)
    {
        $request->validate(['file' => 'required|mimes:xlsx,csv']);

        Excel::import(new ProductsImport, $request->file('file'));

        return back()->with('success', 'Products Imported Successfully!');
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 11: Define Routes

In routes/web.php, add routes for importing and exporting:

Route::get('/products', [ProductController::class, 'index'])->name('products.index');
Route::post('/products/import-users', [ProductController::class, 'import'])->name('products.import');
Route::get('/products/export-products', [ProductController::class, 'export'])->name('products.export');

Enter fullscreen mode Exit fullscreen mode

Step 12: Create a simple blade form
In your Blade file (resources/views/products/index.blade.php), add:

<!DOCTYPE html>
<html lang="en">

    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Product Import & Export</title>
        <script src="https://cdn.tailwindcss.com"></script>
    </head>

    <body class="bg-gray-100 flex items-center justify-center h-screen">

        <div class="bg-white p-8 rounded-lg shadow-md w-96">
            <h2 class="text-xl font-semibold text-gray-700 text-center mb-4">Import & Export Products</h2>

            <!-- Import Form -->
            <form action="{{ route('products.import') }}" method="POST" enctype="multipart/form-data" class="space-y-4">
                @csrf
                <label class="block">
                    <span class="text-gray-700">Upload File</span>
                    <input type="file" name="file" required
                        class="mt-2 block w-full px-3 py-2 border rounded-lg text-gray-700 bg-gray-50">
                </label>

                <button type="submit"
                    class="w-full bg-blue-600 text-white py-2 rounded-lg hover:bg-blue-700 transition">
                    Import Products
                </button>
            </form>

            <!-- Export Button -->
            <div class="mt-4 text-center">
                <a href="{{ route('products.export') }}" class="text-blue-600 hover:underline">Export Products</a>
            </div>
        </div>

    </body>

</html>
Enter fullscreen mode Exit fullscreen mode

Conclusion

Using Maatwebsite Excel in Laravel simplifies Excel imports and exports. Whether you're handling large datasets or need quick CSV/Excel downloads, this package is an essential tool for Laravel developers. Try it out in your Laravel projects and streamline your data operations!

You can view the code on GitHub.

Happy Reading
Happy Coding
🦄 ❤️

Top comments (0)