Skip to content

Commit 82b10ce

Browse files
committed
Allow initial value casting
1 parent 10240fa commit 82b10ce

File tree

3 files changed

+68
-16
lines changed

3 files changed

+68
-16
lines changed

README.md

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ echo $pipeline->applyTo('foo '); // 'foo I am the context I am the context'
112112

113113
## DTO "freshness"
114114

115-
Everytime `Pipeline::applyTo()` is called on same Pipeline instance, DTO instance passed to callbacks
115+
Every time `Pipeline::applyTo()` is called on same Pipeline instance, DTO instance passed to callbacks
116116
is a *fresh* one, i.e. DTO state is not maintained across `applyTo()` calls.
117117

118118
Only `DTO::context()` returns the same value because it is set at Pipeline level.
@@ -169,7 +169,21 @@ $pipeline = (new Pipeline(null, Pipeline::TO_ARRAY))
169169
return $pipeline->applyTo('foo'); // ['foo', 'bar']
170170
```
171171

172-
Note that value received by 1st callback is not returned by any callback, so it is not type casted.
172+
Note that, by default, initial value *passed to* 1st callback, is **not** type casted (but its *returning value* is).
173+
174+
However, it's also possible to type cast even the initial value before it is passed to first callback.
175+
That can be done by passing `true` as 3rd argument to Pipeline constructor.
176+
177+
```php
178+
use Toobo\PipePie\Pipeline;
179+
180+
$pipeline = (new Pipeline(null, Pipeline::TO_ARRAY, true))
181+
->pipe(function (array $carry) { // Even 1st callback receives type-casted value
182+
return $carry;
183+
});
184+
185+
return $pipeline->applyTo('foo'); // ['foo']
186+
```
173187

174188

175189
### Type Casting via Custom Callback
@@ -321,8 +335,8 @@ return $pipeline->info();
321335

322336
Note that:
323337

324-
- informations on various `applyTo()` calls, are shown in inverse chronological order: later calls are shown first;
325-
- an `info()` call *flushes* informations, so on subsequent calls the method returns only data for `applyTo()` calls
338+
- information on various `applyTo()` calls, are shown in inverse chronological order: later calls are shown first;
339+
- an `info()` call *flushes* information, so on subsequent calls the method returns only data for `applyTo()` calls
326340
happened since last `info()` call.
327341

328342
## Requirements

src/Pipeline.php

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ class Pipeline
4242
*/
4343
private $caster;
4444

45+
/**
46+
* @var bool
47+
*/
48+
private $castFirst;
49+
4550
/**
4651
* @var bool
4752
*/
@@ -58,18 +63,20 @@ class Pipeline
5863
private $DTOs;
5964

6065
/**
61-
* @param mixed $context Something that can be accessed with $dto->context()
62-
* acting as context for all the callbacks
63-
* @param int|callable|null $caster Values returned by any of pipeline callbacks can be
64-
* casted using a class constants or a custom callback
66+
* @param mixed $context Something that can be accessed with $dto->context()
67+
* acting as context for all the callbacks
68+
* @param int|callable|null $caster Values returned by any of pipeline callbacks can be
69+
* casted using a class constants or a custom callback
70+
* @param bool $castFirst Should initial value should be casted?
6571
*/
66-
public function __construct($context = null, $caster = null)
72+
public function __construct($context = null, $caster = null, $castFirst = false)
6773
{
6874
$this->pipeline = new SplObjectStorage();
6975
if (is_int($caster) && array_key_exists($caster, self::$casters_map)) {
7076
$caster = [$this, self::$casters_map[$caster]];
7177
}
7278
$this->caster = is_callable($caster) ? $caster : null;
79+
$this->castFirst = $this->toBool($castFirst);
7380
$this->context = $context;
7481
$this->DTOs = new SplStack();
7582
$this->locked = false;
@@ -121,7 +128,7 @@ public function applyTo($initial, DTO $dto = null, $cursor = null)
121128
return $initial;
122129
}
123130
$this->DTOs->push($this->init($dto, $initial));
124-
$carry = is_null($cursor) ? $initial : $this->maybeCast($cursor);
131+
$carry = $this->initialValue($initial, $cursor);
125132
while ($this->pipeline->valid()) {
126133
$carry = $this->run($initial, $carry);
127134
$this->pipeline->next();
@@ -198,6 +205,22 @@ private function init(DTO $dto = null, $initial = null)
198205
return $dto;
199206
}
200207

208+
/**
209+
* Setup initial value for Pipeline based on caster settings.
210+
*
211+
* @param mixed $initial
212+
* @param mixed $cursor
213+
* @return mixed
214+
*/
215+
private function initialValue($initial, $cursor)
216+
{
217+
if (! is_null($cursor)) {
218+
return $this->maybeCast($cursor);
219+
}
220+
221+
return $this->castFirst ? $this->maybeCast($initial) : $initial;
222+
}
223+
201224
/**
202225
* Run current callback in the pipeline.
203226
*
@@ -223,6 +246,12 @@ private function run($initial, $carry)
223246
*
224247
* @param mixed $data
225248
* @return mixed
249+
* @uses \Toobo\PipePie\Pipeline::toArray()
250+
* @uses \Toobo\PipePie\Pipeline::toObject()
251+
* @uses \Toobo\PipePie\Pipeline::toString()
252+
* @uses \Toobo\PipePie\Pipeline::toInt()
253+
* @uses \Toobo\PipePie\Pipeline::toBool()
254+
* @uses \Toobo\PipePie\Pipeline::toFloat()
226255
*/
227256
private function maybeCast($data)
228257
{

tests/PHPUnit/PipelineTest.php

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
class PipelineTest extends PHPUnit_Framework_TestCase
88
{
99
/**
10-
* @expectedException LogicException
10+
* @expectedException \LogicException
1111
*/
1212
public function testPipeFailsIfWorking()
1313
{
@@ -22,7 +22,7 @@ public function testPipeFailsIfWorking()
2222
}
2323

2424
/**
25-
* @expectedException LogicException
25+
* @expectedException \LogicException
2626
*/
2727
public function testPipeFailsIfLocked()
2828
{
@@ -44,7 +44,7 @@ public function testApplyDoNothingIfNoCallbacks()
4444
}
4545

4646
/**
47-
* @expectedException LogicException
47+
* @expectedException \LogicException
4848
*/
4949
public function testApplyFailsIfWorking()
5050
{
@@ -161,6 +161,15 @@ public function testApplyCustomCaster()
161161
assertSame([0, 1, 2, 3, 4], $pipeline->applyTo(['foo' => 0, 'bar' => 'baz']));
162162
}
163163

164+
public function testApplyCasterFirstItem()
165+
{
166+
$pipeline = new Pipeline(null, Pipeline::TO_OBJECT, true);
167+
$pipeline->pipe(function (\stdClass $carry) {
168+
return $carry;
169+
});
170+
assertEquals((object) ['baz' => 'baz'], $pipeline->applyTo(['baz' => 'baz']));
171+
}
172+
164173
public function testApplyMoreArgs()
165174
{
166175
$pipeline = new Pipeline();
@@ -186,7 +195,7 @@ public function testApplyCustomDTO()
186195
}
187196

188197
/**
189-
* @expectedException LogicException
198+
* @expectedException \LogicException
190199
*/
191200
public function testApplyCustomDTOFailsIfWrongInput()
192201
{
@@ -249,7 +258,7 @@ public function testDTOisSharedInNestedPipelines()
249258
}
250259

251260
/**
252-
* @expectedException LogicException
261+
* @expectedException \LogicException
253262
*/
254263
public function testInfoFailsIfWorking()
255264
{
@@ -264,7 +273,7 @@ public function testInfoFailsIfWorking()
264273
public function testInfo()
265274
{
266275
$pipeline = new Pipeline('I am the context');
267-
$pipeline->pipe(function ($carry, $initial, $dto) {
276+
$pipeline->pipe(function ($carry, $initial, DTO $dto) {
268277
$dto['called'] = 1;
269278

270279
return $carry.$initial.$dto->context();

0 commit comments

Comments
 (0)