Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[ObjectMapper] handle non existing property errors #60856

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: 7.3
Choose a base branch
from

Conversation

soyuka
Copy link
Contributor

@soyuka soyuka commented Jun 20, 2025

Q A
Branch? 7.3
Bug fix? yes
New feature? no
Deprecations? no
Issues Fix #60848
License MIT

The property accessor allows to ignore exceptions when a property does not exist. Without the property accessor we now throw a proper exception when the property does not exist (as opposed to the PHP Warning it'd trigger otherwise). I think its better to thrown then to hide the error in that particular case.

This fixes #60848 providing a working solution and a better DX, especially that in PHP the behavior of dynamic properties is to avoid them as much as possible.

@soyuka soyuka force-pushed the default-value-stdclass branch from c6a7f6d to 88a4a59 Compare June 20, 2025 14:12
return $this->propertyAccessor->getValue($source, $propertyName);
}

if (!property_exists($source, $propertyName) && !(method_exists($source, '__isset') && true === $source->__isset($propertyName))) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not a huge fan of testing for the __isset magic method but if we don't add this its hard to support magic getters properly, maybe we should not support them in the first place?

Comments welcome.

@tacman
Copy link
Contributor

tacman commented Jun 20, 2025

Hmm. I'm not sure why this is a non-existing property error.

The DTO has the property $extra, with a default of null (or something else).

The source object is a simple StdClass that doesn't have the property. It's not setting a non-existing property of the target object, but rather set a default on the target object when the source object is missing the field.

I think it's a pretty common case -- the source and target have some common fields, create the target object and map with the property name is the same or the property has a #[Map()] attribute.

@tacman
Copy link
Contributor

tacman commented Jun 20, 2025

the "isset" was just something I tried because it seemed like logic that would work, but didn't. Could be a different issue.

@nicolas-grekas nicolas-grekas modified the milestones: 7.4, 7.3 Jun 20, 2025
@symfony symfony deleted a comment from carsonbot Jun 20, 2025
@soyuka
Copy link
Contributor Author

soyuka commented Jun 21, 2025

The source object is a simple StdClass that doesn't have the property. It's not setting a non-existing property of the target object, but rather set a default on the target object when the source object is missing the field.

In your example:

$mapper = new ObjectMapper();
$target = 'App\Dto\MyClass';
$obj = (object) ['id'=>'abc'];
$entity = $mapper->map($obj, $target);

The stdClass does not have any information about how it should be mapped, therefore we use the data from the $target (here App\Dto\MyClass. App\Dto\MyClass has a default but when we read that property on the stdClass it does not exists. So it's not "setting a non-existing property" but "reading a non-existing property" which leads to a NoSuchPropertyException. Looks fine to me.
The default value works fine when using the PropertyAccessor with the proper option see my assertions in the tests:

        $this->assertEquals('abc', $b->id);
        $this->assertEquals(null, $b->optional);

I think it's a pretty common case -- the source and target have some common fields, create the target object and map with the property name is the same or the property has a #[Map()] attribute.

stdClass is quite specific, use DTOs on both ends of the mapping and you probably won't have any issues.

the "isset" was just something I tried because it seemed like logic that would work, but didn't. Could be a different issue.

Isset would be a weird use case but NotNull would be quite useful.

@tacman
Copy link
Contributor

tacman commented Jun 21, 2025

Thanks. My use case is that I'm getting data from csv and JSON, and I want to map the data to a DTO. But the field names and often type are wrong.

So

First Name,Last Name,Country,Language Spoken At Home
Bob,Roberts,USA,English

And I want a DTO of a class with properties $firstName, $lastName,$countryCode,$langCode

So I want to import from $row['First Name'] to $dto->firstName and transform the country and language names to codes them with a service. ObjectMapper seems like the perfect tool for that. So this step is to go from the stdClass to a DTO. What approach do you suggest? I've been using league/csv-reader for some parts, (which will map to a DTO), but the problem is that I don't have a DTO yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[ObjectMapper] if 'isset' and default values not working
4 participants