Skip to content

Commit

Permalink
Make maxOutputs() work with Group steps
Browse files Browse the repository at this point in the history
Move most functionality from `Step` to `BaseStep` and make it work with
`Group` steps.
  • Loading branch information
otsch committed Sep 4, 2024
1 parent 576d1db commit 5856bea
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 27 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
* New methods `FileCache::prolong()` and `FileCache::prolongAll()` to allow prolonging the time to live for cached responses.

### Fixed
* The `maxOutputs()` method is now also available and working on `Group` steps.

## [1.10.0] - 2024-08-05
### Added
* URL refiners: `UrlRefiner::withScheme()`, `UrlRefiner::withHost()`, `UrlRefiner::withPort()`, `UrlRefiner::withoutPort()`, `UrlRefiner::withPath()`, `UrlRefiner::withQuery()`, `UrlRefiner::withoutQuery()`, `UrlRefiner::withFragment()` and `UrlRefiner::withoutFragment()`.
Expand Down
25 changes: 25 additions & 0 deletions src/Steps/BaseStep.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ abstract class BaseStep implements StepInterface

protected ?string $outputKey = null;

protected ?int $maxOutputs = null;

protected int $currentOutputCount = 0;

/**
* @param Input $input
* @return Generator<Output>
Expand Down Expand Up @@ -250,9 +254,18 @@ public function outputKey(string $key): static
return $this;
}

public function maxOutputs(int $maxOutputs): static
{
$this->maxOutputs = $maxOutputs;

return $this;
}

public function resetAfterRun(): void
{
$this->uniqueOutputKeys = $this->uniqueInputKeys = [];

$this->currentOutputCount = 0;
}

/**
Expand Down Expand Up @@ -717,4 +730,16 @@ protected function getOutputKeyAliasRealKey(string $key): string

return $mapping[$key];
}

protected function maxOutputsExceeded(): bool
{
return $this->maxOutputs !== null && $this->currentOutputCount >= $this->maxOutputs;
}

protected function trackYieldedOutput(): void
{
if ($this->maxOutputs !== null) {
$this->currentOutputCount += 1;
}
}
}
21 changes: 21 additions & 0 deletions src/Steps/Group.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ public function addStep(StepInterface $step): self
$step->setLoader($this->loader);
}

if ($this->maxOutputs) {
$step->maxOutputs($this->maxOutputs);
}

$this->steps[] = $step;

return $this;
Expand Down Expand Up @@ -98,6 +102,17 @@ public function setLoader(LoaderInterface $loader): self
return $this;
}

public function maxOutputs(int $maxOutputs): static
{
parent::maxOutputs($maxOutputs);

foreach ($this->steps as $step) {
$step->maxOutputs($maxOutputs);
}

return $this;
}

public function outputType(): StepOutputType
{
return StepOutputType::AssociativeArrayOrObject;
Expand Down Expand Up @@ -144,6 +159,10 @@ private function addOutputToCombinedOutputs(
private function prepareCombinedOutputs(array $combinedOutputs, Input $input): Generator
{
foreach ($combinedOutputs as $combinedOutput) {
if ($this->maxOutputsExceeded()) {
break;
}

$outputData = $this->normalizeCombinedOutputs($combinedOutput);

$outputData = $this->applyRefiners($outputData, $input->get());
Expand All @@ -156,6 +175,8 @@ private function prepareCombinedOutputs(array $combinedOutputs, Input $input): G
}

yield $output;

$this->trackYieldedOutput();
}
}
}
Expand Down
27 changes: 1 addition & 26 deletions src/Steps/Step.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@ abstract class Step extends BaseStep

protected bool $excludeFromGroupOutput = false;

protected ?int $maxOutputs = null;

protected int $currentOutputCount = 0;

/**
* @return Generator<mixed>
*/
Expand Down Expand Up @@ -79,13 +75,6 @@ public function shouldOutputBeExcludedFromGroupOutput(): bool
return $this->excludeFromGroupOutput;
}

public function maxOutputs(int $maxOutputs): static
{
$this->maxOutputs = $maxOutputs;

return $this;
}

/**
* If the user set a callback to update the input (see above) => call it.
*/
Expand All @@ -100,13 +89,6 @@ public function callUpdateInputUsingOutput(Input $input, Output $output): Input
return $input;
}

public function resetAfterRun(): void
{
parent::resetAfterRun();

$this->currentOutputCount = 0;
}

/**
* Validate and sanitize the incoming Input object
*
Expand Down Expand Up @@ -235,17 +217,10 @@ private function invokeAndYield(mixed $validInputValue, Input $input): Generator

yield $output;

if ($this->maxOutputs !== null) {
$this->currentOutputCount += 1;
}
$this->trackYieldedOutput();
}
}

private function maxOutputsExceeded(): bool
{
return $this->maxOutputs !== null && $this->currentOutputCount >= $this->maxOutputs;
}

/**
* Sometimes there can be a so-called byte order mark character as first characters in a text file. See:
* https://stackoverflow.com/questions/53303571/why-does-the-filereader-stream-read-239-187-191-from-a-textfile
Expand Down
2 changes: 2 additions & 0 deletions src/Steps/StepInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,7 @@ public function orWhere(string|FilterInterface $keyOrFilter, ?FilterInterface $f

public function outputKey(string $key): static;

public function maxOutputs(int $maxOutputs): static;

public function resetAfterRun(): void;
}
75 changes: 74 additions & 1 deletion tests/Steps/GroupTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ protected function invoke(mixed $input): Generator
});

test(
'When defining keys for the steps as first param in addStep call, the combined output array has those keys',
'When defining keys for the steps via $step->outputKey(), the combined output array has those keys',
function () {
$step1 = helper_getValueReturningStep('ich');

Expand Down Expand Up @@ -789,3 +789,76 @@ function () {
expect($outputs[0]->get())->toBe(['yo' => 'lo']);
},
);

it('stops calling its steps and producing outputs when maxOutputs is reached', function () {
$step1 = new class extends Step {
public int $called = 0;

protected function invoke(mixed $input): Generator
{
yield ['foo' => 'one'];

$this->called++;
}
};

$step2 = new class extends Step {
public int $called = 0;

protected function invoke(mixed $input): Generator
{
yield ['bar' => 'two'];

$this->called++;
}
};

$group = (new Group())
->addStep($step1)
->addStep($step2)
->maxOutputs(2);

expect(helper_invokeStepWithInput($group, 'hey'))->toHaveCount(1)
->and(helper_invokeStepWithInput($group, 'ho'))->toHaveCount(1)
->and(helper_invokeStepWithInput($group, 'hey'))->toHaveCount(0)
->and($step1->called)->toBe(2)
->and($step2->called)->toBe(2);
});

it(
'also stops creating outputs when maxOutputs is reached, when maxOutputs() was called before addStep()',
function () {
$step1 = new class extends Step {
public int $called = 0;

protected function invoke(mixed $input): Generator
{
yield ['foo' => 'one'];

$this->called++;
}
};

$step2 = new class extends Step {
public int $called = 0;

protected function invoke(mixed $input): Generator
{
yield ['bar' => 'two'];

$this->called++;
}
};

$group = (new Group())
->maxOutputs(2)
->addStep($step1)
->addStep($step2);

expect(helper_invokeStepWithInput($group, 'hey'))->toHaveCount(1)
->and(helper_invokeStepWithInput($group, 'ho'))->toHaveCount(1)
->and(helper_invokeStepWithInput($group, 'hey'))->toHaveCount(0)
->and($step1->called)->toBe(2)
->and($step2->called)->toBe(2);
},
);

0 comments on commit 5856bea

Please sign in to comment.