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

[ObjectMapper] Condition to target a specific class#60028

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
fabpot merged 1 commit intosymfony:7.3fromsoyuka:allow-different-targets
May 6, 2025

Conversation

soyuka
Copy link
Contributor

@soyukasoyuka commentedMar 24, 2025
edited
Loading

QA
Branch?7.3
Bug fix?no
New feature?yes
Deprecations?no
LicenseMIT

We want to be able to choose which property to map according to the target. Herefoo is mapped toB only when the target isB. IfC has afoo property it won't be mapped as we only map tobar.

useSymfony\Component\ObjectMapper\Attribute\Map;useSymfony\Component\ObjectMapper\TargetClass;#[Map(target: B::class)]#[Map(target: C::class)]class A{    #[Map(target:'foo', transform:'strtoupper', if:newTargetClass(B::class))]    #[Map(target:'bar')]publicstring$something ='test';publicstring$doesNotExistInTargetB ='foo';}

This is a good alternative to groups as we can have one class that has multiple representation.

siganushka reacted with thumbs up emoji
@OskarStark
Copy link
Contributor

I extracted the CS fixes into

to keep this PR clean

soyuka reacted with thumbs up emoji

@soyukasoyukaforce-pushed theallow-different-targets branch from564b44b to81039a8CompareMarch 25, 2025 08:57
@soyukasoyuka closed thisMar 25, 2025
@soyukasoyukaforce-pushed theallow-different-targets branch from81039a8 tof803dc1CompareMarch 25, 2025 13:17
@soyukasoyuka reopened thisMar 25, 2025
@soyukasoyukaforce-pushed theallow-different-targets branch from95783e6 to2b46190CompareMarch 27, 2025 11:41
@soyukasoyukaforce-pushed theallow-different-targets branch from2b46190 to377a6a6CompareMarch 27, 2025 15:44
@soyukasoyuka changed the title[ObjectMapper] Target in the transform and condition callback[ObjectMapper] Condition allows target class nameMar 27, 2025
@soyukasoyukaforce-pushed theallow-different-targets branch from377a6a6 to388f5abCompareMarch 27, 2025 15:46
@soyuka
Copy link
ContributorAuthor

Ready for review@mtarld@GromNaN

@soyukasoyukaforce-pushed theallow-different-targets branch 4 times, most recently froma60b582 toca88a41CompareMarch 28, 2025 08:20
@GromNaN
Copy link
Member

GromNaN commentedMar 31, 2025
edited
Loading

The feature is relevant, but I find the syntax of the attribute is not explicit.

I would find it clearer if the target contained[class, property] instead. That would let theif for an actual condition.

- #[Map(target: 'foo', transform: 'strtoupper', if: B::class)]+ #[Map(target: [B::class, 'foo'], transform: 'strtoupper']
IndraGunawan reacted with thumbs up emoji

@soyuka
Copy link
ContributorAuthor

I would find it clearer if the target contained [class, property] instead. That would let the if for an actual condition.

This was my first attempt but its weird to use a Closure that's not interpreted as a Closure no? Also thetarget is either a class or a property name, using this would require more code changes. instead of

@GromNaN
Copy link
Member

Then, can we add atargetClass property to the attribute? We'd need separate attribute classes since the properties diverge:MapClass andMapProperty.

@soyuka
Copy link
ContributorAuthor

soyuka commentedMar 31, 2025
edited
Loading

targetClass is confusing with target, not sure this needs to split attributes in two for now and if we didMapProperty would have class and property. What's wrong with just having the class on theif?

#[Map(if: fn($target) => $target instance of ClassName)]

using the class name is just a shortcut for that. Although to make this work we would also need to add thetarget to our callbacks.

To re-center the debate I think symfony should allow some use cases with a as straightforward as possible DX, when users want more behavior it's quite feasible using the MetadataFactory.

@GromNaN
Copy link
Member

GromNaN commentedMar 31, 2025
edited
Loading

Adding thetarget after thevalue and thesource, sounds like a good idea. The condition callable signature would becomefunction (mixed $value, object $source, object $target).

The if condition can be an invokable object that implementsConditionCallableInterface.

readonlyclass TargetClassimplements ConditionCallableInterface {publicfunction__construct(privatestring$targetClass) {}publicfunction__invoke(mixed$value,object$source,object$target):bool {returnis_a($this->targetClass,$target,true);    }}

Usage:

#[Map(target: B::class)]class A{    #[Map(target:'foo', transform:'strtoupper', if:newTargetClass(B::class))]publicstring$something ='test';}

That way, it's explicit, it doesn't require the PHP 8.5 closures in attributes and keep a good DX. Later you can combine more conditions by nesting objects.

Experimentation:soyuka#1

mtarld reacted with thumbs up emoji

