Skip to content

Commit a5dad12

Browse files
authored
Merge branch 'master' into feature/400-delete-namespace
2 parents 8de011d + a773a0d commit a5dad12

86 files changed

Lines changed: 6596 additions & 196 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

psalm-baseline.xml

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<files psalm-version="6.14.3@d0b040a91f280f071c1abcb1b77ce3822058725a">
2+
<files psalm-version="6.16.0@7cf3e8b988edd75e0766963b0b9e671b220f5785">
33
<file src="src/Activity/ActivityInterface.php">
44
<DeprecatedClass>
55
<code><![CDATA[NamedArgumentConstructor]]></code>
@@ -134,15 +134,9 @@
134134
<code><![CDATA[object]]></code>
135135
<code><![CDATA[object]]></code>
136136
</InvalidReturnType>
137-
<LessSpecificReturnStatement>
138-
<code><![CDATA[new self($serviceClient, $options, $converter, $interceptorProvider)]]></code>
139-
</LessSpecificReturnStatement>
140137
<MissingParamType>
141138
<code><![CDATA[$workflow]]></code>
142139
</MissingParamType>
143-
<MoreSpecificReturnType>
144-
<code><![CDATA[static]]></code>
145-
</MoreSpecificReturnType>
146140
<RedundantFunctionCall>
147141
<code><![CDATA[\sprintf]]></code>
148142
<code><![CDATA[\sprintf]]></code>
@@ -711,18 +705,21 @@
711705
<file src="src/Internal/Marshaller/Type/ArrayType.php">
712706
<MoreSpecificImplementedParamType>
713707
<code><![CDATA[$current]]></code>
714-
<code><![CDATA[$value]]></code>
715708
</MoreSpecificImplementedParamType>
716709
</file>
717710
<file src="src/Internal/Marshaller/Type/DateIntervalType.php">
718711
<ArgumentTypeCoercion>
719712
<code><![CDATA[$this->format]]></code>
720713
<code><![CDATA[$this->format]]></code>
721714
</ArgumentTypeCoercion>
715+
<DeprecatedConstant>
716+
<code><![CDATA[DateInterval::FORMAT_MONTHS]]></code>
717+
<code><![CDATA[DateInterval::FORMAT_YEARS]]></code>
718+
</DeprecatedConstant>
722719
<InvalidOperand>
720+
<code><![CDATA[$interval->totalMicroseconds * 1000]]></code>
723721
<code><![CDATA[$value * 1000000000]]></code>
724722
<code><![CDATA[($value * 1000000000) % 1000000000]]></code>
725-
<code><![CDATA[DateInterval::parse($value, $this->format)->totalMicroseconds * 1000]]></code>
726723
</InvalidOperand>
727724
</file>
728725
<file src="src/Internal/Marshaller/Type/DurationJsonType.php">
@@ -731,15 +728,6 @@
731728
<code><![CDATA[($value * 1000000000) % 1000000000]]></code>
732729
</InvalidOperand>
733730
</file>
734-
<file src="src/Internal/Marshaller/Type/EnumType.php">
735-
<PropertyTypeCoercion>
736-
<code><![CDATA[$class]]></code>
737-
</PropertyTypeCoercion>
738-
<UndefinedMethod>
739-
<code><![CDATA[$this->classFQCN::from($value)]]></code>
740-
<code><![CDATA[$this->classFQCN::from($value['value'])]]></code>
741-
</UndefinedMethod>
742-
</file>
743731
<file src="src/Internal/Marshaller/Type/ObjectType.php">
744732
<InvalidPropertyAssignmentValue>
745733
<code><![CDATA[new \ReflectionClass($class ?? \stdClass::class)]]></code>
@@ -753,11 +741,6 @@
753741
<code><![CDATA[TClass]]></code>
754742
</InvalidReturnType>
755743
</file>
756-
<file src="src/Internal/Marshaller/Type/OneOfType.php">
757-
<InvalidReturnType>
758-
<code><![CDATA[array]]></code>
759-
</InvalidReturnType>
760-
</file>
761744
<file src="src/Internal/Marshaller/Type/Type.php">
762745
<ArgumentTypeCoercion>
763746
<code><![CDATA[$typeClass]]></code>
@@ -1357,6 +1340,8 @@
13571340
$converter ?? DataConverter::createDefault(),
13581341
$rpc ?? Goridge::create(),
13591342
$credentials,
1343+
$pluginRegistry,
1344+
$client,
13601345
)]]></code>
13611346
</UnsafeInstantiation>
13621347
</file>
@@ -1411,6 +1396,12 @@
14111396
<code><![CDATA[$response->toArray()['assets']]]></code>
14121397
</PossiblyUndefinedStringArrayOffset>
14131398
</file>
1399+
<file src="testing/src/Environment.php">
1400+
<PossiblyNullReference>
1401+
<code><![CDATA[stop]]></code>
1402+
<code><![CDATA[stop]]></code>
1403+
</PossiblyNullReference>
1404+
</file>
14141405
<file src="testing/src/Replay/WorkflowReplayer.php">
14151406
<UndefinedMethod>
14161407
<code><![CDATA[getWorkflowType]]></code>

