Skip to content

fix(state): object-mapper reuse related entity - #7300

Merged
soyuka merged 1 commit into
api-platform:mainfrom
soyuka:object-mapper-with-relations-put
Jul 29, 2025
Merged

fix(state): object-mapper reuse related entity#7300
soyuka merged 1 commit into
api-platform:mainfrom
soyuka:object-mapper-with-relations-put

Conversation

@soyuka

@soyuka soyuka commented Jul 18, 2025

Copy link
Copy Markdown
Member
Q A
Branch? main
License MIT

Fixes an issue where we keep fetched relations so that we don't create new entities instead of persisting the existing one. Check the test and the issue at symfony/symfony#61119.

This needs symfony/symfony#61145 to work.

Comment thread src/State/ObjectMapper/ObjectMapper.php Outdated

public function map(object $source, object|string|null $target = null): object
{
if (isset($this->objectMap[$source])) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we want to check if a target has not been given explicitly by the user before overriding it?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my tests the target is a string and I do need to map but I'll test this further.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, if the target is an object it shouldn't be overridden.

@mrossard

mrossard commented Jul 25, 2025

Copy link
Copy Markdown
Contributor

I was taking a look at the ObjectMapper, and I have doubts about simple patches in the current implementation - if you add $this->assertEquals($uri, $r->toArray()['@id']); here : https://github.com/api-platform/core/blob/main/tests/Functional/MappingTest.php#L69 you get this :

1) ApiPlatform\Tests\Functional\MappingTest::testShouldMapBetweenResourceAndEntity
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-'/mapped_resources/11'
+'/mapped_resources/12'

Would this fix work on this too?

[edit]

Yes, it should.

$target = $this->objectMap[$source];
}
$mapped = $this->decorated->map($source, $target);
$this->objectMap[$mapped] = $source;

@mrossard mrossard Jul 26, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't you also add $this->objectMap[$source] = $target; ? In persist operations you have multiple back and forth mappings between resource and entity.

This probably should be indexed by the object class too, otherwise multiple mappings will not work - you'll get errors similar to what was fixed by #7311

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have a test case for this?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll try to build one, but you can imagine something like a resource that includes 2 different subresources that are actually representations of the same entity. You'd be storing that $entity maps to $firstResource, then on the call for SecondResource::class you'd get back $firstResource.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...and if it was about the first part of my comment, ObjectMapperProcessor does the transformation both ways :

  • first the resource is mapped to the entity
  • the entity is persisted
  • the entity is mapped back to the resource

But as i'm writing this i realize it shouldn't reuse the previous object since its contents can change on persist, so you can just ignore my ramblings :D

Comment thread src/State/ObjectMapper/ObjectMapper.php Outdated

public function map(object $source, object|string|null $target = null): object
{
if (isset($this->objectMap[$source])) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, if the target is an object it shouldn't be overridden.

@soyuka
soyuka force-pushed the object-mapper-with-relations-put branch 4 times, most recently from a9844d7 to e3a23b7 Compare July 29, 2025 07:26
@soyuka
soyuka force-pushed the object-mapper-with-relations-put branch from e3a23b7 to 024b431 Compare July 29, 2025 07:29
@soyuka
soyuka merged commit d06b1a0 into api-platform:main Jul 29, 2025
113 of 114 checks passed
@soyuka
soyuka deleted the object-mapper-with-relations-put branch July 29, 2025 08:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants