feat: use ghost objects for auto refresh mechanism#967
Conversation
a033d3f to
fdd2490
Compare
| * @throws RefreshObjectFailed | ||
| */ | ||
| public function refresh(object &$object, bool $force = false, bool $allowRefreshDeletedObject = false): object | ||
| public function refresh(object &$object, bool $force = false): object |
There was a problem hiding this comment.
I've actually reset the refresh() method to the same state than in 2.x
| * | ||
| * @param T $object | ||
| */ | ||
| public function autorefresh(object $object, object $clone): void |
There was a problem hiding this comment.
I decided to split "refresh" and "autorefresh" mechanisms, because they does not involve the same problems, and the autorefresh should not manipulate the object reference (otherwise, we're exposed to identity problems)
| // the object no longer exists | ||
| Hydrator::hydrateFromOtherObject($object, $clone); | ||
| $om->detach($object); |
There was a problem hiding this comment.
if the object no longer exist, we still need to return something, otherwise, the lazy ghost will be re-initialized as an empty shell. For this purpose we're using a clone of the object
| $strategy = $this->strategyFor($object::class); | ||
| $om = $strategy->objectManagerFor($object::class); | ||
|
|
||
| $id = $strategy->getIdentifierValues($clone); |
There was a problem hiding this comment.
we need the clone here, because it still has is "identifier fields" hydrated
|
|
||
| self::assertSame('foo', $object->getProp1()); | ||
|
|
||
| self::assertTrue($this->objectManager()->contains($object)); |
There was a problem hiding this comment.
there is exactly the same test in ORM version, but because the document manager is not cleared when kernel.reset is triggered, this assertions is not the same
cdd4164 to
fdd2490
Compare
There was a problem hiding this comment.
Awesome! I'm glad using lazy ghosts solves the identity problems.
Question about auto-refreshing:
$user = UserFactory::createOne();
// some code that manipulates the user
$this->assertSame('updated', $user->getUsername()); // auto-refresh is triggered
// some additional code that manipulates the user
$this->assertSame('updatedagain', $user->getUsername()); // is auto-refresh still triggered?
|
@kbond if by "code that manipulates the user", you mean a call with browser and/or console command and/or messenger, the answer is yes I think I need to add a test for this |
| public static function hydrateFromOtherObject(object $object, object $other): void | ||
| { | ||
| $classes = [$object::class, ...\array_values(\class_parents($object))]; | ||
|
|
||
| $properties = []; | ||
| foreach ($classes as $class) { | ||
| $reflector = new \ReflectionClass($class); | ||
| foreach ($reflector->getProperties() as $property) { | ||
| $properties[$property->getName()] = $property->getName(); | ||
| } | ||
| } | ||
|
|
||
| foreach ($properties as $property) { | ||
| self::set($object, $property, self::get($other, $property), catchErrors: true); | ||
| } | ||
| } |
There was a problem hiding this comment.
I hope this code won't break too much things...
actually if it breaks, it means that the entity/object has a design problem 😅
| // no identifier values means the object no longer exists | ||
| return; | ||
| } | ||
| } catch (\Throwable $e) { |
There was a problem hiding this comment.
I really don't like to do this, but, this was the only way to have something working in all situations, without being to tight with Doctrine
fdd2490 to
9fabc82
Compare
|
@kbond I've added the test I was mentioning... I'm merging this PR 🎉 |
* tests: improve test for auto refresh with lazy proxy * refactor: use lazy ghost instead of lazy proxy
Lazy ghost do not create identity problems, so they are more suited for our purpose.
I've also added a lot of tests, based on the different errors I had when testing the feature on a real life project