From a926da9c0d5d137d4a0c362b926a2d483ec3f3e5 Mon Sep 17 00:00:00 2001 From: Beno!t POLASZEK Date: Fri, 17 Nov 2023 14:41:06 +0100 Subject: [PATCH] Feat: Default context (#45) --- doc/getting-started.md | 16 ++++++++++++++++ src/EtlExecutor.php | 11 ++++++++++- src/Internal/EtlBuilderTrait.php | 8 ++++++++ tests/Unit/EtlExecutorTest.php | 11 +++++++++++ 4 files changed, 45 insertions(+), 1 deletion(-) diff --git a/doc/getting-started.md b/doc/getting-started.md index dc4a56d..e11d920 100644 --- a/doc/getting-started.md +++ b/doc/getting-started.md @@ -71,6 +71,22 @@ If you use callables, it will be injected as well. The `ETLState` object is also injected into all events. Most of its properties are read-only, except `context`. +> [!TIP] +> Your executor can provide a default context (see example below). + +```php +it('accepts a default context', function () { + // Given + $executor = (new EtlExecutor())->withContext(['foo' => 'bar']); + + // When + $report = $executor->process([], context: ['bar' => 'baz']); + + // Then + expect($report->context)->toBe(['foo' => 'bar', 'bar' => 'baz']); +}); +``` + Skipping items -------------- diff --git a/src/EtlExecutor.php b/src/EtlExecutor.php index 86811c4..b47984f 100644 --- a/src/EtlExecutor.php +++ b/src/EtlExecutor.php @@ -56,12 +56,16 @@ final class EtlExecutor implements EventDispatcherInterface private EventDispatcher $eventDispatcher; + /** + * @param array $context + */ public function __construct( public readonly ExtractorInterface $extractor = new IterableExtractor(), public readonly TransformerInterface $transformer = new NullTransformer(), public readonly LoaderInterface $loader = new InMemoryLoader(), public readonly EtlConfiguration $options = new EtlConfiguration(), public readonly ProcessorInterface $processor = new IterableProcessor(), + public readonly array $context = [], ) { $this->listenerProvider = new PrioritizedListenerProvider(); $this->eventDispatcher = new EventDispatcher($this->listenerProvider); @@ -74,7 +78,12 @@ public function __construct( */ public function process(mixed $source = null, mixed $destination = null, array $context = []): EtlState { - $state = new EtlState(options: $this->options, source: $source, destination: $destination, context: $context); + $state = new EtlState( + options: $this->options, + source: $source, + destination: $destination, + context: [...$this->context, ...$context] + ); try { $this->emit(InitEvent::class, $state); diff --git a/src/Internal/EtlBuilderTrait.php b/src/Internal/EtlBuilderTrait.php index 31d98a1..22f4bb5 100644 --- a/src/Internal/EtlBuilderTrait.php +++ b/src/Internal/EtlBuilderTrait.php @@ -108,4 +108,12 @@ public function withProcessor(ProcessorInterface $processor): self { return $this->cloneWith(['processor' => $processor]); } + + /** + * @param array $context + */ + public function withContext(array $context): self + { + return $this->cloneWith(['context' => $context]); + } } diff --git a/tests/Unit/EtlExecutorTest.php b/tests/Unit/EtlExecutorTest.php index 3dbe0c9..7ff99ef 100644 --- a/tests/Unit/EtlExecutorTest.php +++ b/tests/Unit/EtlExecutorTest.php @@ -114,3 +114,14 @@ public function process(EtlExecutor $executor, EtlState $state, mixed $extracted // When $executor->process([]); })->throws(ExtractException::class); + +it('accepts a default context', function () { + // Given + $executor = (new EtlExecutor())->withContext(['foo' => 'bar']); + + // When + $report = $executor->process([], context: ['bar' => 'baz']); + + // Then + expect($report->context)->toBe(['foo' => 'bar', 'bar' => 'baz']); +});