Skip to content

Commit 60a0c66

Browse files
authored
Skip magic methods in Activity classes (#572)
1 parent 347e344 commit 60a0c66

File tree

6 files changed

+88
-52
lines changed

6 files changed

+88
-52
lines changed

src/Internal/Declaration/Reader/ActivityReader.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,10 @@ private function getMethodGroups(ClassNode $graph, \ReflectionMethod $root): arr
139139
continue;
140140
}
141141

142+
if ($attribute === null && $this->isMagic($method)) {
143+
continue;
144+
}
145+
142146
//
143147
// The name of the activity must be generated based on the
144148
// optional prefix on the #[ActivityInterface] attribute and

src/Internal/Declaration/Reader/Reader.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@
1818
*/
1919
abstract class Reader
2020
{
21+
private const MAGIC_METHODS = [
22+
'__construct', '__destruct', '__call', '__callStatic', '__get', '__set', '__isset', '__unset', '__sleep',
23+
'__wakeup', '__serialize', '__unserialize', '__toString', '__invoke', '__set_state', '__clone', '__debugInfo',
24+
];
25+
2126
protected ReaderInterface $reader;
2227

2328
public function __construct(ReaderInterface $reader)
@@ -35,4 +40,9 @@ protected function isValidMethod(\ReflectionMethod $method): bool
3540
{
3641
return !$method->isStatic() && $method->isPublic();
3742
}
43+
44+
protected function isMagic(\ReflectionMethod $method): bool
45+
{
46+
return \in_array($method->getName(), self::MAGIC_METHODS, true);
47+
}
3848
}

tests/Unit/Activity/ActivityPrototypeTestCase.php

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,17 @@
99
use Spiral\Attributes\Composite\SelectiveReader;
1010
use Temporal\Internal\Declaration\Reader\ActivityReader;
1111
use Temporal\Tests\Unit\AbstractUnit;
12-
use WeakReference;
1312

