genesis-brain/laravel-excel-import-analysis

A reusable Excel import analysis framework for Laravel with rules, severity levels, analysis DTOs, and modular import behavior.

Installs: 66

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/genesis-brain/laravel-excel-import-analysis

v1.0.4 2025-11-29 09:56 UTC

This package is auto-updated.

Last update: 2025-12-12 15:15:15 UTC


README

A reusable, rule-based Excel import analysis framework for Laravel. It provides structured per-row analysis, severity levels, contextual DTOs, and a clean import architecture that integrates seamlessly with Laravel Excel.

This package is designed to help you build robust, extensible, and maintainable Excel import pipelines in your Laravel applications.

✨ Features

  • 🧩 Rule-based per-row validation
  • ⚠️ Built-in severity levels (INFO, WARNING, ERROR, CRITICAL)
  • πŸ“„ Rich DTOs (messages, codes, row/column/cell, context)
  • πŸ— Pluggable rules via repository
  • ♻️ Reusable import architecture using traits & contracts
  • πŸ“š Clean interfaces and abstract base classes
  • πŸ”Œ Fully compatible with Maatwebsite/Laravel-Excel

πŸ“¦ Installation

composer require genesis-brain/laravel-excel-import-analysis

Requires:

  • PHP >= 8.2
  • Laravel >= 10
  • maatwebsite/excel >= 3.1

πŸš€ Basic Usage

1. Create an Import

use Gbrain\ExcelImports\Concerns\AnalyzesData\AnalyzesData;
use Gbrain\ExcelImports\Contracts\ExcelImportAnalyzesDataInterface;
use Gbrain\ExcelImports\Enums\ExcelImportAnalysisLevelEnum;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\WithHeadingRow;

class ProductsImport implements ExcelImportAnalyzesDataInterface, WithHeadingRow
{
    use AnalyzesData;

    /**
     * Business logic that runs once a row has passed validation.
     */
    protected function handleRowImport(Collection $row): void
    {
        // Persist the row, dispatch a job, etc.
    }

    /**
     * Register the analysis rules for this import.
     *
     * @return list<class-string<\Gbrain\ExcelImports\Contracts\ExcelImportAnalysisRuleInterface>>
     */
    public function getRulesCollection(): iterable
    {
        return [
            \Gbrain\ExcelImports\Abstracts\Analysis\ExampleRules\TitleIsRequiredImportRule::class,
            // Your custom rules...
        ];
    }

    /**
     * Minimal analysis level that should be considered an error for this import.
     */
    public function getMinimalReportLevel(): ExcelImportAnalysisLevelEnum
    {
        return ExcelImportAnalysisLevelEnum::WARNING;
    }
}

2. Run the Import

use Maatwebsite\Excel\Facades\Excel;

Excel::import(new ProductsImport(), 'products.xlsx');

If any analysis results are produced at or below the configured minimal level, an Gbrain\ExcelImports\Exceptions\ExcelImportNotPassedRulesValidation exception will be thrown. You can catch it to surface errors to users or logs.

try {
    Excel::import(new ProductsImport(), 'products.xlsx');
} catch (\Gbrain\ExcelImports\Exceptions\ExcelImportNotPassedRulesValidation $e) {
    foreach ($e->getAnalysisCollection() as $result) {
        // $result is an ExcelImportAnalysisResultDto
        // e.g. $result->message, $result->uniqueCode, $result->rowIndex, etc.
    }
}

πŸ” Controlling Analysis Execution: withAnalysis() and withoutAnalysis()

The AnalyzesData trait provides two important methods to control when analysis rules run during an import:

### βœ… withAnalysis(bool $withoutImport = false) (default behaviour)

Enables analysis and allows you to decide whether the import should also run.

Since $onlyAnalysis is false by default, calling withAnalysis() without arguments means:

➑ Analysis runs ➑ Import also runs (if analysis passes)

You may optionally pass a boolean:

$import->withAnalysis(false); // analysis + import
$import->withAnalysis(true);  // analysis only (no import)
  • withAnalysis(false) β†’ normal mode: validate rows and import if valid
  • withAnalysis(true) β†’ analysis-only mode: validate rows, skip import entirely

Example (normal mode):

Excel::import((new ProductsImport())->withAnalysis(), 'products.xlsx'); // default state
  • Each row is validated using your registered rules
  • All analysis results are collected
  • If any rule produces a result at or below the minimal report level, an exception is thrown

### β›” withoutAnalysis()

Disables all rule checks.