src/Client/ScheduleClient.php

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@
3232
use Temporal\DataConverter\DataConverter;
3333
use Temporal\DataConverter\DataConverterInterface;
3434
use Temporal\Internal\Mapper\ScheduleMapper;
35+
use Temporal\Internal\Interceptor\Pipeline;
36+
use Temporal\Plugin\ConnectionPluginInterface;
37+
use Temporal\Plugin\PluginRegistry;
38+
use Temporal\Plugin\ScheduleClientPluginContext;
39+
use Temporal\Plugin\ScheduleClientPluginInterface;
3540
use Temporal\Internal\Marshaller\Mapper\AttributeMapperFactory;
3641
use Temporal\Internal\Marshaller\Marshaller;
3742
use Temporal\Internal\Marshaller\MarshallerInterface;
@@ -45,14 +50,39 @@ final class ScheduleClient implements ScheduleClientInterface
4550
private DataConverterInterface $converter;
4651
private MarshallerInterface $marshaller;
4752
private ProtoToArrayConverter $protoConverter;
53+
private PluginRegistry $pluginRegistry;
4854

4955
public function __construct(
5056
ServiceClientInterface $serviceClient,
5157
?ClientOptions $options = null,
5258
?DataConverterInterface $converter = null,
59+
?PluginRegistry $pluginRegistry = null,
5360
) {
5461
$this->clientOptions = $options ?? new ClientOptions();
5562
$this->converter = $converter ?? DataConverter::createDefault();
63+
$this->pluginRegistry = $pluginRegistry ?? new PluginRegistry();
64+
65+
// Apply connection plugins (before client-level configuration)
66+
$connectionPlugins = $this->pluginRegistry->getPlugins(ConnectionPluginInterface::class);
67+
$serviceClient = Pipeline::prepare($connectionPlugins)
68+
/** @see ConnectionPluginInterface::configureServiceClient() */
69+
->with(static fn(ServiceClientInterface $serviceClient) => $serviceClient, 'configureServiceClient')($serviceClient);
70+
71+
$pluginContext = new ScheduleClientPluginContext(
72+
clientOptions: $this->clientOptions,
73+
dataConverter: $this->converter,
74+
);
75+
$schedulePlugins = $this->pluginRegistry->getPlugins(ScheduleClientPluginInterface::class);
76+
/** @see ScheduleClientPluginInterface::configureScheduleClient() */
77+
Pipeline::prepare($schedulePlugins)
78+
->with(static fn() => null, 'configureScheduleClient')($pluginContext);
79+
80+
$this->clientOptions = $pluginContext->getClientOptions();
81+
$pluginConverter = $pluginContext->getDataConverter();
82+
if ($pluginConverter !== null) {
83+
$this->converter = $pluginConverter;
84+
}
85+
5686
$this->marshaller = new Marshaller(
5787
new AttributeMapperFactory(new AttributeReader()),
5888
);
@@ -71,8 +101,9 @@ public static function create(
71101
ServiceClientInterface $serviceClient,
72102
?ClientOptions $options = null,
73103
?DataConverterInterface $converter = null,
104+
?PluginRegistry $pluginRegistry = null,
74105
): ScheduleClientInterface {
75-
return new self($serviceClient, $options, $converter);
106+
return new self($serviceClient, $options, $converter, $pluginRegistry);
76107
}
77108

78109
public function createSchedule(

src/Client/WorkflowClient.php

Lines changed: 61 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,13 @@
3838
use Temporal\Interceptor\WorkflowClientCallsInterceptor;
3939
use Temporal\Internal\Client\ActivityCompletionClient;
4040
use Temporal\Internal\Client\WorkflowProxy;
41+
use Temporal\Plugin\ClientPluginContext;
42+
use Temporal\Plugin\ClientPluginInterface;
43+
use Temporal\Plugin\CompositePipelineProvider;
44+
use Temporal\Plugin\ConnectionPluginInterface;
45+
use Temporal\Plugin\PluginRegistry;
46+
use Temporal\Plugin\ScheduleClientPluginInterface;
47+
use Temporal\Plugin\WorkerPluginInterface;
4148
use Temporal\Internal\Client\WorkflowRun;
4249
use Temporal\Internal\Client\WorkflowStarter;
4350
use Temporal\Internal\Client\WorkflowStub;
@@ -63,6 +70,7 @@ class WorkflowClient implements WorkflowClientInterface
6370
private DataConverterInterface $converter;
6471
private ?WorkflowStarter $starter = null;
6572
private WorkflowReader $reader;
73+
private PluginRegistry $pluginRegistry;
6674

6775
/** @var Pipeline<WorkflowClientCallsInterceptor, mixed> */
6876
private Pipeline $interceptorPipeline;
@@ -72,11 +80,40 @@ public function __construct(
7280
?ClientOptions $options = null,
7381
?DataConverterInterface $converter = null,
7482
?PipelineProvider $interceptorProvider = null,
83+
?PluginRegistry $pluginRegistry = null,
7584
) {
76-
$this->interceptorPipeline = ($interceptorProvider ?? new SimplePipelineProvider())
77-
->getPipeline(WorkflowClientCallsInterceptor::class);
85+
$this->pluginRegistry = $pluginRegistry ?? new PluginRegistry();
7886
$this->clientOptions = $options ?? new ClientOptions();
7987
$this->converter = $converter ?? DataConverter::createDefault();
88+
89+
// Apply connection plugins (before client-level configuration)
90+
$connectionPlugins = $this->pluginRegistry->getPlugins(ConnectionPluginInterface::class);
91+
$serviceClient = Pipeline::prepare($connectionPlugins)
92+
/** @see ConnectionPluginInterface::configureServiceClient() */
93+
->with(static fn(ServiceClientInterface $serviceClient) => $serviceClient, 'configureServiceClient')($serviceClient);
94+
95+
$pluginContext = new ClientPluginContext(
96+
clientOptions: $this->clientOptions,
97+
dataConverter: $this->converter,
98+
);
99+
$clientPlugins = $this->pluginRegistry->getPlugins(ClientPluginInterface::class);
100+
Pipeline::prepare($clientPlugins)
101+
/** @see ClientPluginInterface::configureClient() */
102+
->with(static fn(ClientPluginContext $pluginContext) => $pluginContext, 'configureClient')($pluginContext);
103+
104+
$this->clientOptions = $pluginContext->getClientOptions();
105+
$pluginConverter = $pluginContext->getDataConverter();
106+
if ($pluginConverter !== null) {
107+
$this->converter = $pluginConverter;
108+
}
109+
110+
// Build interceptor pipeline: merge plugin-contributed interceptors with user-provided ones
111+
$provider = new CompositePipelineProvider(
112+
$pluginContext->getInterceptors(),
113+
$interceptorProvider ?? new SimplePipelineProvider(),
114+
);
115+
116+
$this->interceptorPipeline = $provider->getPipeline(WorkflowClientCallsInterceptor::class);
80117
$this->reader = new WorkflowReader($this->createReader());
81118

82119
// Set Temporal-Namespace metadata
@@ -88,16 +125,34 @@ public function __construct(
88125
);
89126
}
90127

91-
/**
92-
* @return static
93-
*/
94128
public static function create(
95129
ServiceClientInterface $serviceClient,
96130
?ClientOptions $options = null,
97131
?DataConverterInterface $converter = null,
98132
?PipelineProvider $interceptorProvider = null,
133+
?PluginRegistry $pluginRegistry = null,
99134
): self {
100-
return new self($serviceClient, $options, $converter, $interceptorProvider);
135+
return new self($serviceClient, $options, $converter, $interceptorProvider, $pluginRegistry);
136+
}
137+
138+
/**
139+
* Get plugins that also implement WorkerPluginInterface for propagation to workers.
140+
*
141+
* @return list<WorkerPluginInterface>
142+
*/
143+
public function getWorkerPlugins(): array
144+
{
145+
return $this->pluginRegistry->getPlugins(WorkerPluginInterface::class);
146+
}
147+
148+
/**
149+
* Get plugins that also implement ScheduleClientPluginInterface for propagation to schedule clients.
150+
*
151+
* @return list<ScheduleClientPluginInterface>
152+
*/
153+
public function getScheduleClientPlugins(): array
154+
{
155+
return $this->pluginRegistry->getPlugins(ScheduleClientPluginInterface::class);
101156
}
102157

103158
public function getServiceClient(): ServiceClientInterface

src/Interceptor/SimplePipelineProvider.php

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,28 @@ class SimplePipelineProvider implements PipelineProvider
2222
* @param array<array-key, Interceptor> $interceptors
2323
*/
2424
public function __construct(
25-
private iterable $interceptors = [],
25+
private readonly iterable $interceptors = [],
2626
) {}
2727

28+
/**
29+
* Create a new provider with additional interceptors prepended.
30+
*
31+
* @param list<Interceptor> $interceptors Interceptors to prepend before existing ones.
32+
*/
33+
public function withPrependedInterceptors(array $interceptors): self
34+
{
35+
if ($interceptors === []) {
36+
return $this;
37+
}
38+
39+
return new self(\array_merge($interceptors, [...$this->interceptors]));
40+
}
41+
2842
public function getPipeline(string $interceptorClass): Pipeline
2943
{
3044
return $this->cache[$interceptorClass] ??= Pipeline::prepare(
3145
\array_filter(
32-
$this->interceptors,
46+
[...$this->interceptors],
3347
static fn(Interceptor $i): bool => $i instanceof $interceptorClass,
3448
),
3549
);

src/Internal/Interceptor/Pipeline.php

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ private function __construct(
5353
/**
5454
* Make sure that interceptors implement the same interface.
5555
*
56-
* @template T of Interceptor
56+
* @template T of object
5757
*
5858
* @param iterable<T> $interceptors
5959
*
@@ -64,6 +64,21 @@ public static function prepare(iterable $interceptors): self
6464
return new self($interceptors);
6565
}
6666

67+
/**
68+
* Merge two pipelines into one. Interceptors from the first pipeline run before the second.
69+
*
70+
* @template T of object
71+
*
72+
* @param self<T, mixed> $first
73+
* @param self<T, mixed> $second
74+
*
75+
* @return self<T, mixed>
76+
*/
77+
public static function merge(self $first, self $second): self
78+
{
79+
return new self([...$first->interceptors, ...$second->interceptors]);
80+
}
81+
6782
/**
6883
* @param non-empty-string $method Method name of the all interceptors.
6984
*

src/Internal/Marshaller/Type/ActivityCancellationType.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
* Converts a boolean value to an activity cancellation policy.
1111
*
1212
* @see Policy
13-
* @extends Type<bool>
13+
* @extends Type<bool, int>
1414
* @internal
1515
*/
1616
final class ActivityCancellationType extends Type

src/Internal/Marshaller/Type/ArrayType.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
use Temporal\Internal\Marshaller\MarshallingRule;
1616

1717
/**
18-
* @extends Type<array>
18+
* @extends Type<array, array>
1919
*/
2020
class ArrayType extends Type implements DetectableTypeInterface, RuleFactoryInterface
2121
{
@@ -57,7 +57,6 @@ public static function makeRule(\ReflectionProperty $property): ?MarshallingRule
5757
}
5858

5959
/**
60-
* @psalm-assert array $value
6160
* @param mixed $value
6261
* @param array $current
6362
*/

src/Internal/Marshaller/Type/AssocArrayType.php

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
/**
1818
* Force the value to be an associative array (object) on serialization.
1919
*
20-
* @extends Type<object>
20+
* @extends Type<object, mixed>
2121
*/
2222
class AssocArrayType extends Type
2323
{
@@ -40,17 +40,13 @@ public function __construct(MarshallerInterface $marshaller, MarshallingRule|str
4040
parent::__construct($marshaller);
4141
}
4242

43-
/**
44-
* @psalm-assert array $value
45-
* @psalm-assert array $current
46-
* @param mixed $value
47-
* @param mixed $current
48-
*/
4943
public function parse($value, $current): array
5044
{
51-
\is_array($value) or throw new \InvalidArgumentException(
52-
\sprintf(self::ERROR_INVALID_TYPE, \get_debug_type($value)),
53-
);
45+
if (!\is_array($value)) {
46+
throw new \InvalidArgumentException(
47+
\sprintf(self::ERROR_INVALID_TYPE, \get_debug_type($value)),
48+
);
49+
}
5450

5551
if ($this->type) {
5652
$result = [];

src/Internal/Marshaller/Type/ChildWorkflowCancellationType.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*
1212
* @see Policy
1313
*
14-
* @extends Type<bool>
14+
* @extends Type<bool, int>
1515
* @internal
1616
*/
1717
final class ChildWorkflowCancellationType extends Type

0 commit comments

Comments
 (0)