PHPackages                             deep-shah/omniporter - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. deep-shah/omniporter

ActiveLibrary[Database &amp; ORM](/categories/database)

deep-shah/omniporter
====================

Unified CSV/Excel Import/Export for Modular Laravel

v1.0.1(1mo ago)04MITPHPPHP ^8.2CI passing

Since Apr 27Pushed 2d agoCompare

[ Source](https://github.com/deep-0127/OmniPorter)[ Packagist](https://packagist.org/packages/deep-shah/omniporter)[ Docs](https://github.com/deep-shah/omniporter)[ RSS](/packages/deep-shah-omniporter/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (2)Dependencies (12)Versions (3)Used By (0)

🚀 Unlocking Data Mastery with **OmniPorter**
============================================

[](#-unlocking-data-mastery-with-omniporter)

### *The Ultimate Laravel Import/Export Framework*

[](#the-ultimate-laravel-importexport-framework)

[![Latest Version on Packagist](https://camo.githubusercontent.com/d7ebc28ddf7719ac220b00d9bac69b25909d863cf90c90a3e4f716d39b4bc473/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f646565702d736861682f6f6d6e69706f727465722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/deep-shah/omniporter)[![GitHub Tests Action Status](https://camo.githubusercontent.com/fc8b41da32946b2e51866572e4092784909d6fb025adc98b02b0efdce706d2eb/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f646565702d303132372f4f6d6e69506f727465722f74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/deep-0127/OmniPorter/actions?query=workflow%3ATests+branch%3Amain)[![Total Downloads](https://camo.githubusercontent.com/5864766b5e018f3ae36a3268a9e982f081b3466a91be7421f090b19736d2b300/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f646565702d736861682f6f6d6e69706f727465722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/deep-shah/omniporter)[![License](https://camo.githubusercontent.com/ce907e5d0868942a21d01bdddab3160dd968164e0eaff6139d20b0c549f5923f/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f646565702d736861682f6f6d6e69706f727465722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/deep-shah/omniporter)

Tired of manual data entry nightmares and clunky import/export processes? Dream of a world where your application effortlessly ingests and disgorges vast datasets with bulletproof validation and intelligent relationship management?

**Your quest ends here—with OmniPorter.**

OmniPorter is a **meticulously engineered, battle-tested solution** that injects your Eloquent models with unparalleled import and export superpowers.
Prepare to catapult your application's data fluency into the stratosphere.

This isn't merely about shuffling bits and bytes; it's about **intelligent, resilient, and user-centric data orchestration**.
OmniPorter harnesses the full might of Laravel's queueing system, trait-based architecture, dynamic class resolution, and advanced caching mechanisms to forge a system that:

- ✅ **Ingests mammoth files asynchronously**, keeping your UI snappy
- ✅ **Validates data with surgical precision**, catching errors before they corrupt your database
- ✅ **Navigates complex model relationships** like a seasoned architect
- ✅ **Ensures peak performance** even under heavy load
- ✅ **Keeps your users fully informed** with real-time notifications

Let’s embark on this journey to bestow your models with these remarkable capabilities—**OmniPorter style**.

---

🧱 I. The Foundational Pillars: Architecting OmniPorter’s Excellence
-------------------------------------------------------------------

[](#-i-the-foundational-pillars-architecting-omniporters-excellence)

- **🧩 Traits (`HasImport`, `HasExport`)**
    Your plug-and-play powerups—just `use` them in your Eloquent models and you're off to the races.
- **📜 Interfaces (`Importable`, `Exportable`)**
    Sacred contracts that ensure any participating model defines the required metadata and methods.
- **🎩 Service Provider (`ImportExportServiceProvider`)**
    The dynamic scanner and registrar of all eligible models—**auto-wiring FTW**, courtesy of OmniPorter.
- **🧰 Controllers (`ImportController`, `ExportController`)**
    OmniPorter’s API gatekeepers: enforcing permissions, handling requests, and delegating heavy work to jobs.
- **🧠 Intelligent Caching (`ImportDetailsCache`, `ExportDetailsCache`)**
    Persist chunked job state in Redis for smooth recovery and flawless continuity.
- **📦 Queues &amp; Jobs**
    All major processing (reading, saving, exporting) happens off the main thread—**no UI freeze ever**.
- **📬 Notifications**
    Clear and concise emails are dispatched to notify users of success or failure—with full results.

---

📥 II. Making Your Model Importable with OmniPorter
--------------------------------------------------

[](#-ii-making-your-model-importable-with-omniporter)

### 🔧 A. Implementing the `Importable` and `Exportable` Contracts

[](#-a-implementing-the-importable-and-exportable-contracts)

```
use OmniPorter\Contracts\Importable;
use OmniPorter\Contracts\Exportable;
use Illuminate\Database\Eloquent\Model;

class YourModel extends Model implements Importable, Exportable
{
    public static function getUniqueKeyForImportExport(): string
    {
        return 'work_email';
    }

    public static function getListOfRelationDetails(): array
    {
        return [
            Department::class => ['type' => 'belongsTo', 'method' => 'department', 'field' => 'department_id'],
            Employee::class => ['type' => 'belongsTo', 'method' => 'manager', 'field' => 'reports_to'],
            Profile::class => ['type' => 'hasOne', 'method' => 'profile', 'field' => 'profile_id'],
            Role::class => ['type' => 'belongsToMany', 'method' => 'roles'],
        ];
    }
}
```

---

### ✨ B. Leveraging the `HasImport` Trait

[](#-b-leveraging-the-hasimport-trait)

```
use OmniPorter\Traits\HasImport;

class YourModel extends Model implements Importable, Exportable
{
    use HasImport;
}
```

---

### ✅ C. Model-Specific Validation

[](#-c-model-specific-validation)

```
// CreateEmployeeRequest
public function rules(): array
{
    return [
        'work_email' => ['required', 'string', 'email', 'max:255', 'unique:employees,work_email'],
        // ...
    ];
}
```

```
// UpdateEmployeeRequest
public function rules(?int $id = null): array
{
    return [
        'work_email' => ['required', 'string', 'email', 'max:255', Rule::unique('employees', 'work_email')->ignore($id)],
        // ...
    ];
}
```

---

### 🔄 D. Mapping Excel Headings to Model Fields

[](#-d-mapping-excel-headings-to-model-fields)

- Excel headers should match your model’s `fillable` fields.
- For `belongsTo` relations, use the related model's `getUniqueKeyForImportExport()` return value as the header name.
- For `belongsToMany` relations, provide a comma-separated list of unique keys.

Note

`hasOne` relations are currently supported for **Export** only. For **Import**, use `belongsTo` on the model that holds the foreign key.

---

### 🔮 E. Auto-Creating Missing Related Records

[](#-e-auto-creating-missing-related-records)

OmniPorter can automatically create missing related records during import. For example, if an employee's CSV contains a designation that doesn't exist yet, OmniPorter can create it on the fly.

To enable this, implement the `getAutoCreateAttributesOnImport()` static method on the related model:

```
class Designation extends Model
{
    /**
     * Return the attributes for auto-creating this model during import.
     * Return null to disable auto-creation.
     */
    public static function getAutoCreateAttributesOnImport(string $value): ?array
    {
        return [
            'title' => $value,       // The matched column
            'type'  => 'employee',   // Default values for required fields
        ];
    }
}
```

**How it works:**

1. During import, if a `belongsTo` relation value (e.g., "Data Scientist") is not found in the database, OmniPorter checks if the related model has `getAutoCreateAttributesOnImport()`.
2. If the method exists and returns a non-null array, a new record is created with those attributes.
3. The import cache is updated so subsequent rows referencing the same value don't trigger duplicate creation.
4. All auto-creations are logged for audit purposes.

Tip

If `getAutoCreateAttributesOnImport()` returns `null`, the relation is skipped (set to `null`) and a warning is logged. This allows you to opt-in per model.

---

📤 III. Making Your Model Exportable with OmniPorter
---------------------------------------------------

[](#-iii-making-your-model-exportable-with-omniporter)

### 🧲 A. Use the `HasExport` Trait

[](#-a-use-the-hasexport-trait)

```
use OmniPorter\Traits\HasExport;

class YourModel extends Model implements Importable, Exportable
{
    use HasExport;
}
```

---

### 📃 B. Define `getColumnsToExport()`

[](#-b-define-getcolumnstoexport)

```
public static function getColumnsToExport(): array
{
    return [
        'first_name',
        'work_email',
        'department',
        'roles',
    ];
}
```

---

### 🔍 C. Filtering Exports the OmniPorter Way

[](#-c-filtering-exports-the-omniporter-way)

Example queries:

```
?status=active
?name_like=john
?department_id_in=1,2,3

```

SuffixDescription`_eq`Equal to`_ne`Not equal to`_gt`Greater than`_gte`Greater than or equal to`_lt`Less than`_lte`Less than or equal to`_like`SQL LIKE (e.g. `%value%`)`_nlike`SQL NOT LIKE`_in`In list (comma-separated)`_nin`Not in list (comma-separated)`_null`Is NULL`_nnull`Is NOT NULL---

🌐 IV. Routing Data Traffic with OmniPorter
------------------------------------------

[](#-iv-routing-data-traffic-with-omniporter)

### 📥 Import Endpoint

[](#-import-endpoint)

```
POST /imports/{resource}/{mode}
```

- `mode`: `create` or `update`
- `file`: required in body

---

### 📤 Export Endpoint

[](#-export-endpoint)

```
GET /exports/{resource}
```

- Fully filterable
- OmniPorter handles everything in the background

---

### 📊 Progress Tracking Endpoint

[](#-progress-tracking-endpoint)

```
GET /imports/progress/{batchId}
```

Track the progress of an import in real-time:

**Response**:

```
{
  "success": true,
  "data": {
    "batch_id": "550e8400-e29b-41d4-a716-446655440000",
    "total_rows": 1000,
    "processed_rows": 750,
    "progress": 75.0,
    "status": "in_progress"
  }
}
```

**Status Values**:

- `pending`: Import has not started
- `in_progress`: Import is currently processing
- `completed`: Import has finished

**WebSocket Events**: For real-time updates, listen to the `omniporter-progress.{batchId}` channel:

```
Echo.channel(`omniporter-progress.${batchId}`)
    .listen('ProgressUpdated', (e) => {
        console.log(`Progress: ${e.progress}%`);
        console.log(`Processed: ${e.processedRows}/${e.totalRows}`);
    });
```

---

🛡️ V. OmniPorter Authorization &amp; Permissions
------------------------------------------------

[](#️-v-omniporter-authorization--permissions)

- `employee:import`, `employee:create`, `employee:store`
- `employee:update`, `employee:edit`
- `employee:export`, `employee:index`

```
$user->hasAnyPermission(['employee:create', 'employee:store']);
```

---

---

⚙️ VI. Configuration
--------------------

[](#️-vi-configuration)

Publish the config file:

```
php artisan vendor:publish --tag="omniporter-config"
```

KeyEnvironment VariableDefaultDescription`cache.store``OMNIPORTER_CACHE_STORE``redis`The cache store for job state.`cache.prefix``OMNIPORTER_CACHE_PREFIX``omniporter`Prefix for cache keys.`cache.ttl``OMNIPORTER_CACHE_TTL``3600`How long to keep state (seconds).`import.disk``OMNIPORTER_IMPORT_DISK``local`Disk for uploads/results.`export.disk``OMNIPORTER_EXPORT_DISK``local`Disk for final export files.---

🧹 VII. Maintenance
------------------

[](#-vii-maintenance)

### Clearing Cache

[](#clearing-cache)

If you encounter issues with stuck jobs or state, you can clear the OmniPorter cache:

```
php artisan omniporter:clear-cache
```

---

🏗️ VIII. Behind the Curtains of OmniPorter: How it Works
--------------------------------------------------------

[](#️-viii-behind-the-curtains-of-omniporter-how-it-works)

OmniPorter is designed for massive scale and reliability. Here is how the magic happens:

### 📥 The Import Flow

[](#-the-import-flow)

1. **Upload**: The user sends a file to the `ImportController`.
2. **Storage**: The file is stored on the configured disk.
3. **Queueing**: A `GenericImport` job is dispatched to the queue.
4. **Processing**:
    - The file is read in chunks using `Maatwebsite\Excel`.
    - Each row is validated using your model's `getImportValidators()`.
    - Relationships are resolved via `getListOfRelationDetails()`.
    - Records are created or updated using the unique key from `getUniqueKeysForUpdate()`.
5. **State Tracking**: Progress and failures are tracked in real-time using the `ImportDetailsCache` (stored in Redis).
6. **Completion**: A notification is sent to the user with a summary of successes and failures.

### 📤 The Export Flow

[](#-the-export-flow)

1. **Request**: The user requests an export via `ExportController`, optionally providing filters and columns.
2. **Filtering**: OmniPorter applies dynamic filters based on the request parameters.
3. **Queueing**: A `GenericExport` job is dispatched.
4. **Generation**:
    - Data is queried in chunks to avoid memory issues.
    - Relationships are eager-loaded for performance.
    - The final spreadsheet is generated and saved to the export disk.
5. **Notification**: The user receives an email with a secure download link.

🎯 Conclusion: OmniPorter, Your Data Swiss Army Knife
----------------------------------------------------

[](#-conclusion-omniporter-your-data-swiss-army-knife)

You now wield **OmniPorter**—a high-performance Laravel-based import/export engine that’s:

✅ Asynchronous
✅ Resilient
✅ Secure
✅ Developer-Friendly

> **Go forth, and automate with elegance—with OmniPorter.**
> Because your data deserves better.

###  Health Score

40

—

FairBetter than 86% of packages

Maintenance96

Actively maintained with recent releases

Popularity3

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity47

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

2

Last Release

43d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/5e1d4e5c0d5060ea36bfed39a6fc25fd90612477d868a4d2bbee5ce1dac343f5?d=identicon)[deep-0127](/maintainers/deep-0127)

---

Top Contributors

[![deep-0127](https://avatars.githubusercontent.com/u/279849858?v=4)](https://github.com/deep-0127 "deep-0127 (10 commits)")

---

Tags

csveloquentexcelimport-exportlaravelphpspatielaravelexportexcelcsvqueueimportmaatwebsitebulk-importgeneric-import

###  Code Quality

TestsPHPUnit

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/deep-shah-omniporter/health.svg)

```
[![Health](https://phpackages.com/badges/deep-shah-omniporter/health.svg)](https://phpackages.com/packages/deep-shah-omniporter)
```

###  Alternatives

[unopim/unopim

UnoPim Laravel PIM

10.1k2.2k](/packages/unopim-unopim)[ddeboer/data-import

Import data from, and export data to, a range of file formats and media

5604.3M9](/packages/ddeboer-data-import)[anourvalar/eloquent-serialize

Laravel Query Builder (Eloquent) serialization

11122.5M32](/packages/anourvalar-eloquent-serialize)[portphp/portphp

Data import/export workflow

2873.0M23](/packages/portphp-portphp)[mozex/laravel-scout-bulk-actions

Import, flush, and queue-import all your Laravel Scout searchable models at once. Auto-discovers models, runs in bulk, tracks progress.

1437.7k](/packages/mozex-laravel-scout-bulk-actions)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
