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
Requires
- php: >=8.3
- laravel/framework: ^10.0|^11.0
- maatwebsite/excel: ^3.1
Requires (Dev)
- laravel/pint: ^1.13
- orchestra/testbench: ^8.0 || ^9.0
- pestphp/pest-plugin-laravel: @stable
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 validwithAnalysis(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