Use this when you want to:

  • Import data without validation
  • Re-run an import using only the business logic (handleRowImport())
  • Bypass rules temporarily (e.g. admin override)

Example:

Excel::import((new ProductsImport())->withoutAnalysis(), 'products.xlsx');

### πŸ”„ How it works internally

withAnalysis() and withoutAnalysis() work together using two internal flags:

  • $analyzeBeforeHandle β€” whether rules should run at all
  • $onlyAnalysis β€” whether only rules should run (skipping import)

According to the current implementation:

βœ” Default state

  • $analyzeBeforeHandle = true
  • $onlyAnalysis = false

So calling withAnalysis() with no arguments:

  • enables analysis
  • does NOT skip import

βœ” Truth table

Method call $analyzeBeforeHandle $onlyAnalysis Effect
withAnalysis() true false Run analysis and then import
withAnalysis(false) true false Same as above
withAnalysis(true) true true Run analysis only, no import
withoutAnalysis() false false Skip analysis, run import only

βœ” What actually happens

  • If analysis is enabled ($analyzeBeforeHandle = true), rules run on each row.
  • If minimal report level is breached, an exception is thrown.
  • If only analysis is enabled ($onlyAnalysis = true), the import is skipped entirely.
  • If withoutAnalysis() is called, rules are skipped and only import logic runs.

Summary

  • withAnalysis() β†’ analysis + import (default)
  • withAnalysis(true) β†’ analysis only
  • withAnalysis(false) β†’ analysis + import
  • withoutAnalysis() β†’ import only

This gives you full control over whether to run validation-only scans, full validated imports, or unvalidated imports.**, without changing your import class.

πŸ§ͺ Writing Custom Rules

Rules extend the abstract ExcelImportAnalysisRule and return an ExcelImportAnalysisResultDto when the rule fails.

use Gbrain\ExcelImports\Abstracts\Analysis\ExcelImportAnalysisRule;
use Gbrain\ExcelImports\Dtos\ExcelImportAnalysisResultDto;
use Illuminate\Support\Collection;

class PositiveQuantityRule extends ExcelImportAnalysisRule
{
    protected function getRowAnalysis(Collection $row, int $rowIndex): ?ExcelImportAnalysisResultDto
    {
        $qty = (int) ($row->get('quantity') ?? 0);

        if ($qty <= 0) {
            return ExcelImportAnalysisResultDto::error(
                message: 'Quantity must be positive',
                uniqueCode: 'qty-negative',
                cell: 'B'.($rowIndex + 1),
                columnName: 'Quantity',
                context: ['value' => $qty],
            );
        }

        return null;
    }
}

Then register it in your import’s getRulesCollection() method.

πŸ“Š Severity Levels

The package ships with a built-in severity enum:

use Gbrain\ExcelImports\Enums\ExcelImportAnalysisLevelEnum;

ExcelImportAnalysisLevelEnum::INFO;
ExcelImportAnalysisLevelEnum::WARNING;
ExcelImportAnalysisLevelEnum::ERROR;
ExcelImportAnalysisLevelEnum::CRITICAL;

Levels are comparable using helper methods:

$level->gte(ExcelImportAnalysisLevelEnum::WARNING);
$level->lt(ExcelImportAnalysisLevelEnum::ERROR);

Internally, comparison is driven by PHP 8 attributes (ComparableValue) attached to each enum case.

🧱 Architecture Overview

  • Contracts β€” describe import, rule, and repository responsibilities
  • Abstracts β€” provide base behavior (rules, repository)
  • Concerns β€” traits that orchestrate analysis (AnalyzesData)
  • Enums β€” severity levels, with comparable semantics
  • DTOs β€” carry structured analysis results
  • Exceptions β€” encapsulate failed analysis and structured context

πŸ§ͺ Testing

This package is designed to be test-friendly. Example Pest tests:

use Gbrain\ExcelImports\Abstracts\Analysis\ExampleRules\TitleIsRequiredImportRule;
use Gbrain\ExcelImports\Dtos\ExcelImportAnalysisResultDto;

test('TitleIsRequiredImportRule flags missing title', function () {
    $rule = new TitleIsRequiredImportRule();

    $result = $rule->validateRow(collect(['title' => null]), 0);

    expect($result)->toBeInstanceOf(ExcelImportAnalysisResultDto::class)
        ->and($result->uniqueCode)->toBe('no-title')
        ->and($result->level->name)->toBe('CRITICAL');
});

Run tests with:

vendor/bin/pest

πŸ“„ License

MIT