@soyukasoyukaforce-pushed theallow-different-targets branch 3 times, most recently fromc826e6d to53b56d6CompareApril 2, 2025 10:13
@joelwurtz
Copy link
Contributor

I'm being late on this, but having this check on theif condition will avoid potential optimization later if there is other conditions.

It's due to the fact, that those kind of condition (evaluating a target class) can be easily checked during metadata extraction. But if there is future condition that induce runtime check it will be impossible to extrapolate this check during metadata extraction (since it's too generic) so we will have to do it each time

@joelwurtz
Copy link
Contributor

Maybe something like this would be better :

#[Map(target: B::class)]#[Map(target: C::class)]class A{    #[Map(to:'foo', target: B::class, transform:'strtoupper')]    #[Map(to:'bar')]publicstring$something ='test';publicstring$doesNotExistInTargetB ='foo';}

It keep target consistent with the attribute being on either a property or the class,

However this is a hard change in current api (but since it's not released i think it's ok ?)

@OskarStark
Copy link
Contributor

It would be no problem yes

@soyuka
Copy link
ContributorAuthor

@joelwurtz I think it's too confusing to haveto/from andsource/target. I don't share the concerns as we can easily take this check as a "static" check that we can induce during the metadata extraction. We could also add a particular interface that would force these checks at runtime instead.

@joelwurtz
Copy link
Contributor

joelwurtz commentedApr 2, 2025
edited
Loading

Personally i find this confusing to have the same property on the same attribute that does not mean the same thing given the position of the attribute :/ (as an user i would expect a property having the same meaning)

I don't share the concerns as we can easily take this check as a "static" check that we can induce during the metadata extraction. We could also add a particular interface that would force these checks at runtime instead.

Not sure how it would work since they may be check that combine multiple checks ?

I just find this complex given the use case

EDIT :

Also this could be :

#[Map(property:'foo', target: B::class, transform:'strtoupper')]

(Could be also rename ? or any other name)

So no to / from, work both ways

Korbeil reacted with thumbs up emoji

@soyuka
Copy link
ContributorAuthor

soyuka commentedApr 3, 2025
edited
Loading

I'm not sure we need to anticipate these use cases quite yet as we're still a long way to go before adding performance optimizations. I suggest that we leave this like this: theif adds a condition, and it's quite clear that "map only when this class is the target" is a condition. I want this API to be tried in user-land and we'll see if the use cases don't match we'll consider changing the whole API. Same goes when we will want to introduce performance with a cache warmup we'll see how this goes.

Not sure how it would work since they may be check that combine multiple checks ?

Sure but then they would be executed at runtime, just like transformations. Let's say we haveclass TargetClass implements StaticConditionInterface then we know we can execute the condition when doing an optimization pass. If not, we just use the condition at runtime.

Personally i find this confusing to have the same property on the same attribute that does not mean the same thing given the position of the attribute

You mean having thetarget being aclass on the class attribute and aproperty on the property attribute? Then we shall have two different attributes and it brings other issues (like mapping an embed object).

GromNaN reacted with thumbs up emoji

Copy link
Contributor

@mtarldmtarld left a comment

Choose a reason for hiding this comment

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

With minor comments

@joelwurtz
Copy link
Contributor

You mean having the target being a class on the class attribute and a property on the property attribute? Then we shall have two different attributes and it brings other issues (like mapping an embed object).

Yes that was i mean, i think consistent wording is important across a component, specially when this parameter can be considered as a "configuration" parameter having different meaning for the same word in the same component will induce a lot of friction IMO

@chalasr
Copy link
Member

Although the potential confusion seems real, making that setting context-dependent (i.e. expecting a property if used on a property vs a FQCN if used on a class) looks sensible to me. Throwing meaningful errors on such mistake should be good enough, do we have that?

@soyuka
Copy link
ContributorAuthor

IMHO its outside of the current scope of this PR we can always open a new issue to discuss this (or add this to the RFC issue)

GromNaN reacted with thumbs up emoji

@fabpotfabpotforce-pushed theallow-different-targets branch fromfd55ff0 toa5698aaCompareMay 6, 2025 06:50
@fabpot
Copy link
Member

Thank you@soyuka.

@fabpotfabpot merged commit7379bfb intosymfony:7.3May 6, 2025
9 of 11 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@fabpotfabpotfabpot approved these changes

@nicolas-grekasnicolas-grekasnicolas-grekas approved these changes

@GromNaNGromNaNGromNaN approved these changes

@mtarldmtarldmtarld approved these changes

Assignees
No one assigned
Projects
None yet
Milestone
7.3
Development

Successfully merging this pull request may close these issues.

9 participants
@soyuka@OskarStark@GromNaN@mtarld@joelwurtz@chalasr@fabpot@nicolas-grekas@carsonbot

[8]ページ先頭

©2009-2025 Movatter.jp