Skip to content

Commit

Permalink
Added Pipeline support class and Pipeline facade
Browse files Browse the repository at this point in the history
  • Loading branch information
lukewatts committed Mar 7, 2024
1 parent 0bfb333 commit b787abb
Show file tree
Hide file tree
Showing 15 changed files with 779 additions and 1 deletion.
76 changes: 76 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -264,3 +264,79 @@ $container
->unless(fn($container) => $container->has('FileDriver'), FileDriverServiceFactory($container))
->unless(fn($container) => $container->has('Logger'), LoggerServiceFactory($container));
```

## Pipeline Support class

Pipelines allow for a middleware-like interface to chain processing of tasks.

A pipeline processes each task, passed the returned value to the next process in the chain.

They are useful for multi-step data processing, http middleware, database querying and validation tasks.

Here's an example of how to use it to validation, filter, transform and save an incoming get request.

```php
class PrepareRequest
{
public function handle($request, $next)
{
$uri = $request->getUri();
$query = $uri->getQuery(); // Get the query string (e.g., "param1=value1&param2=value2")
parse_str($query, $queryParams); // Parse the query string into an array

return $next($request);
}
}

// 1. Create a custom pipe for validation
class ValidateRequest
{
public function handle($request, $next)
{
// Validate parameters (e.g., check if 'name', 'age', and 'email' exist)

return $next($request);
}
}

// 2. Create a pipe for data transformation
class TransformRequest
{
public function handle($request, $next)
{
// Capitalize the 'name' parameter
$request['name'] = ucfirst($request['name']);

return $next($request);
}
}

// 3. Create a pipe for Saving the data
class SaveRequest
{
public function handle($request, $next)
{
// Save to database

return $next($request);
}
}

App::get('/', function ($request) {
// 4. Define the pipeline
$result = (new Pipeline(App::getContainer()))
->send($request)
->through([
PrepareRequest::class,
ValidateRequest::class,
TransformRequest::class,
SaveRequest::class,
])
->thenReturn();

// 5. Respond with the processed data
return response()->json(['message' => 'Request processed successfully', 'result' => $result])->get();
});
```

This way our controller stays clean, and readable, and each responsibility is separated to it's own class to make maintainance easier in the long run. This would also make testing easier, as you could test the individual classes, and also the overall pipeline result, without needing to test the controller itself.
5 changes: 5 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@
"./src/Support/helpers.php"
]
},
"autoload-dev": {
"psr-4": {
"SlimFacades\\Tests\\": "tests/"
}
},
"require": {
"php": "^8.1",
"psr/http-factory": "^1.0"
Expand Down
40 changes: 40 additions & 0 deletions src/Contracts/Pipeline.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

namespace SlimFacades\Contracts;

use Closure;

interface Pipeline
{
/**
* Set the traveler object being sent on the pipeline.
*
* @param mixed $traveler
* @return $this
*/
public function send($traveler);

/**
* Set the stops of the pipeline.
*
* @param dynamic|array $stops
* @return $this
*/
public function through($stops);

/**
* Set the method to call on the stops.
*
* @param string $method
* @return $this
*/
public function via($method);

/**
* Run the pipeline with a final destination callback.
*
* @param \Closure $destination
* @return mixed
*/
public function then(Closure $destination);
}
22 changes: 22 additions & 0 deletions src/Facades/Pipeline.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php declare(strict_types=1);

namespace SlimFacades\Facades;

use SlimFacades\Support\Facade;
use SlimFacades\Support\Pipeline as PipelineBase;

class Pipeline extends Facade
{
public static function getFacadeRoot()
{
return new PipelineBase(static::$app->getContainer());
}

/**
* @inheritDoc
*/
protected static function getFacadeAccessor(): string
{
return 'pipeline';
}
}
Loading

0 comments on commit b787abb

Please sign in to comment.