Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit2bbc09b

Browse files
[Workflow] State contamination due to class-based setter cache
1 parent5c76029 commit2bbc09b

File tree

3 files changed

+114
-5
lines changed

3 files changed

+114
-5
lines changed

‎src/Symfony/Component/Workflow/MarkingStore/MethodMarkingStore.php‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@
3131
*/
3232
finalclass MethodMarkingStoreimplements MarkingStoreInterface
3333
{
34-
/** @var array<class-string,MarkingStoreMethod> */
34+
/** @var array<class-string,\Closure(object): mixed> */
3535
privatearray$getters = [];
36-
/** @var array<class-string,MarkingStoreMethod> */
36+
/** @var array<class-string,\Closure(object, mixed, array)> */
3737
privatearray$setters = [];
3838

3939
/**
@@ -84,7 +84,7 @@ public function setMarking(object $subject, Marking $marking, array $context = [
8484
$marking =key($marking);
8585
}
8686

87-
($this->setters[$subject::class] ??=$this->getSetter($subject))($marking,$context);
87+
($this->setters[$subject::class] ??=$this->getSetter($subject))($subject,$marking,$context);
8888
}
8989

9090
privatefunctiongetGetter(object$subject):callable
@@ -104,8 +104,8 @@ private function getSetter(object $subject): callable
104104
$method ='set'.ucfirst($property);
105105

106106
returnmatch (self::getType($subject,$property,$method,$type)) {
107-
MarkingStoreMethod::METHOD =>$type ?staticfn ($marking,$context) =>$subject->{$method}($type::from($marking),$context) :$subject->{$method}(...),
108-
MarkingStoreMethod::PROPERTY =>$type ?staticfn ($marking) =>$subject->{$property} =$type::from($marking) :staticfn ($marking) =>$subject->{$property} =$marking,
107+
MarkingStoreMethod::METHOD =>$type ?staticfn ($subject,$marking,$context) =>$subject->{$method}($type::from($marking),$context) :staticfn ($subject,$marking,$context) =>$subject->{$method}($marking,$context),
108+
MarkingStoreMethod::PROPERTY =>$type ?staticfn ($subject,$marking) =>$subject->{$property} =$type::from($marking) :staticfn ($subject,$marking) =>$subject->{$property} =$marking,
109109
};
110110
}
111111

‎src/Symfony/Component/Workflow/Tests/MarkingStore/MethodMarkingStoreTest.php‎

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,65 @@ public function testGetMarkingWithSameSubjectMultipleTimes()
142142
$this->assertSame(['third_place' =>1],$marking3->getPlaces());
143143
}
144144

145+
publicfunctiontestSetMarkingWithMultipleSubjectsSharingCachedSetter()
146+
{
147+
$subject1 =newSubject();
148+
$subject2 =newSubject();
149+
$subject3 =newSubject();
150+
151+
$markingStore =newMethodMarkingStore(true);
152+
153+
// First call caches the setter for Subject class
154+
$marking1 =$markingStore->getMarking($subject1);
155+
$marking1->mark('place1');
156+
$markingStore->setMarking($subject1,$marking1, ['context1' =>'value1']);
157+
158+
// Subsequent calls should use the cached setter but operate on different subjects
159+
$marking2 =$markingStore->getMarking($subject2);
160+
$marking2->mark('place2');
161+
$markingStore->setMarking($subject2,$marking2, ['context2' =>'value2']);
162+
163+
$marking3 =$markingStore->getMarking($subject3);
164+
$marking3->mark('place3');
165+
$markingStore->setMarking($subject3,$marking3, ['context3' =>'value3']);
166+
167+
// Each subject should have its own marking and context
168+
$this->assertSame('place1',$subject1->getMarking());
169+
$this->assertSame(['context1' =>'value1'],$subject1->getContext());
170+
171+
$this->assertSame('place2',$subject2->getMarking());
172+
$this->assertSame(['context2' =>'value2'],$subject2->getContext());
173+
174+
$this->assertSame('place3',$subject3->getMarking());
175+
$this->assertSame(['context3' =>'value3'],$subject3->getContext());
176+
}
177+
178+
publicfunctiontestSetMarkingWithMultipleSubjectsSharingCachedSetterMultipleState()
179+
{
180+
$subject1 =newSubject();
181+
$subject2 =newSubject();
182+
183+
$markingStore =newMethodMarkingStore(false);
184+
185+
// First call caches the setter for Subject class
186+
$marking1 =$markingStore->getMarking($subject1);
187+
$marking1->mark('place1');
188+
$marking1->mark('place2');
189+
$markingStore->setMarking($subject1,$marking1, ['context1' =>'value1']);
190+
191+
// Second call should use the cached setter but operate on a different subject
192+
$marking2 =$markingStore->getMarking($subject2);
193+
$marking2->mark('place3');
194+
$markingStore->setMarking($subject2,$marking2, ['context2' =>'value2']);
195+
196+
// Each subject should have its own marking and context
197+
$this->assertSame(['place1' =>1,'place2' =>1],$subject1->getMarking());
198+
$this->assertSame(['context1' =>'value1'],$subject1->getContext());
199+
200+
$this->assertSame(['place3' =>1],$subject2->getMarking());
201+
$this->assertSame(['context2' =>'value2'],$subject2->getContext());
202+
}
203+
145204
privatefunctioncreateValueObject(string$markingValue):object
146205
{
147206
returnnewclass($markingValue) {

‎src/Symfony/Component/Workflow/Tests/MarkingStore/PropertiesMarkingStoreTest.php‎

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,56 @@ public function testGetMarkingWithUninitializedProperty()
9292
$this->assertCount(0,$marking->getPlaces());
9393
}
9494

95+
publicfunctiontestSetMarkingWithMultipleSubjectsSharingCachedSetter()
96+
{
97+
$subject1 =newSubjectWithProperties();
98+
$subject2 =newSubjectWithProperties();
99+
$subject3 =newSubjectWithProperties();
100+
101+
$markingStore =newMethodMarkingStore(false);
102+
103+
// First call caches the setter for SubjectWithProperties class
104+
$marking1 =$markingStore->getMarking($subject1);
105+
$marking1->mark('place1');
106+
$markingStore->setMarking($subject1,$marking1, ['context1' =>'value1']);
107+
108+
// Subsequent calls should use the cached setter but operate on different subjects
109+
$marking2 =$markingStore->getMarking($subject2);
110+
$marking2->mark('place2');
111+
$markingStore->setMarking($subject2,$marking2, ['context2' =>'value2']);
112+
113+
$marking3 =$markingStore->getMarking($subject3);
114+
$marking3->mark('place3');
115+
$markingStore->setMarking($subject3,$marking3, ['context3' =>'value3']);
116+
117+
// Each subject should have its own marking set correctly
118+
$this->assertSame(['place1' =>1],$subject1->marking);
119+
$this->assertSame(['place2' =>1],$subject2->marking);
120+
$this->assertSame(['place3' =>1],$subject3->marking);
121+
}
122+
123+
publicfunctiontestSetMarkingWithMultipleSubjectsSharingCachedSetterSingleState()
124+
{
125+
$subject1 =newSubjectWithProperties();
126+
$subject2 =newSubjectWithProperties();
127+
128+
$markingStore =newMethodMarkingStore(true,'place');
129+
130+
// First call caches the setter for SubjectWithProperties class
131+
$marking1 =$markingStore->getMarking($subject1);
132+
$marking1->mark('place1');
133+
$markingStore->setMarking($subject1,$marking1, ['context1' =>'value1']);
134+
135+
// Second call should use the cached setter but operate on a different subject
136+
$marking2 =$markingStore->getMarking($subject2);
137+
$marking2->mark('place2');
138+
$markingStore->setMarking($subject2,$marking2, ['context2' =>'value2']);
139+
140+
// Each subject should have its own marking set correctly
141+
$this->assertSame('place1',$subject1->place);
142+
$this->assertSame('place2',$subject2->place);
143+
}
144+
95145
privatefunctioncreateValueObject(string$markingValue):object
96146
{
97147
returnnewclass($markingValue) {

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp