PHPackages                             glhd/conveyor-belt - 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. [Utility &amp; Helpers](/categories/utility)
4. /
5. glhd/conveyor-belt

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

glhd/conveyor-belt
==================

2.3.0(1mo ago)14797.0k↓16.5%5[1 issues](https://github.com/glhd/conveyor-belt/issues)MITPHPPHP &gt;= 8.0CI passing

Since Jan 28Pushed 1mo ago2 watchersCompare

[ Source](https://github.com/glhd/conveyor-belt)[ Packagist](https://packagist.org/packages/glhd/conveyor-belt)[ RSS](/packages/glhd-conveyor-belt/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (10)Dependencies (26)Versions (13)Used By (0)

 [ ![Build Status](https://github.com/glhd/conveyor-belt/workflows/PHPUnit/badge.svg) ](https://github.com/glhd/conveyor-belt/actions) [ ![Latest Stable Release](https://camo.githubusercontent.com/8abff2eb7be2a336115d7e04f2c465efd15480eae5d5a5288e7da06ce302de97/68747470733a2f2f706f7365722e707567782e6f72672f676c68642f636f6e7665796f722d62656c742f762f737461626c65) ](https://packagist.org/packages/glhd/conveyor-belt) [ ![MIT Licensed](https://camo.githubusercontent.com/302d0fe88317347bd3b47367d7772c087b9a4e0c3c836c9daadfd09021c591e4/68747470733a2f2f706f7365722e707567782e6f72672f676c68642f636f6e7665796f722d62656c742f6c6963656e7365) ](./LICENSE) [ ![Follow @cmorrell.com on bsky](https://camo.githubusercontent.com/8790699596340eff27762850c822f5e8e08a379e860085e46bf69359e4d2bc18/68747470733a2f2f696d672e736869656c64732e696f2f626c7565736b792f666f6c6c6f776572732f636d6f7272656c6c2e636f6d) ](https://bsky.app/profile/cmorrell.com)

Conveyor Belt
=============

[](#conveyor-belt)

Conveyor Belt provides all the underlying mechanics necessary to write artisan commands that process lots of data efficiently.

Quickly process 1000's of records
---------------------------------

[](#quickly-process-1000s-of-records)

[![Screencast of default behavior](img/default.svg)](img/default.svg)

Get verbose output when necessary
---------------------------------

[](#get-verbose-output-when-necessary)

[![Screencast of verbose behavior](img/verbose.svg)](img/verbose.svg)

Step through execution &amp; log operations if needed
-----------------------------------------------------

[](#step-through-execution--log-operations-if-needed)

[![Screencast of step behavior](img/step.svg)](img/step.svg)

See what data is changed by your commands
-----------------------------------------

[](#see-what-data-is-changed-by-your-commands)

[![Screencast of diff behavior](img/diff.svg)](img/diff.svg)

And so much more
----------------

[](#and-so-much-more)

[![Screencast of help view](img/more.svg)](img/more.svg)

Installation
------------

[](#installation)

```
# composer require glhd/conveyor-belt
```

Usage
-----

[](#usage)

To use Conveyor Belt, use one of the conveyor belt traits in your Laravel command:

### Databases

[](#databases)

- `\Glhd\ConveyorBelt\IteratesIdQuery` — use this if your underlying query can be ordered by `id` (improves performance)
- `\Glhd\ConveyorBelt\IteratesQuery` — use this if your query **is not ordered by `id`**

### Files

[](#files)

- `\Glhd\ConveyorBelt\IteratesSpreadsheet` — use this to read CSV or Excel files
- `\Glhd\ConveyorBelt\IteratesJson` — use this to read JSON files or JSON API data

### Other

[](#other)

- `\Glhd\ConveyorBelt\IteratesEnumerable` — use this to work with any generic data source

Configuration
-------------

[](#configuration)

Most commands can be configured by setting public properties on the command itself. For example, if you want to enable exception handling, you would add `public $collect_exceptions = true;` to your command. Each config option can also be managed by overriding a function (if you need more dynamic control over its value). See the source of each trait to find the appropriate function name.

### Common for all commands

[](#common-for-all-commands)

- `$collect_exceptions` — set to `true` to have your command continue to run if an exception is triggered (the exception will be printed at the end of command execution)
- `$row_name` — set this to customize command output (e.g. if you're operating on `User` models you could set this to `"user"`)
- `$row_name_plural` — the plural of `$row_name` (usually not necessary, as we use `Str::plural` for you)

### `IteratesQuery`

[](#iteratesquery)

- `$chunk_size` — the number of database records to load at one time
- `$use_transaction` — whether to run the whole command inside a database transaction (can cause locking issues if your command runs for a long time)

### `IteratesIdQuery`

[](#iteratesidquery)

The `IteratesIdQuery` trait accepts all the options that `IteratesQuery` does, as well as:

- `$id_column` — the name of your ID column (if it is not `"id"`)
- `$id_alias` — the alias to your ID column in your query

### `IteratesSpreadsheet`

[](#iteratesspreadsheet)

- `$use_headings` — whether to treat the first row of each sheet as headings
- `$preserve_empty_rows` — whether empty rows should be included
- `$format_dates` — whether date columns should be formatted (typically you don't need this because Conveyor Belt automatically converts date cells to `Carbon` instances for you)
- `$filename` — the file to load (only set if this is not dynamic in any way, which is unusual)
- `$excel_temp_directory` — set if you need to customize where temp files are stored
- `$field_delimiter` — change this if you need to import non-standard CSV files (e.g. tab-delimited)
- `$field_enclosure` — change this if you need to import non-standard CSV files (that don't use the `"` character)
- `$spreadsheet_encoding` — change this if you're dealing with non-UTF-8 data
- `$heading_format` — Change this to any `Str::` function to change the format of your array keys (`"snake"` by default)

### `IteratesJson`

[](#iteratesjson)

- `$filename` — the file to load (only set if this is not dynamic in any way, which is unusual)
- `$json_endpoint` — the JSON endpoint to query for data (use `getJsonEndpoint` to set this dynamically)
- `$json_pointer` — use this to iterate over nested JSON data ([see spec](https://datatracker.ietf.org/doc/html/rfc6901))

Examples
--------

[](#examples)

### Database Example

[](#database-example)

```
class ProcessUnverifiedUsers extends Command
{
  use \Glhd\ConveyorBelt\IteratesIdQuery;

  // By setting $collect_exceptions to true, we tell Conveyor Belt to catch
  // and log exceptions for display, rather than aborting execution
  public $collect_exceptions = true;

  // First, set up the query for the data that your command will operate on.
  // In this example, we're querying for all users that haven't verified their emails.
  public function query()
  {
    return User::query()
      ->whereNull('email_verified_at')
      ->orderBy('id');
  }

  // Then, set up a handler for each row. Our example command is either going to
  // remind users to verify their email (if they signed up recently), or queue
  // a job to prune them from the database.
  public function handleRow(User $user)
  {
    // The `progressMessage()` method updates the progress bar in normal mode,
    // or prints the message in verbose/step mode
    $this->progressMessage("{$user->name} email}>");

    $days = $user->created_at->diffInDays(now());

    // The `progressSubMessage()` method adds additional context. If you're in
    // normal mode, this gets appended to the `progressMessage()`. In verbose or
    // step mode, this gets added as a list item below your `progressMessage()`
    $this->progressSubMessage('Registered '.$days.' '.Str::plural('day', $days).' ago…');

    // Sometimes our command trigger exceptions. Conveyor Belt makes it easy
    // to handle them and not have to lose all our progress
    ThirdParty::checkSomethingThatMayFail();

    if (1 === $days) {
      $this->progressSubmessage('Sending reminder');
      Mail::send(new EmailVerificationReminderMail($user));
    }

    if ($days >= 7) {
      $this->progressSubmessage('Queuing to be pruned');
      PruneUnverifiedUserJob::dispatch($user);
    }
  }
}
```

### File Example

[](#file-example)

```
class ProcessSignUpSheet extends Command
{
  use \Glhd\ConveyorBelt\IteratesSpreadsheet;

  // Conveyor Belt will automatically pick up a "filename" argument. If one
  // is missing you can set a $filename property or implement the getSpreadsheetFilename method
  protected $signature = 'process:sign-up-sheet {filename}';

  public function handleRow($item)
  {
    // $item is an object keyed by the spreadsheet headings in snake_case,
    // so for example, the following CSV:
    //
    // Full Name, Sign Up Date, Email
    // Chris Morrell, 2022-01-02, chris@mailinator.com
    //
    // Will result in a full_name, sign_up_date, and email property
    // on the $item object. You can change from snake case to any other
    // string helper format by setting $heading_format
  }
}
```

The `IteratesJson` trait works exactly the same as the `IteratesSpreadsheet` trait, just with different configuration options.

###  Health Score

57

—

FairBetter than 98% of packages

Maintenance89

Actively maintained with recent releases

Popularity47

Moderate usage in the ecosystem

Community14

Small or concentrated contributor base

Maturity61

Established project with proven stability

 Bus Factor1

Top contributor holds 97.8% 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 ~137 days

Recently: every ~282 days

Total

12

Last Release

56d ago

Major Versions

0.3.3 → 1.0.02023-02-17

1.0.0 → 2.0.02023-07-03

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/21592?v=4)[Chris Morrell](/maintainers/inxilpro)[@inxilpro](https://github.com/inxilpro)

---

Top Contributors

[![inxilpro](https://avatars.githubusercontent.com/u/21592?v=4)](https://github.com/inxilpro "inxilpro (87 commits)")[![Skullbock](https://avatars.githubusercontent.com/u/1104083?v=4)](https://github.com/Skullbock "Skullbock (1 commits)")[![skylerkatz](https://avatars.githubusercontent.com/u/7297992?v=4)](https://github.com/skylerkatz "skylerkatz (1 commits)")

---

Tags

laravel

###  Code Quality

TestsPHPUnit

Code StylePHP CS Fixer

### Embed Badge

![Health badge](/badges/glhd-conveyor-belt/health.svg)

```
[![Health](https://phpackages.com/badges/glhd-conveyor-belt/health.svg)](https://phpackages.com/packages/glhd-conveyor-belt)
```

###  Alternatives

[aedart/athenaeum

Athenaeum is a mono repository; a collection of various PHP packages

245.2k](/packages/aedart-athenaeum)[livewire/flux

The official UI component library for Livewire.

9475.0M86](/packages/livewire-flux)[laravel-zero/framework

The Laravel Zero Framework.

3371.4M369](/packages/laravel-zero-framework)[spatie/laravel-enum

Laravel Enum support

3655.4M31](/packages/spatie-laravel-enum)[laragear/preload

Effortlessly make a Preload script for your Laravel application.

119363.5k](/packages/laragear-preload)[flarum/core

Delightfully simple forum software.

211.3M1.9k](/packages/flarum-core)

PHPackages © 2026

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