Installation:
composer require ehyiah/mapping-bundle
For non-Flex projects, manually add to composer.json:
"require": {
"ehyiah/mapping-bundle": "^1.0"
}
Enable the bundle in config/bundles.php:
return [
// ...
Ehyiah\MappingBundle\MappingBundle::class => ['all' => true],
];
First Use Case: Map a DTO to an Entity for form handling:
use Ehyiah\MappingBundle\Mapper\MapperAwareInterface;
use Ehyiah\MappingBundle\Mapper\MapperAwareTrait;
class UserDto implements MapperAwareInterface
{
use MapperAwareTrait;
private string $name;
private string $email;
// Getters/setters...
}
class User // Entity
{
private string $name;
private string $email;
// Getters/setters...
}
// In a controller/service:
$mapper = $this->get('ehyiah_mapping.mapper');
$userDto = new UserDto();
$userDto->setName('John');
$userDto->setEmail('[email protected]');
$user = $mapper->mapToTarget($userDto, new User());
ehyiah_mapping.mapper (autowired or via DI container).README.md for method signatures and basic examples.tests/ for edge cases (e.g., nested objects, type mismatches).User with sensitive fields).UserEditDto) and map to/from the entity.
// Controller
$form = $this->createForm(UserEditDtoType::class, $dto);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$mapper->mapToTarget($dto, $userEntity); // Sync DTO → Entity
$entityManager->flush();
}
mapFromTarget to update a DTO from an entity (e.g., after DB fetch):
$userEntity = $entityManager->find(User::class, $id);
$mapper->mapFromTarget($userEntity, $userDto);
setMapping():
$mapper->setMapping($sourceClass, $targetClass, [
'sourceProperty' => 'targetProperty',
// Custom logic via callables:
'sourceMethod' => function ($source) {
return strtoupper($source->getName());
},
]);
MapperAwareInterface in DTOs to auto-configure form fields:
class UserEditDto implements MapperAwareInterface
{
use MapperAwareTrait;
// ...
}
// FormType
$builder->add('name', TextType::class, [
'mapped' => false, // Manually map via MapperBundle
]);
User with Address):
$mapper->mapToTarget($userDto, $userEntity);
// Address is auto-mapped if both DTO/Entity implement MapperAwareInterface.
$mapper->addListener(new class implements MappingListenerInterface {
public function onPreMap($source, $target, MappingEvent $event) {
// Modify $target before mapping.
}
});
$users = $mapper->mapToTargetCollection($userDtos, [], User::class);
Circular References
User ↔ Profile) may cause infinite loops.ignoreProperties:
$mapper->mapToTarget($source, $target, [], ['ignoredProperty']);
Type Mismatches
string ↔ int).$mapper->setStrictMode(true); // Throws exceptions on type errors.
Lazy-Loaded Entities
mapFromTarget after fetching all required data:
$entityManager->refresh($entity); // Ensure data is loaded.
Overwriting Data
mapToTarget overwrites existing target properties.$mapper->setMergeMode(true); // Preserve existing values.
# config/packages/ehyiah_mapping.yaml
ehyiah_mapping:
debug: true # Logs mapping operations.
$mapper->getMappings(); // View registered mappings.
Custom Mappers
MapperInterface for domain-specific logic:
class CustomMapper implements MapperInterface {
public function map($source, $target, array $options = []) {
// Custom logic.
}
}
services:
App\Mapper\CustomMapper:
tags: ['ehyiah_mapping.mapper']
Property Transformers
$mapper->setMapping(UserDto::class, User::class, [
'rawName' => function ($value) {
return trim($value); // Sanitize input.
},
]);
Event-Driven Extensions
MappingEvent for pre/post-processing:
$mapper->addListener(new class implements MappingListenerInterface {
public function onPostMap($source, $target, MappingEvent $event) {
if ($target instanceof User) {
$target->setUpdatedAt(new \DateTime());
}
}
});
mapToTargetCollection) is more efficient than looping.config/bundles.php is updated post-install.How can I help you explore Laravel packages today?