-
Notifications
You must be signed in to change notification settings - Fork 22
Be compatible with Symfony/ObjectMapper #306
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
Conversation
81cb479 to
bcc9aea
Compare
af31016 to
c28a2d8
Compare
d05bc8a to
c55992c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds first-class support for Symfony’s symfony/object-mapper by teaching AutoMapper to understand #[Map]-style attributes, and by providing an implementation of Symfony’s ObjectMapperInterface backed by AutoMapper.
Changes:
- Introduces
AutoMapper\ObjectMapper\ObjectMapper, integrating Symfony’sObjectMapperInterfacewith AutoMapper (including transform callables, target selection, and error handling). - Extends the metadata/mapper generation pipeline (providers, conditions, lazy-object handling, service-locator integration) to consume Symfony ObjectMapper attributes and condition/transform callables.
- Adds an extensive PHPUnit test suite and fixtures mirroring Symfony’s
ObjectMappertests to verify compatibility (recursion, lazy loading, promoted properties, collections, service-based transforms, embedded mappings, etc.).
Reviewed changes
Copilot reviewed 99 out of 99 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
tests/ObjectMapper/ObjectMapperTest.php |
Integration tests verifying AutoMapper’s ObjectMapper implementation matches expected Symfony ObjectMapperInterface behavior across many scenarios. |
tests/ObjectMapper/Fixtures/A.php |
Source fixture annotated with Symfony #[Map] attributes to test basic property mapping, transforms, conditions, and relation mapping. |
tests/ObjectMapper/Fixtures/B.php |
Target fixture for A, used to validate property mapping results, defaults, and relations. |
tests/ObjectMapper/Fixtures/C.php |
Fixture using #[Map(D::class)] with property-level #[Map] annotations to test attribute-driven target mapping. |
tests/ObjectMapper/Fixtures/D.php |
Simple DTO target with constructor-promoted properties used in mapping and relation tests. |
tests/ObjectMapper/Fixtures/ClassWithoutTarget.php |
Fixture with no mapping target to exercise error paths when no mapping is found. |
tests/ObjectMapper/Fixtures/DeeperRecursion/Recursive.php |
Source fixture with recursive relations plus #[Map] to test deep recursion handling. |
tests/ObjectMapper/Fixtures/DeeperRecursion/RecursiveDto.php |
DTO counterpart for Recursive, used to assert recursive mapping structure. |
tests/ObjectMapper/Fixtures/DeeperRecursion/Relation.php |
Source relation class with #[Map(RelationDto::class)] used in deep recursion scenario. |
tests/ObjectMapper/Fixtures/DeeperRecursion/RelationDto.php |
DTO relation type for deep recursion mapping tests. |
tests/ObjectMapper/Fixtures/DefaultLazy/OrderSource.php |
Source fixture with #[Map] to test mapping of lazily-related user objects (skipped test notes differing behavior). |
tests/ObjectMapper/Fixtures/DefaultLazy/OrderTarget.php |
Target DTO for lazy order/user mapping scenarios. |
tests/ObjectMapper/Fixtures/DefaultLazy/UserSource.php |
Source for default-lazy user mapping tests, annotated with #[Map(UserTarget::class)]. |
tests/ObjectMapper/Fixtures/DefaultLazy/UserTarget.php |
Target DTO for lazy user mapping with nullable name. |
tests/ObjectMapper/Fixtures/DefaultValueStdClass/TargetDto.php |
DTO using #[Map(if: self::isDefined)] to test optional property mapping from stdClass. |
tests/ObjectMapper/Fixtures/EmbeddedMapping/Address.php |
Address value object used in embedded property mapping tests. |
tests/ObjectMapper/Fixtures/EmbeddedMapping/User.php |
Target entity with embedded Address, used to verify path-based mapping (address.zipcode, etc.). |
tests/ObjectMapper/Fixtures/EmbeddedMapping/UserDto.php |
DTO using #[Map(target: 'address.*')] to test embedded mapping into nested objects. |
tests/ObjectMapper/Fixtures/Flatten/TargetUser.php |
Flattened DTO for user/profile mapping tests. |
tests/ObjectMapper/Fixtures/Flatten/User.php |
Readonly source with #[Map(target: TargetUser::class)] mapping nested UserProfile into flat fields. |
tests/ObjectMapper/Fixtures/Flatten/UserProfile.php |
Value object with static helper methods used as transform callables in flattening tests. |
tests/ObjectMapper/Fixtures/HydrateObject/SourceOnly.php |
Constructor-based DTO using #[Map(source: ...)] to test mapping from source-only data. |
tests/ObjectMapper/Fixtures/InitializedConstructor/A.php |
Source fixture with pre-initialized tags array for constructor-initialization tests. |
tests/ObjectMapper/Fixtures/InitializedConstructor/B.php |
Target with internal tags initialization and mutators to validate constructor/initialization semantics. |
tests/ObjectMapper/Fixtures/InitializedConstructor/C.php |
Target class whose constructor initializes bar to test constructor-based hydration. |
tests/ObjectMapper/Fixtures/InitializedConstructor/D.php |
Class with computed barUpperCase and #[Map(if: false)] to test differing constructor vs. field names. |
tests/ObjectMapper/Fixtures/InstanceCallback/A.php |
Source using #[Map(transform: [B::class, 'newInstance'])] to test instance-creating callbacks. |
tests/ObjectMapper/Fixtures/InstanceCallback/B.php |
Target with custom constructor and static newInstance factory used in instance callback tests. |
tests/ObjectMapper/Fixtures/InstanceCallbackWithArguments/A.php |
Source with class-level transform [B::class, 'newInstance'] to test transform callables with value and source arguments. |
tests/ObjectMapper/Fixtures/InstanceCallbackWithArguments/B.php |
Target capturing both transformed value and source for verification. |
tests/ObjectMapper/Fixtures/LazyFoo.php |
Custom class implementing LazyObjectInterface to test lazy-object initialization before mapping. |
tests/ObjectMapper/Fixtures/MapStruct/AToBMapper.php |
Example mapper implementing ObjectMapperInterface plus custom #[Map] attributes to simulate MapStruct-like behavior. |
tests/ObjectMapper/Fixtures/MapStruct/Map.php |
Local attribute extending Symfony’s Map to experiment with MapStruct-style declarative mappings. |
tests/ObjectMapper/Fixtures/MapStruct/MapStructMapperMetadataFactory.php |
Custom ObjectMapperMetadataFactoryInterface implementation modeling MapStruct-like mapping metadata. |
tests/ObjectMapper/Fixtures/MapStruct/Source.php |
Source struct for MapStruct-style mapper tests. |
tests/ObjectMapper/Fixtures/MapStruct/Target.php |
Target struct to validate mapping of selected properties via MapStruct-like metadata. |
tests/ObjectMapper/Fixtures/MapTargetToSource/A.php |
Source with constructor-promoted source property for inverse mapping tests. |
tests/ObjectMapper/Fixtures/MapTargetToSource/B.php |
Target annotated with #[Map(source: A::class)] and constructor #[Map(source: 'source')] for target-to-source mapping. |
tests/ObjectMapper/Fixtures/MultipleTargetProperty/A.php |
Source fixture with multiple #[Map] attributes using TargetClass to test per-target property behavior. |
tests/ObjectMapper/Fixtures/MultipleTargetProperty/B.php |
First target DTO for multiple-target-property mapping tests. |
tests/ObjectMapper/Fixtures/MultipleTargetProperty/C.php |
Second target DTO with additional fields, used to validate conditional per-target mapping. |
tests/ObjectMapper/Fixtures/MultipleTargets/A.php |
Source annotated with multiple #[Map(target: ... , if: ...)] entries to select between multiple target types. |
tests/ObjectMapper/Fixtures/MultipleTargets/B.php |
Empty target class for multiple-target mapping (unused target) tests. |
tests/ObjectMapper/Fixtures/MultipleTargets/C.php |
Target with readonly foo used to verify correct target selection. |
tests/ObjectMapper/Fixtures/MyProxy.php |
Simple class used as native PHP 8.4 lazy proxy target in tests. |
tests/ObjectMapper/Fixtures/PartialInput/FinalInput.php |
Final input DTO with defaults to test partial input mapping behavior. |
tests/ObjectMapper/Fixtures/PartialInput/PartialInput.php |
Source type annotated with #[Map(target: FinalInput::class)] to test partial updates. |
tests/ObjectMapper/Fixtures/PromotedConstructor/Source.php |
Source with promoted properties to test mapping with constructor promotion. |
tests/ObjectMapper/Fixtures/PromotedConstructor/Target.php |
Target with promoted properties verifying constructor-promoted mapping updates. |
tests/ObjectMapper/Fixtures/PromotedConstructorWithMetadata/Source.php |
Source annotated with custom Map (MapStruct namespace) targeting a class with extra constructor requirements. |
tests/ObjectMapper/Fixtures/PromotedConstructorWithMetadata/Target.php |
Target with a required extra promoted property to ensure mapping doesn’t re-instantiate when already constructed. |
tests/ObjectMapper/Fixtures/ReadOnlyPromotedProperty/ReadOnlyPromotedPropertyA.php |
Source with readonly promoted property and #[Map] for nested readonly mapping tests. |
tests/ObjectMapper/Fixtures/ReadOnlyPromotedProperty/ReadOnlyPromotedPropertyAMapped.php |
Target for ReadOnlyPromotedPropertyA, verifying nested mapped readonly properties. |
tests/ObjectMapper/Fixtures/ReadOnlyPromotedProperty/ReadOnlyPromotedPropertyB.php |
Nested source with #[Map] to its mapped counterpart. |
tests/ObjectMapper/Fixtures/ReadOnlyPromotedProperty/ReadOnlyPromotedPropertyBMapped.php |
Target for nested readonly mapping tests. |
tests/ObjectMapper/Fixtures/Recursion/AB.php |
Source with self-referential property and #[Map(Dto::class)] to test recursion. |
tests/ObjectMapper/Fixtures/Recursion/Dto.php |
DTO with self-referential property Dto $dto to validate recursive mapping behavior. |
tests/ObjectMapper/Fixtures/ServiceLoadedValue/LoadedValue.php |
Simple value object named LoadedValue used in service-loaded transform tests. |
tests/ObjectMapper/Fixtures/ServiceLoadedValue/LoadedValueService.php |
Service class that lazily loads and returns a LoadedValue instance. |
tests/ObjectMapper/Fixtures/ServiceLoadedValue/LoadedValueTarget.php |
Target DTO whose relation is populated from LoadedValueService. |
tests/ObjectMapper/Fixtures/ServiceLoadedValue/ServiceLoadedValueTransformer.php |
Symfony TransformCallableInterface implementation that inspects mapping metadata and returns service-loaded values. |
tests/ObjectMapper/Fixtures/ServiceLoadedValue/ValueToMap.php |
Source with #[Map(target: LoadedValueTarget::class)] to test class-level service-loaded relation transforms. |
tests/ObjectMapper/Fixtures/ServiceLoadedValue/ValueToMapRelation.php |
Related value annotated with #[Map(..., transform: ServiceLoadedValueTransformer::class)] to drive service-based relation mapping. |
tests/ObjectMapper/Fixtures/ServiceLocator/A.php |
Source annotated to use service-locator-based transform and condition callables. |
tests/ObjectMapper/Fixtures/ServiceLocator/B.php |
Target with property bar used to validate service-based mapping behavior. |
tests/ObjectMapper/Fixtures/ServiceLocator/ConditionCallable.php |
Condition callable implementing Symfony’s ConditionCallableInterface for use via service locator. |
tests/ObjectMapper/Fixtures/ServiceLocator/TransformCallable.php |
Transform callable implementing TransformCallableInterface to be used from the service locator. |
tests/ObjectMapper/Fixtures/TargetTransform/SourceEntity.php |
Source entity with name for target-transform tests. |
tests/ObjectMapper/Fixtures/TargetTransform/TargetDto.php |
Target DTO with class-level #[Map(..., transform: [self::class, 't'])] verifying target transform semantics. |
tests/ObjectMapper/Fixtures/TransformCollection/TransformCollectionA.php |
Source with #[Map(transform: new MapCollection())] to test collection-wide transforms. |
tests/ObjectMapper/Fixtures/TransformCollection/TransformCollectionB.php |
Target DTO with foo array of TransformCollectionD used to verify transformed collection element types. |
tests/ObjectMapper/Fixtures/TransformCollection/TransformCollectionC.php |
Element source annotated to map to TransformCollectionD and remap bar→baz. |
tests/ObjectMapper/Fixtures/TransformCollection/TransformCollectionD.php |
Target element class with baz used in collection transform assertions. |
tests/ObjectMapper/Fixtures/DefaultLazy/OrderSource.php |
(Duplicate noted earlier) Source for lazy order mapping; supports mapping with nested lazy user. |
tests/ObjectMapper/Fixtures/DefaultLazy/OrderTarget.php |
(Duplicate noted earlier) Target for lazy order mapping (id + user). |
tests/ObjectMapper/Fixtures/DefaultLazy/UserSource.php |
(Duplicate noted earlier) Source user for default lazy mapping. |
tests/ObjectMapper/Fixtures/DefaultLazy/UserTarget.php |
(Duplicate noted earlier) Target user for default lazy mapping. |
tests/ObjectMapper/Fixtures/HydrateObject/SourceOnly.php |
(Duplicate noted earlier) Constructor-only DTO mapping from source object properties. |
tests/ObjectMapper/Fixtures/EmbeddedMapping/* |
(Summarized above individually) Fixtures for embedded mapping of address into user. |
tests/ObjectMapper/Fixtures/Flatten/* |
(Summarized above individually) Fixtures for flattening nested profile into user DTO. |
tests/ObjectMapper/Fixtures/PartialInput/* |
(Summarized above individually) Fixtures for partial input to final input mapping. |
tests/ObjectMapper/Fixtures/PromotedConstructor*/* |
(Summarized above individually) Fixtures for promoted-constructor mapping tests. |
tests/ObjectMapper/Fixtures/ReadOnlyPromotedProperty/* |
(Summarized above individually) Fixtures for readonly-promoted-property lazy loading tests. |
tests/ObjectMapper/Fixtures/Recursion/* |
(Summarized above individually) Fixtures for recursion mapping tests. |
tests/ObjectMapper/Fixtures/ServiceLoadedValue/* |
(Summarized above individually) Fixtures for service-loaded relation tests. |
tests/ObjectMapper/Fixtures/ServiceLocator/* |
(Summarized above individually) Fixtures for service-locator-based transform and condition tests. |
tests/ObjectMapper/Fixtures/TargetTransform/* |
(Summarized above individually) Fixtures for target-transform tests. |
tests/ObjectMapper/Fixtures/TransformCollection/* |
(Summarized above individually) Fixtures for collection transform tests. |
tests/ObjectMapper/Fixtures/MyProxy.php |
(Summarized above) Proxy subject for native PHP 8.4 lazy object tests. |
tests/ObjectMapper/Fixtures/DefaultValueStdClass/TargetDto.php |
(Summarized above) Fixture for default-value mapping from stdClass. |
tests/AutoMapperBuilder.php |
Test helper updated to pass an extraServices array into AutoMapper::create for registering object-mapper-related services. |
src/AutoMapper.php |
Extends AutoMapper::create() to accept extraMapperServices and registers them into the internal service locator. |
src/AttributeReference/Reference.php |
Adds getReferenceExpression() to encapsulate building ReflectionReference AST nodes for attributes. |
src/Event/GenerateMapperEvent.php |
Extends event to carry a typed Provider object and to extend Symfony’s Event base for propagation control. |
src/Event/PropertyMetadataEvent.php |
Allows the if field to be either a string or an AttributeReference\Reference to support object-mapper callbacks. |
src/EventListener/ApiPlatform/JsonLdListener.php |
Adapts provider assignment to use the new Provider value object for JSON-LD IRI provider. |
src/EventListener/Doctrine/DoctrineProviderListener.php |
Updates Doctrine provider selection to use the new typed Provider. |
src/EventListener/MapProviderListener.php |
Wraps resolved provider IDs into Metadata\Provider instead of raw strings. |
src/EventListener/ObjectMapper/MapListener.php |
New abstract base for object-mapper-specific listeners that converts Symfony #[Map] attributes into AutoMapper transformers (including service-locator and expression-language handling). |
src/EventListener/ObjectMapper/MapSourceListener.php |
Translates source-side Symfony #[Map] attributes into PropertyMetadataEvents and sets up proper providers and conditions. |
src/EventListener/ObjectMapper/MapTargetListener.php |
Translates target-side #[Map] attributes into metadata, including support for class-level transforms as providers. |
src/Generator/MapMethodStatementsGenerator.php |
Adds lazy-object initialization logic and refactors provider handling to support both AutoMapper and ObjectMapper-based providers via the new Provider type. |
src/Generator/PropertyConditionsGenerator.php |
Extends condition generation to support AttributeReference\Reference and Symfony ConditionCallableInterface-based conditions, and adjusts callable invocation signatures. |
src/MapperContext.php |
Adds new context flags INITIALIZE_LAZY_OBJECT and LAZY_MAPPING, and types class constants for safer use. |
src/Metadata/GeneratorMetadata.php |
Changes the provider field to the new Provider object type. |
src/Metadata/MapperMetadata.php |
Adjusts generated mapper class names to handle anonymous classes more gracefully by normalizing their names. |
src/Metadata/MetadataFactory.php |
Wires new object-mapper listeners, updates provider handling, and ensures PropertyMetadata construction supports Reference-backed conditions. |
src/Metadata/PropertyMetadata.php |
Allows the if property to be either a string or a Reference for attribute-based conditions. |
src/Metadata/Provider.php |
Introduces a typed value object representing provider type and identifier, with flags to distinguish ObjectMapper-origin providers. |
src/ObjectMapper/ObjectMapper.php |
New implementation of Symfony’s ObjectMapperInterface delegating to AutoMapper, with support for mapping selection, transform callables, and robust error handling. |
src/Transformer/ObjectMapper/TransformCallableTransformer.php |
New property transformer bridging Symfony TransformCallableInterface into AutoMapper’s PropertyTransformerInterface. |
src/Transformer/ReferenceTransformer.php |
Refactors to use Reference::getReferenceExpression() and to support both AutoMapper and ObjectMapper-style transform methods (transform vs transformer). |
src/Transformer/ServiceLocatorTransformer.php |
New transformer that resolves Symfony transform callables from the service locator and invokes them with (value, source, target). |
phpstan.neon |
Adds an ignore rule for phpstan’s generic return-type complaint on ObjectMapper::map(). |
composer.json |
Adds symfony/object-mapper as a dev requirement and targets PHP 8.4+, aligning with new features (typed constants, native lazy objects). |
CHANGELOG.md |
Documents support for ObjectMapper attributes and the new Symfony ObjectMapperInterface implementation (with a minor spelling issue flagged separately). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
331faad to
576c799
Compare
Korbeil
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having Symfony's ObjectMapper is really awesome, thanks 😍
576c799 to
ec15b9c
Compare
No description provided.