PHP code example of kariricode / processor-pipeline

1. Go to this page and download the library: Download kariricode/processor-pipeline library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

kariricode / processor-pipeline example snippets


// The old way: ad-hoc chain, hard to test or reuse
function processInput(string $input): string
{
    $input = trim($input);
    $input = strtolower($input);
    if (strlen($input) < 3) {
        throw new \InvalidArgumentException('Too short');
    }
    return $input;
}

use KaririCode\ProcessorPipeline\ProcessorRegistry;
use KaririCode\ProcessorPipeline\ProcessorBuilder;

// 1. Register processors once, per context
$registry = new ProcessorRegistry();
$registry
    ->register('sanitizer', 'trim',      new TrimProcessor())
    ->register('sanitizer', 'lowercase', new LowercaseProcessor())
    ->register('validator', 'length',    new LengthValidator());

// 2. Build immutable pipelines from specs
$builder   = new ProcessorBuilder($registry);
$sanitized = $builder->buildPipeline('sanitizer', ['trim', 'lowercase']);
$validated = $builder->buildPipeline('validator', [
    'length' => ['minLength' => 3, 'maxLength' => 50],
]);

// 3. Execute — pipelines are immutable and reusable
$output = $sanitized->process('  HELLO WORLD  '); // 'hello world'
$validated->process($output);



declare(strict_types=1);

or\Processor;
use KaririCode\Contract\Processor\ConfigurableProcessor;
use KaririCode\ProcessorPipeline\ProcessorRegistry;
use KaririCode\ProcessorPipeline\ProcessorBuilder;

// 1. Define processors
final class TrimProcessor implements Processor
{
    public function process(mixed $input): mixed
    {
        return is_string($input) ? trim($input) : $input;
    }
}

final class LengthValidator implements ConfigurableProcessor
{
    private int $min = 0;
    private int $max = PHP_INT_MAX;

    public function configure(array $options): void
    {
        $this->min = $options['minLength'] ?? $this->min;
        $this->max = $options['maxLength'] ?? $this->max;
    }

    public function process(mixed $input): mixed
    {
        $len = mb_strlen((string) $input);
        if ($len < $this->min || $len > $this->max) {
            throw new \LengthException("Length must be between {$this->min} and {$this->max}.");
        }
        return $input;
    }
}

// 2. Register and build
$registry = new ProcessorRegistry();
$registry
    ->register('sanitizer', 'trim',   new TrimProcessor())
    ->register('validator', 'length', new LengthValidator());

$builder  = new ProcessorBuilder($registry);
$pipeline = $builder->buildPipeline('sanitizer', ['trim']);
$validate = $builder->buildPipeline('validator', [
    'length' => ['minLength' => 3, 'maxLength' => 50],
]);

// 3. Execute
$sanitized = $pipeline->process('  Hello, World!  '); // 'Hello, World!'
$validate->process($sanitized);                        // passes — 13 chars

var_dump($sanitized); // string(13) "Hello, World!"

$base     = $builder->buildPipeline('sanitizer', ['trim']);
$extended = $base->withProcessor(new LowercaseProcessor());

// $base still has 1 processor
// $extended has 2 processors
assert($base->count() === 1);
assert($extended->count() === 2);

$registry->register('validator', 'email', new EmailValidator());
$registry->register('sanitizer', 'email', new EmailSanitizer()); // same name, different context

$validationPipeline  = $builder->buildPipeline('validator', ['email']);
$sanitizationPipeline = $builder->buildPipeline('sanitizer', ['email']);

$pipeline = $builder->buildPipeline('validator', [
    'licit: enabled
    'strict' => false,                           // Explicit: disabled (skipped)
    'length' => ['minLength' => 3, 'maxLength' => 50], // Configured
]);

final class SlugProcessor implements ConfigurableProcessor
{
    private string $separator = '-';

    public function configure(array $options): void
    {
        $this->separator = $options['separator'] ?? '-';
    }

    public function process(mixed $input): mixed
    {
        return strtolower(str_replace(' ', $this->separator, trim((string) $input)));
    }
}

$pipeline = $builder->buildPipeline('formatter', [
    'slug' => ['separator' => '_'],
]);
$pipeline->process('Hello World'); // 'hello_world'

use KaririCode\ProcessorPipeline\Handler\ProcessorHandler;
use KaririCode\ProcessorPipeline\Result\ProcessingResultCollection;

$results = new ProcessingResultCollection();

$handler = new ProcessorHandler(
    processor:        new EmailValidator(),
    resultCollection: $results,
    haltOnError:      false,   // continue on failure
);

$output = $handler->process('not-an-email'); // returns input unchanged

if ($results->hasErrors()) {
    foreach ($results->getErrors() as $processor => $errors) {
        foreach ($errors as $error) {
            echo "{$processor}: {$error['message']}\n";
        }
    }
}

use KaririCode\ProcessorPipeline\Attribute\Process;

final class UserProfile
{
    #[Process(
        processors: ['trim', 'lowercase'],
        messages:   [],
    )]
    public private(set) string $email = '';

    #[Process(
        processors: ['

use KaririCode\ProcessorPipeline\Exception\PipelineExecutionException;

try {
    $pipeline->process($input);
} catch (PipelineExecutionException $e) {
    // $e->context['stage']         — stage index where failure occurred
    // $e->context['processorName'] — FQCN of the failing processor
    // $e->getPrevious()            — original exception
}

ProcessorBuilder::buildPipeline($context, $specs)
        │
        ▼
foreach spec entry:
    resolveSpec($key, $value)
      ├── string key   → name only (enabled, default config)
      ├── name => true → enabled, no config
      ├── name => false → SKIP
      └── name => [..] → enabled + configure()
        │
        ▼
    ProcessorRegistry::get($context, $name)
    ConfigurableProcessor::configure($options)  ← if applicable
    $processors[] = $processor
        │
        ▼
new Pipeline($processors)   ← immutable, readonly

Pipeline::process($input)
        │
        ▼
foreach processor as $index => $p:
    try:
        $state = $p->process($state)
    catch \Throwable:
        throw PipelineExecutionException::atStage($p::class, $index, $cause)
        │
        ▼
return $state

src/
├── Attribute/
│   └── Process.php                       PHP 8.4 attribute for declarative pipelines
├── Exception/
│   ├── PipelineExecutionException.php    Stage-aware failure with context array
│   ├── ProcessorNotFoundException.php    Registry miss
│   ├── InvalidProcessorConfigurationException.php
│   └── ProcessorPipelineException.php    Base exception
├── Handler/
│   └── ProcessorHandler.php             Error-collecting processor wrapper
├── Pipeline/
│   └── Pipeline.php                     Immutable readonly sequential executor
├── Result/
│   └── ProcessingResultCollection.php   Error + execution trace accumulator
├── ProcessorBuilder.php                 Factory: spec → Pipeline
└── ProcessorRegistry.php               Context-based processor store