1413
final class ActivityPrototypeTestCase extends AbstractUnit
1514
{
1615
private ActivityReader $activityReader;
1716

18-
protected function setUp(): void
17+
public function testNoMagicMethods(): void
1918
{
20-
$this->activityReader = new ActivityReader(new SelectiveReader([new AnnotationReader(), new AttributeReader()]));
21-
parent::setUp();
19+
$protos = $this->activityReader->fromClass(MagicActivity::class);
20+
21+
self::assertCount(1, $protos);
22+
self::assertSame('MagicActivity.Do', $protos[0]->getID());
2223
}
2324

2425
public function testInstanceLeaks(): void
@@ -27,11 +28,11 @@ public function testInstanceLeaks(): void
2728
$proto = $this->activityReader
2829
->fromClass(DummyActivity::class)[0];
2930

30-
$refProto = WeakReference::create($proto);
31-
$refInstance = WeakReference::create($proto->getInstance());
32-
$refHandler = WeakReference::create($proto->getHandler());
33-
$refInstanceHandler = WeakReference::create($proto->getInstance()->getHandler());
34-
$refActivity = WeakReference::create($proto->getInstance()->getContext());
31+
$refProto = \WeakReference::create($proto);
32+
$refInstance = \WeakReference::create($proto->getInstance());
33+
$refHandler = \WeakReference::create($proto->getHandler());
34+
$refInstanceHandler = \WeakReference::create($proto->getInstance()->getHandler());
35+
$refActivity = \WeakReference::create($proto->getInstance()->getContext());
3536

3637
unset($proto, $instance);
3738

@@ -49,8 +50,8 @@ public function testProtoWithInstanceImmutabilityAndLeaks(): void
4950
->fromClass(DummyActivity::class)[0];
5051
$newProto = $proto->withInstance($instance);
5152
// References
52-
$refProto = WeakReference::create($proto);
53-
$refNewProto = WeakReference::create($newProto);
53+
$refProto = \WeakReference::create($proto);
54+
$refNewProto = \WeakReference::create($newProto);
5455

5556
// New object is result of clone operation
5657
$this->assertNotSame($proto, $newProto);
@@ -80,7 +81,7 @@ public function testGetInstanceFromClass(): void
8081
public function testGetInstanceFromFactory(): void
8182
{
8283
$proto = $this->activityReader->fromClass(DummyActivity::class)[0];
83-
$protoWithFactory = $proto->withFactory(fn () => new DummyActivity());
84+
$protoWithFactory = $proto->withFactory(static fn() => new DummyActivity());
8485

8586
$this->assertInstanceOf(DummyActivity::class, $protoWithFactory->getInstance()->getContext());
8687
}
@@ -97,7 +98,7 @@ public function testLocalActivityFlag(): void
9798
public function testFactoryCreatesNewInstances(): void
9899
{
99100
$proto = $this->activityReader->fromClass(DummyActivity::class)[0];
100-
$protoWithFactory = $proto->withFactory(fn () => new DummyActivity());
101+
$protoWithFactory = $proto->withFactory(static fn() => new DummyActivity());
101102

102103
$this->assertEquals($protoWithFactory->getInstance()->getContext(), $protoWithFactory->getInstance()->getContext());
103104
$this->assertNotSame($protoWithFactory->getInstance()->getContext(), $protoWithFactory->getInstance()->getContext());
@@ -106,7 +107,7 @@ public function testFactoryCreatesNewInstances(): void
106107
public function testFactoryAcceptsReflectionClassOfActivity(): void
107108
{
108109
$proto = $this->activityReader->fromClass(DummyActivity::class)[0];
109-
$protoWithFactory = $proto->withFactory(fn (\ReflectionClass $reflectionClass) => $reflectionClass->newInstance());
110+
$protoWithFactory = $proto->withFactory(static fn(\ReflectionClass $reflectionClass) => $reflectionClass->newInstance());
110111

111112
$this->assertEquals($protoWithFactory->getInstance()->getContext(), $protoWithFactory->getInstance()->getContext());
112113
$this->assertNotSame($protoWithFactory->getInstance()->getContext(), $protoWithFactory->getInstance()->getContext());
@@ -115,9 +116,15 @@ public function testFactoryAcceptsReflectionClassOfActivity(): void
115116
public function testGetFactory(): void
116117
{
117118
$proto = $this->activityReader->fromClass(DummyActivity::class)[0];
118-
$protoWithFactory = $proto->withFactory(fn (\ReflectionClass $reflectionClass) => $reflectionClass->newInstance());
119+
$protoWithFactory = $proto->withFactory(static fn(\ReflectionClass $reflectionClass) => $reflectionClass->newInstance());
119120

120121
$this->assertNull($proto->getFactory());
121122
$this->assertNotNull($protoWithFactory->getFactory());
122123
}
124+
125+
protected function setUp(): void
126+
{
127+
$this->activityReader = new ActivityReader(new SelectiveReader([new AnnotationReader(), new AttributeReader()]));
128+
parent::setUp();
129+
}
123130
}

tests/Unit/Activity/DummyActivity.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,5 @@
1111
final class DummyActivity
1212
{
1313
#[ActivityMethod(name: "DoNothing")]
14-
public function doNothing(): void
15-
{
16-
}
14+
public function doNothing(): void {}
1715
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Temporal\Tests\Unit\Activity;
6+
7+
use Temporal\Activity\ActivityInterface;
8+
use Temporal\Activity\ActivityMethod;
9+
10+
#[ActivityInterface(prefix: 'MagicActivity.')]
11+
final class MagicActivity
12+
{
13+
public function __construct() {}
14+
15+
#[ActivityMethod(name: "Do")]
16+
public function __invoke(): void {}
17+
18+
public function __destruct() {}
19+
}

tests/Unit/Router/InvokeActivityTestCase.php

Lines changed: 32 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
namespace Temporal\Tests\Unit\Router;
66

77
use React\Promise\Deferred;
8-
use RuntimeException;
98
use Spiral\Attributes\AnnotationReader;
109
use Spiral\Attributes\AttributeReader;
1110
use Spiral\Attributes\Composite\SelectiveReader;
@@ -34,6 +33,38 @@ final class InvokeActivityTestCase extends AbstractUnit
3433
private InvokeActivity $router;
3534
private ActivityContext $activityContext;
3635

36+
public function testFinalizerIsCalledOnSuccessActivityInvocation(): void
37+
{
38+
$finalizerWasCalled = false;
39+
$this->services->activities->addFinalizer(
40+
static function () use (&$finalizerWasCalled): void {
41+
$finalizerWasCalled = true;
42+
},
43+
);
44+
45+
$this->activityContext->getInfo()->type->name = 'DummyActivityDoNothing';
46+
$request = new Request('DummyActivityDoNothing', EncodedValues::fromValues([]));
47+
$this->router->handle($request, [], new Deferred());
48+
$this->assertTrue($finalizerWasCalled);
49+
}
50+
51+
public function testFinalizerIsCalledOnFailedActivityInvocation(): void
52+
{
53+
$finalizerWasCalled = false;
54+
$this->services->activities->addFinalizer(
55+
function (\Throwable $error) use (&$finalizerWasCalled): void {
56+
$finalizerWasCalled = true;
57+
$this->assertInstanceOf(\RuntimeException::class, $error);
58+
$this->assertSame('Failed', $error->getMessage());
59+
},
60+
);
61+
62+
$this->activityContext->getInfo()->type->name = 'DummyActivityDoFail';
63+
$request = new Request('DummyActivityDoFail', EncodedValues::fromValues([]));
64+
$this->router->handle($request, [], new Deferred());
65+
$this->assertTrue($finalizerWasCalled);
66+
}
67+
3768
protected function setUp(): void
3869
{
3970
$rpc = $this->createMock(RPCConnectionInterface::class);
@@ -70,37 +101,4 @@ protected function setUp(): void
70101

71102
parent::setUp();
72103
}
73-
74-
75-
public function testFinalizerIsCalledOnSuccessActivityInvocation(): void
76-
{
77-
$finalizerWasCalled = false;
78-
$this->services->activities->addFinalizer(
79-
function () use (&$finalizerWasCalled) {
80-
$finalizerWasCalled = true;
81-
}
82-
);
83-
84-
$this->activityContext->getInfo()->type->name = 'DummyActivityDoNothing';
85-
$request = new Request('DummyActivityDoNothing', EncodedValues::fromValues([]));
86-
$this->router->handle($request, [], new Deferred());
87-
$this->assertTrue($finalizerWasCalled);
88-
}
89-
90-
public function testFinalizerIsCalledOnFailedActivityInvocation(): void
91-
{
92-
$finalizerWasCalled = false;
93-
$this->services->activities->addFinalizer(
94-
function (\Throwable $error) use (&$finalizerWasCalled) {
95-
$finalizerWasCalled = true;
96-
$this->assertInstanceOf(RuntimeException::class, $error);
97-
$this->assertSame('Failed', $error->getMessage());
98-
}
99-
);
100-
101-
$this->activityContext->getInfo()->type->name = 'DummyActivityDoFail';
102-
$request = new Request('DummyActivityDoFail', EncodedValues::fromValues([]));
103-
$this->router->handle($request, [], new Deferred());
104-
$this->assertTrue($finalizerWasCalled);
105-
}
106104
}

0 commit comments

Comments
 (0)