Pipelines
Process data through multiple stages with pipelines.
Introduction
Section titled “Introduction”Pipelines allow you to chain multiple processing stages:
- ✅ Transformers - Transform data
- ✅ Normalizers - Normalize data types
- ✅ Validators - Validate data
- ✅ Custom Stages - Create custom stages
Basic Usage
Section titled “Basic Usage”Creating a Pipeline
Section titled “Creating a Pipeline”use event4u\DataHelpers\SimpleDTO\Pipeline\DTOPipeline;use event4u\DataHelpers\SimpleDTO\Pipeline\Stages\TransformerStage;use event4u\DataHelpers\SimpleDTO\Pipeline\Transformers\TrimStringsTransformer;
$pipeline = new DTOPipeline();$pipeline->addStage(new TransformerStage(new TrimStringsTransformer()));
$dto = UserDTO::fromArrayWithPipeline($data, $pipeline);Multiple Stages
Section titled “Multiple Stages”$pipeline = new DTOPipeline();$pipeline->addStage(new NormalizerStage(new TypeNormalizer(['age' => 'int'])));$pipeline->addStage(new TransformerStage(new TrimStringsTransformer()));$pipeline->addStage(new ValidationStage());
$dto = UserDTO::fromArrayWithPipeline($data, $pipeline);Built-in Transformers
Section titled “Built-in Transformers”TrimStringsTransformer
Section titled “TrimStringsTransformer”use event4u\DataHelpers\SimpleDTO\Pipeline\Transformers\TrimStringsTransformer;
$pipeline = new DTOPipeline();$pipeline->addStage(new TransformerStage(new TrimStringsTransformer()));
$data = ['name' => ' John Doe '];$dto = UserDTO::fromArrayWithPipeline($data, $pipeline);// name: 'John Doe'LowerCaseTransformer
Section titled “LowerCaseTransformer”use event4u\DataHelpers\SimpleDTO\Pipeline\Transformers\LowerCaseTransformer;
$pipeline = new DTOPipeline();$pipeline->addStage(new TransformerStage(new LowerCaseTransformer(['email'])));
$data = ['email' => 'JOHN@EXAMPLE.COM'];$dto = UserDTO::fromArrayWithPipeline($data, $pipeline);// email: 'john@example.com'UpperCaseTransformer
Section titled “UpperCaseTransformer”use event4u\DataHelpers\SimpleDTO\Pipeline\Transformers\UpperCaseTransformer;
$pipeline = new DTOPipeline();$pipeline->addStage(new TransformerStage(new UpperCaseTransformer(['code'])));
$data = ['code' => 'abc123'];$dto = UserDTO::fromArrayWithPipeline($data, $pipeline);// code: 'ABC123'Custom Transformers
Section titled “Custom Transformers”Creating a Custom Transformer
Section titled “Creating a Custom Transformer”use event4u\DataHelpers\SimpleDTO\Contracts\Transformer;
class SlugifyTransformer implements Transformer{ public function __construct( private array $fields = [], ) {}
public function transform(array $data): array { foreach ($this->fields as $field) { if (isset($data[$field])) { $data[$field] = $this->slugify($data[$field]); } }
return $data; }
private function slugify(string $value): string { $slug = strtolower($value); $slug = preg_replace('/[^a-z0-9]+/', '-', $slug); $slug = trim($slug, '-');
return $slug; }}
// Usage$pipeline = new DTOPipeline();$pipeline->addStage(new TransformerStage(new SlugifyTransformer(['title'])));Custom Stages
Section titled “Custom Stages”Creating a Custom Stage
Section titled “Creating a Custom Stage”use event4u\DataHelpers\SimpleDTO\Contracts\PipelineStage;
class SanitizeStage implements PipelineStage{ public function process(array $data): array { foreach ($data as $key => $value) { if (is_string($value)) { $data[$key] = htmlspecialchars($value, ENT_QUOTES, 'UTF-8'); } }
return $data; }
public function getName(): string { return 'sanitize'; }}
// Usage$pipeline = new DTOPipeline();$pipeline->addStage(new SanitizeStage());Real-World Examples
Section titled “Real-World Examples”User Registration Pipeline
Section titled “User Registration Pipeline”$pipeline = new DTOPipeline();
// 1. Trim all strings$pipeline->addStage(new TransformerStage(new TrimStringsTransformer()));
// 2. Lowercase email$pipeline->addStage(new TransformerStage(new LowerCaseTransformer(['email'])));
// 3. Normalize types$pipeline->addStage(new NormalizerStage(new TypeNormalizer([ 'age' => 'int', 'active' => 'bool',])));
// 4. Validate$pipeline->addStage(new ValidationStage());
$dto = UserDTO::fromArrayWithPipeline($_POST, $pipeline);API Data Processing
Section titled “API Data Processing”$pipeline = new DTOPipeline();
// 1. Remove null values$pipeline->addStage(new FilterStage(fn($v) => $v !== null));
// 2. Trim strings$pipeline->addStage(new TransformerStage(new TrimStringsTransformer()));
// 3. Convert dates$pipeline->addStage(new TransformerStage(new DateTransformer([ 'created_at', 'updated_at',])));
$dto = ProductDTO::fromArrayWithPipeline($apiResponse, $pipeline);Form Data Processing
Section titled “Form Data Processing”$pipeline = new DTOPipeline();
// 1. Sanitize HTML$pipeline->addStage(new SanitizeStage());
// 2. Trim strings$pipeline->addStage(new TransformerStage(new TrimStringsTransformer()));
// 3. Generate slug from title$pipeline->addStage(new TransformerStage(new SlugifyTransformer(['slug'])));
// 4. Validate$pipeline->addStage(new ValidationStage());
$dto = PostDTO::fromArrayWithPipeline($_POST, $pipeline);Pipeline Context
Section titled “Pipeline Context”Passing Context
Section titled “Passing Context”$pipeline = new DTOPipeline();$pipeline->setContext('user_id', auth()->id());$pipeline->setContext('ip_address', request()->ip());
$pipeline->addStage(new AuditStage());
$dto = UserDTO::fromArrayWithPipeline($data, $pipeline);Reading Context
Section titled “Reading Context”class AuditStage implements PipelineStage{ public function process(array $data): array { $userId = $this->getContext('user_id'); $ipAddress = $this->getContext('ip_address');
// Log audit trail AuditLog::create([ 'user_id' => $userId, 'ip_address' => $ipAddress, 'data' => $data, ]);
return $data; }
public function getName(): string { return 'audit'; }}Error Handling
Section titled “Error Handling”Stop on Error
Section titled “Stop on Error”$pipeline = new DTOPipeline();$pipeline->stopOnError(true); // Default
$pipeline->addStage(new ValidationStage());
try { $dto = UserDTO::fromArrayWithPipeline($data, $pipeline);} catch (Exception $e) { // Handle error}Continue on Error
Section titled “Continue on Error”$pipeline = new DTOPipeline();$pipeline->stopOnError(false);
$pipeline->addStage(new ValidationStage());$pipeline->addStage(new TransformerStage(new TrimStringsTransformer()));
$dto = UserDTO::fromArrayWithPipeline($data, $pipeline);
// Check for errors$errors = $pipeline->getErrors();Best Practices
Section titled “Best Practices”Order Matters
Section titled “Order Matters”// ✅ Good - correct order$pipeline->addStage(new TrimStage()); // 1. Clean data$pipeline->addStage(new NormalizeStage()); // 2. Normalize types$pipeline->addStage(new ValidationStage()); // 3. Validate
// ❌ Bad - wrong order$pipeline->addStage(new ValidationStage()); // Validates dirty data$pipeline->addStage(new TrimStage());Reusable Pipelines
Section titled “Reusable Pipelines”// ✅ Good - reusableclass UserPipeline{ public static function create(): DTOPipeline { $pipeline = new DTOPipeline(); $pipeline->addStage(new TrimStage()); $pipeline->addStage(new ValidationStage());
return $pipeline; }}
$dto = UserDTO::fromArrayWithPipeline($data, UserPipeline::create());
// ❌ Bad - not reusable$pipeline = new DTOPipeline();$pipeline->addStage(new TrimStage());// ... repeat everywhereSingle Responsibility
Section titled “Single Responsibility”// ✅ Good - single responsibilityclass TrimStage implements PipelineStage{ public function process(array $data): array { // Only trim strings }}
// ❌ Bad - multiple responsibilitiesclass ProcessStage implements PipelineStage{ public function process(array $data): array { // Trim, validate, transform, etc. }}See Also
Section titled “See Also”- Custom Casts - Custom type casts
- Custom Validation - Custom validation rules
- Hooks & Events - Hooks and events