Skip to content

Commit 67ac28d

Browse files
ACPT-1929
When multiple reseters match class in resetStateWithReflection, they are now run in order of inheritance so that subclasses can have specialized resetters. Also runs resetters for interfaces in proper order as well.
1 parent 40fefb6 commit 67ac28d

File tree

1 file changed

+62
-3
lines changed
  • lib/internal/Magento/Framework/ObjectManager/Resetter

1 file changed

+62
-3
lines changed

lib/internal/Magento/Framework/ObjectManager/Resetter/Resetter.php

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ class Resetter implements ResetterInterface
4040
/** @var array */
4141
private readonly array $classList;
4242

43+
/** @var array */
44+
private array $sortedClassListsByClass = [];
45+
4346
/**
4447
* @param ComponentRegistrarInterface|null $componentRegistrar
4548
* @param array $classList
@@ -172,11 +175,67 @@ private function resetStateWithReflection(object $instance)
172175
$instance->{self::RESET_STATE_METHOD}();
173176
return;
174177
}
175-
foreach ($this->classList as $className => $value) {
176-
if ($instance instanceof $className) {
177-
$this->resetStateWithReflectionByClassName($instance, $className);
178+
$className = get_class($instance);
179+
if (!array_key_exists($className, $this->sortedClassListsByClass)) {
180+
$temporaryClassList = [];
181+
foreach ($this->classList as $key => $value) {
182+
if ($instance instanceof $key) {
183+
$temporaryClassList[] = $key;
184+
}
178185
}
186+
$this->sortClasses($temporaryClassList);
187+
$this->sortedClassListsByClass[$className] = $temporaryClassList;
188+
}
189+
foreach ($this->sortedClassListsByClass[$className] as $currentClassName) {
190+
$this->resetStateWithReflectionByClassName($instance, $currentClassName);
191+
}
192+
}
193+
194+
/**
195+
* Sorts an array of strings that are class names and interface names
196+
*
197+
* Note: This sorting algorithm only takes arrays that are keyed by contiguous numbers starting at zero.
198+
* Note: This sorting algorithm works with comparators that return false on unrelated items.
199+
*
200+
* @param array $array
201+
* @return void
202+
*/
203+
private function sortClasses(array &$array) : void
204+
{
205+
$i = 0;
206+
$count = count($array);
207+
while ($i + 1 < $count) {
208+
for ($j = $i + 1; $j < $count; $j++) {
209+
if ($this->sortClassesComparitor($array[$i], $array[$j])) {
210+
$swapTemp = $array[$i];
211+
$array[$i] = $array[$j];
212+
$array[$j] = $swapTemp;
213+
continue 2;
214+
}
215+
}
216+
$i++;
217+
}
218+
}
219+
220+
/**
221+
* Comparator for class/interface sorter that returns true if $b should come before $a.
222+
*
223+
* @param string $a
224+
* @param string $b
225+
* @return bool
226+
*/
227+
private function sortClassesComparitor(string $a, string $b) : bool
228+
{
229+
if (is_a($a, $b, true)) {
230+
return true;
231+
}
232+
if (is_a($b, $a, true)) {
233+
return false;
234+
}
235+
if (interface_exists($a) && class_exists($b)) {
236+
return true; // Note: If they aren't related, classes should come before interfaces
179237
}
238+
return false; // No relation
180239
}
181240

182241
/**

0 commit comments

Comments
 (0)