Skip to content

Commit a49c568

Browse files
committed
Change of argument order in call() scalar method
1 parent 318c3b7 commit a49c568

File tree

9 files changed

+97
-23
lines changed

9 files changed

+97
-23
lines changed

documentation/upgrading.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,28 @@ Please follow the instructions for your specific version to ensure a smooth upgr
55

66
---
77

8+
## Upgrading from 0.27.x to 0.28.x
9+
10+
### 1) Change of argument order in `call()` scalar method, and enforcing string types for argument names
11+
12+
Before:
13+
```php
14+
ref('integers')->call(lit('explode'), ['separator' => ','], refAlias: 'string', returnType: type_list(type_integer()))
15+
ref('integers')->call(lit('explode'), ['separator' => ','])
16+
ref('integers')->call(lit('explode'), [','])
17+
ref('integers')->call(lit('count'))
18+
```
19+
20+
After:
21+
22+
```php
23+
ref('integers')->call(lit('explode'), refAlias: 'string', arguments: ['separator' => ','], returnType: type_list(type_integer()))
24+
ref('integers')->call(lit('explode'), refAlias: 'string', arguments: ['separator' => ','])
25+
ref('integers')->call(lit('explode'), arguments: [',']) // will return null or error in strict mode
26+
ref('integers')->call(lit('explode')) // will return null or error in strict mode
27+
ref('integers')->call(lit('count')) // will work same as before
28+
```
29+
830
## Upgrading from 0.26.x to 0.27.x
931

1032
### 1) Force `EntryFactory $entryFactory` to be required on `array_to_row` & `array_to_row(s)`

examples/topics/transformations/call/code.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
)
2424
->withEntry(
2525
'integers',
26-
ref('integers')->call(lit('explode'), ['separator' => ','], refAlias: 'string', returnType: type_list(type_integer()))
26+
ref('integers')->call(lit('explode'), refAlias: 'string', arguments: ['separator' => ','], returnType: type_list(type_integer()))
2727
)
2828
->write(to_stream(__DIR__ . '/output.txt', truncate: false))
2929
->run();

src/core/etl/src/Flow/ETL/DSL/functions.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1373,13 +1373,16 @@ function count(?EntryReference $function = null) : Count
13731373
/**
13741374
* Calls a user-defined function with the given parameters.
13751375
*
1376-
* @param callable|ScalarFunction $callable
1377-
* @param array<mixed> $parameters
1376+
* @param array<string, mixed> $parameters
13781377
* @param null|Type<mixed> $return_type
13791378
*/
13801379
#[DocumentationDSL(module: Module::CORE, type: DSLType::SCALAR_FUNCTION)]
13811380
function call(ScalarFunction|callable $callable, array $parameters = [], ?Type $return_type = null) : CallUserFunc
13821381
{
1382+
if ([] !== $parameters && \array_is_list($parameters)) {
1383+
throw new InvalidArgumentException('call arguments cannot be a list');
1384+
}
1385+
13831386
return new CallUserFunc($callable, $parameters, $return_type);
13841387
}
13851388

src/core/etl/src/Flow/ETL/Function/CallUserFunc.php

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@ final class CallUserFunc extends ScalarFunctionChain
1717
private $callable;
1818

1919
/**
20-
* @param callable|ScalarFunction $callable
21-
* @param array<mixed> $parameters
20+
* @param array<array-key, mixed> $parameters
2221
* @param null|Type<mixed> $returnType
2322
*/
2423
public function __construct(ScalarFunction|callable $callable, private readonly array $parameters, private readonly ?Type $returnType = null)
@@ -40,13 +39,17 @@ public function eval(Row $row, FlowContext $context) : mixed
4039
$parameters[$key] = (new Parameter($parameter))->eval($row, $context);
4140
}
4241

43-
if ($this->returnType) {
44-
return new ScalarResult(
45-
\call_user_func($callable, ...$parameters),
46-
$this->returnType
47-
);
42+
try {
43+
if ($this->returnType) {
44+
return new ScalarResult(
45+
\call_user_func($callable, ...$parameters),
46+
$this->returnType
47+
);
48+
}
49+
50+
return \call_user_func($callable, ...$parameters);
51+
} catch (\ArgumentCountError $e) {
52+
return $context->functions()->invalidResult(new InvalidArgumentException($e->getMessage(), $e->getCode(), $e));
4853
}
49-
50-
return \call_user_func($callable, ...$parameters);
5154
}
5255
}

src/core/etl/src/Flow/ETL/Function/ScalarFunctionChain.php

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,12 +152,22 @@ public function binaryLength() : BinaryLength
152152
}
153153

154154
/**
155-
* @param array<array-key, mixed> $arguments
156-
* @param Type<mixed> $returnType
155+
* @param array<string, mixed> $arguments
156+
* @param null|Type<mixed> $returnType
157157
*/
158-
public function call(ScalarFunction|callable $callable, array $arguments = [], string|int $refAlias = 0, ?Type $returnType = null) : CallUserFunc
158+
public function call(ScalarFunction|callable $callable, ?string $refAlias = null, array $arguments = [], ?Type $returnType = null) : CallUserFunc
159159
{
160-
return new CallUserFunc($callable, array_merge($arguments, [$refAlias => $this]), $returnType);
160+
if ([] !== $arguments && \array_is_list($arguments)) {
161+
throw new InvalidArgumentException('call arguments cannot be a list');
162+
}
163+
164+
if ($refAlias === null && [] === $arguments) {
165+
$arguments = [$this];
166+
} else {
167+
$arguments[$refAlias] = $this;
168+
}
169+
170+
return new CallUserFunc($callable, $arguments, $returnType);
161171
}
162172

163173
public function capitalize() : Capitalize

src/core/etl/tests/Flow/ETL/Tests/Integration/Function/CallUserFuncTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public function test_call() : void
2323
)
2424
->withEntry(
2525
'integers',
26-
ref('integers')->call(lit('explode'), ['separator' => ','], refAlias: 'string', returnType: type_list(type_integer()))
26+
ref('integers')->call(lit('explode'), refAlias: 'string', arguments: ['separator' => ','], returnType: type_list(type_integer()))
2727
)
2828
->write(to_memory($memory = new ArrayMemory()))
2929
->run();

src/core/etl/tests/Flow/ETL/Tests/Unit/Function/CallUserFuncTest.php

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@
66

77
use function Flow\ETL\DSL\{call, flow_context, list_entry, lit, ref, row, string_entry};
88
use function Flow\Types\DSL\{type_integer, type_list};
9+
use Flow\ETL\Exception\InvalidArgumentException;
910
use Flow\ETL\Function\ScalarFunction\ScalarResult;
10-
use Flow\ETL\Tests\FlowTestCase;
1111
use Flow\ETL\Tests\Unit\Function\Fixtures\CallUserFunc\StaticCalculator;
12+
use PHPUnit\Framework\TestCase;
1213

13-
final class CallUserFuncTest extends FlowTestCase
14+
final class CallUserFuncTest extends TestCase
1415
{
1516
public function test_call_user_func_as_dsl() : void
1617
{
@@ -31,6 +32,41 @@ public function test_call_user_func_with_native_function() : void
3132
);
3233
}
3334

35+
public function test_call_user_func_with_native_function_and_no_arguments() : void
36+
{
37+
$row = row(
38+
list_entry('list', [1, 2, 3], type_list(type_integer())),
39+
);
40+
41+
self::assertNull(
42+
ref('list')
43+
->call(lit('time'))
44+
->eval($row, flow_context())
45+
);
46+
}
47+
48+
public function test_call_user_func_with_non_callable_function() : void
49+
{
50+
$row = row(
51+
list_entry('list', [1, 2, 3], type_list(type_integer())),
52+
);
53+
54+
self::assertNull(
55+
ref('list')
56+
->call(lit('unknown'), 'whatever')
57+
->eval($row, flow_context())
58+
);
59+
}
60+
61+
public function test_call_user_func_with_non_string_argument_keys() : void
62+
{
63+
$this->expectException(InvalidArgumentException::class);
64+
$this->expectExceptionMessage('call arguments cannot be a list');
65+
66+
ref('list')
67+
->call(lit('explode'), refAlias: 'string', arguments: [',']); // @phpstan-ignore argument.type
68+
}
69+
3470
public function test_call_user_func_with_object_method() : void
3571
{
3672
$row = row(
@@ -56,7 +92,7 @@ public function test_call_user_func_with_ref_alias_and_optional_arguments() : vo
5692
self::assertSame(
5793
['1', '2', '3'],
5894
ref('item_ids')
59-
->call(lit('explode'), ['separator' => ','], refAlias: 'string')
95+
->call(lit('explode'), refAlias: 'string', arguments: ['separator' => ','])
6096
->eval($row, flow_context())
6197
);
6298
}
@@ -70,7 +106,7 @@ public function test_call_user_func_with_ref_alias_and_optional_arguments_and_re
70106
self::assertEquals(
71107
new ScalarResult([1, 2, 3], type_list(type_integer())),
72108
ref('item_ids')
73-
->call(lit('explode'), ['separator' => ','], refAlias: 'string', returnType: type_list(type_integer()))
109+
->call(lit('explode'), refAlias: 'string', arguments: ['separator' => ','], returnType: type_list(type_integer()))
74110
->eval($row, flow_context())
75111
);
76112
}

web/landing/resources/api.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

web/landing/resources/dsl.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)