PHPackages                             shampine/sequence - 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. shampine/sequence

ActiveLibrary

shampine/sequence
=================

A modern pipeline package

v2.0.0(3y ago)211202[9 issues](https://github.com/shampine/sequence/issues)MITPHPPHP ^8.1|^8.2

Since Sep 13Pushed 3y agoCompare

[ Source](https://github.com/shampine/sequence)[ Packagist](https://packagist.org/packages/shampine/sequence)[ RSS](/packages/shampine-sequence/feed)WikiDiscussions master Synced 1w ago

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

sequence
========

[](#sequence)

[![example workflow name](https://github.com/shampine/sequence/workflows/Sequence%20Build/badge.svg)](https://github.com/shampine/sequence/workflows/Sequence%20Build/badge.svg)

A framework agnostic pipelining package to handle complete requests built on [The PHP League Pipeline Package](https://github.com/thephpleague/pipeline).

[Laravel Demo - https://github.com/shampine/sequence-demo](https://github.com/shampine/sequence-demo)
[Tutorial - https://medium.com/gosteady/day-5-sequence-how-to-guide-56c0af1b2303](https://medium.com/gosteady/day-5-sequence-how-to-guide-56c0af1b2303)

why
---

[](#why)

Using the pipeline pattern developers can move quickly, recycle processes, and test everything.

[![pipeline diagram](https://raw.githubusercontent.com/shampine/sequence/master/diagram.png)](https://raw.githubusercontent.com/shampine/sequence/master/diagram.png)

Benefits to using pipelines for an MVC framework include

- skinny and consistent controllers
- ability to share processes amongst different pipelines
- simple injection of service or repository classes into the processes to keep code clean
- ease of testing individual processes
- clear, consistent api responses
- eliminate need to try/catch exceptions inside the stack

installation
------------

[](#installation)

`composer require shampine/sequence`

usage
-----

[](#usage)

These examples are using Laravel conventions but this package is framework agnostic.

See these three files for verbose usage examples and live demos inside the phpunit tests.

[Sample Payload](https://github.com/shampine/sequence/blob/master/tests/Sample/SamplePayload.php)
[Sample Response](https://github.com/shampine/sequence/blob/master/tests/Sample/SampleResponse.php)
[Sample Pipeline](https://github.com/shampine/sequence/blob/master/tests/Sample/SamplePipeline.php)

### Payloads

[](#payloads)

This is the active workspace. The payload is mutated as it passes thru each stage. Any data needed from one stage to another needs to be set on the payload, and then retrieved from the payload.

When defining your Payloads you can optionally define a `$allowlist` and `$overrides`.

```
$allowlist = ['email']; // Only hydrate `email` from post/patch
$overrides = ['email_address' => 'email']; // Allows `email_address` to be hydrated as `email`
$payload = new \Sample\SamplePayload($allowlist, $overrides);
```

An allowlist will limit what user supplied input will be hydrated into the Payload. The overrides parameter allows mapping of different external keys to internal keys. E.g. if the post contains `email_address` but on the payload the method is called `setEmail`. Mapping `['email_address' => 'email']` will properly align hydration.

### Pipeline Composition

[](#pipeline-composition)

A pipeline can have multiple named closures stored in the `$pipelines` property. This will allow grouping of similar pipelines together, e.g. GET, POST, PATCH, DELETE pipelines. You can pass attributes into the pipeline either thru the class constructor OR the closure constructor.

Services, repositories, and other dependency injectable parameters are best set by using the class constructor. While flags and other stage related properties can be injected using `->process($pipelineName, $payload, ...$argments)`.

This example pipeline has a service injected into the constructor but two boolean flags passed through the $arguments parameter on `->process()`.

```
class SamplePipeline extends AbstractPipeline
{
    public const SAMPLE_PIPELINE = 'SamplePipeline';

    public function __construct(?SampleUseService $sampleUseService = null)
    {
        $this->pipelines = [
            self::SAMPLE_PIPELINE => static function(
                bool $validationFailure = false,
                bool $sequenceFailure = false
            ) use ($sampleUseService)
            {
                return (new Pipeline)
                    ->pipe(new ValidationExceptionProcess($validationFailure, $sampleUseService))
                    ->pipe(new SequenceExceptionProcess($sequenceFailure))
                    ->pipe(new HydrateResponseProcess(SampleResponsePayload::class));
            }
        ];

        $this->excludeWhenEmpty = [
            'empty_value',
        ];

        $this->excludeWhenNull = [
            'null_value',
        ];
    }
}
```

The property `$excludeWhenEmpty` or `$excludeWhenNull` will check ANY root or data keys to see if their value is `empty()` or `=== null`. If so they are excluded from the final array, all keys should use `snake_case`.

### Response

[](#response)

Responses are the final output containers and should be hydrated in the final stage of a pipeline. All properties on the class can have a getter, but if they do not the property will be magically accessed.

```
public function __construct(SamplePayload $payload)
{
    $this->setSampleAbout('This is an about statement.');
}
```

During the format process `getSampleAbout` would be used to compile the final array that will be returned as json.

### Controller Examples (Laravel)

[](#controller-examples-laravel)

Using dependency injection on your controller to instantiate the pipeline.

```
class SampleController
{
    public function __construct(SamplePipeline $samplePipeline)
    {
        $this-samplePipeline = $samplePipeline;
    }
}
```

#### GET

[](#get)

```
public function get(Request $request)
{
    $payload = new SamplePayload();
    $response = $this->samplePipeline->process(SamplePipeline::SAMPLE_PIPELINE, $payload)->format();

    return response()->json($response, $response['http_code']);
}
```

#### POST

[](#post)

```
public function post(Request $request)
{
    $payload = (new SamplePayload())->hydratePost($request->all());
    $response = $this->samplePipeline->process(SamplePipeline::SAMPLE_PIPELINE, $payload)->format();

    return response()->json($response, $response['http_code']);
}
```

#### PATCH

[](#patch)

Patch payloads require the `PatchInterface` and `PatchTrait`. The payload will contain methods to decipher what is requested to be patched `->getPatch()` and whether the payload is a patch request `->isPatch()`.

```
public function patch(Request $request)
{
    $payload = (new SamplePayload())->hydratePatch($request->all());
    $response = $this->samplePipeline->process(SamplePipeline::SAMPLE_PIPELINE, $payload)->format();

    return response()->json($response, $response['http_code']);
}
```

### Exceptions

[](#exceptions)

Included are two exceptions, ValidationException and SequenceException. Both are caught and rendered to json. You can define specific exception by extending these classes. They are caught and rendered the same as a normal payload to easily allow json to be return.

```
class FetchUser extends AbstractProcess
{
    public function process($payload)
    {
        $user = $this->userService->getUserRepository()->fetchUserById($payload->getId());

        if ($user === null) {
            throw new SequenceException(1000, 'User not found', 400);
        }

        $payload->setUser($user);

        return $payload;
    }
}
```

A null user returns

```
{
  "error_code": 1000,
  "status_code": 400,
  "data": null,
  "message": "User not found",
  "error_messages": null
}
```

Any standard php exception will fatal the application like normal. Logging should exist in a constructor of an exception class that extends ValidationException or SequenceException.

testing
-------

[](#testing)

To run all tests run `./tests/run.sh`.

This will execute:

- phpstan level 8
- phpunit with code coverage (expects 100% coverage)

license
-------

[](#license)

MIT

###  Health Score

32

—

LowBetter than 72% of packages

Maintenance11

Infrequent updates — may be unmaintained

Popularity19

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity73

Established project with proven stability

 Bus Factor1

Top contributor holds 98.6% 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 ~94 days

Recently: every ~141 days

Total

11

Last Release

1126d ago

Major Versions

v0.2.0 → v1.0.02020-10-22

v1.3.0 → v2.0.02023-04-17

PHP version history (5 changes)v0.1.0PHP &gt;=7.4

v1.0.1PHP ^7.4

v1.2.0PHP ^7.4|^8.0

v1.3.0PHP ^7.4|^8.0|^8.1

v2.0.0PHP ^8.1|^8.2

### Community

Maintainers

![](https://www.gravatar.com/avatar/64b04b330c1adf5689dd0a531dbcef2fc39f7efffa92db14e1a36dee338e0eca?d=identicon)[shampine](/maintainers/shampine)

---

Top Contributors

[![shampine](https://avatars.githubusercontent.com/u/1027737?v=4)](https://github.com/shampine "shampine (70 commits)")[![thekonz](https://avatars.githubusercontent.com/u/2700089?v=4)](https://github.com/thekonz "thekonz (1 commits)")

---

Tags

laravellaravel-pipelinephppipelinesymfony

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/shampine-sequence/health.svg)

```
[![Health](https://phpackages.com/badges/shampine-sequence/health.svg)](https://phpackages.com/packages/shampine-sequence)
```

###  Alternatives

[hisorange/browser-detect

Browser &amp; Mobile detection package for Laravel.

1.1k10.1M50](/packages/hisorange-browser-detect)[concrete5/core

Concrete core subtree split

19159.3k48](/packages/concrete5-core)[beacon-hq/bag

A comprehensive immutable value objects implementation

1789.1k3](/packages/beacon-hq-bag)[phuml/phuml

phUML is a fully automatic UML class diagram generator for PHP code

11411.3k1](/packages/phuml-phuml)[synolia/sylius-akeneo-plugin

Akeneo connector for Sylius.

2696.0k](/packages/synolia-sylius-akeneo-plugin)[refinery29/piston

Opinionated Micro Framework for APIs

1936.8k](/packages/refinery29-piston)

PHPackages © 2026

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