Installation
Add the bundle to your composer.json:
composer require bcc/auto-mapper-bundle
Enable it in config/bundles.php:
return [
// ...
Bcc\AutoMapperBundle\BCCAutoMapperBundle::class => ['all' => true],
];
Basic Configuration
Define mappings in config/packages/bcc_auto_mapper.yaml:
bcc_auto_mapper:
mappings:
App\Entity\User: App\DTO\UserDTO
App\Entity\Post: App\DTO\PostDTO
First Use Case Map an entity to a DTO in a controller:
use Bcc\AutoMapperBundle\AutoMapper\AutoMapperInterface;
class UserController extends AbstractController
{
public function show(User $user, AutoMapperInterface $mapper)
{
$dto = $mapper->map($user, UserDTO::class);
return $this->json($dto);
}
}
Explicit Mapping Define mappings in YAML for clarity:
bcc_auto_mapper:
mappings:
App\Entity\Order:
App\DTO\OrderDTO:
- orderId
- customerId
- createdAt
- status
Dynamic Mapping
Use the map() method with runtime classes:
$mapper->map($entity, $dtoClass, $options);
Nested Object Mapping Automatically map nested entities:
bcc_auto_mapper:
mappings:
App\Entity\Order:
App\DTO\OrderDTO:
- customer: App\Entity\Customer:App\DTO\CustomerDTO
Custom Logic via Callbacks Inject custom logic for specific fields:
bcc_auto_mapper:
mappings:
App\Entity\User:
App\DTO\UserDTO:
- email
- fullName: [getFullName, ['firstName', 'lastName']]
Service Integration
Inject AutoMapperInterface into services:
class OrderService
{
public function __construct(private AutoMapperInterface $mapper) {}
public function createOrderFromRequest(Request $request)
{
$order = $this->mapper->map($request->request->all(), Order::class);
// ...
}
}
Circular References
Avoid circular references in mappings (e.g., User ↔ Profile ↔ User). Use ignore or break cycles manually:
bcc_auto_mapper:
mappings:
App\Entity\User:
App\DTO\UserDTO:
- profile: ignore
Property Name Mismatches The mapper assumes property names match exactly. Use aliases or custom logic for mismatches:
bcc_auto_mapper:
mappings:
App\Entity\User:
App\DTO\UserDTO:
- userId: id
Lazy Loading If entities use lazy loading (e.g., Doctrine), ensure related objects are loaded before mapping:
$user->load('profile'); // Manually load if needed
$dto = $mapper->map($user, UserDTO::class);
Performance with Large Datasets Mapping collections can be slow. Use batch processing or limit fields:
bcc_auto_mapper:
mappings:
App\Entity\Post[]:
App\DTO\PostDTO[]:
- id
- title
- excerpt
Enable Verbose Logging
Add to config/packages/bcc_auto_mapper.yaml:
bcc_auto_mapper:
debug: true
Logs will show mapping attempts and failures.
Check for Undefined Mappings
Use hasMapping() to verify mappings exist:
if (!$mapper->hasMapping(User::class, UserDTO::class)) {
throw new \RuntimeException('Mapping not configured!');
}
Override Default Behavior Extend the mapper for custom logic:
class CustomMapper extends AbstractMapper
{
protected function mapProperty($source, $target, $property, $value)
{
if ($property === 'password') {
return bcrypt($value);
}
return parent::mapProperty($source, $target, $property, $value);
}
}
Register it as a service:
services:
App\Mapper\CustomMapper:
tags: [bcc_auto_mapper.mapper]
Custom Type Handlers
Handle non-standard types (e.g., DateTime):
$mapper->addTypeHandler(DateTime::class, function ($value) {
return $value->format('Y-m-d');
});
Pre/Post Mapping Hooks Use events for side effects:
$dispatcher->addListener('bcc_auto_mapper.pre_map', function ($event) {
if ($event->getSource() instanceof User) {
$event->setTargetProperty('fullName', 'Admin');
}
});
Conditional Mapping Dynamically enable/disable mappings:
if ($user->isActive()) {
$mapper->map($user, ActiveUserDTO::class);
} else {
$mapper->map($user, InactiveUserDTO::class);
}
Priority of Mappings Later mappings override earlier ones. Define specific mappings last.
Array vs. Object Mappings
For arrays, use [] in the target class:
bcc_auto_mapper:
mappings:
App\Entity\Post[]:
App\DTO\PostDTO[]:
- id
- title
Symfony 4+ Compatibility The bundle is designed for Symfony 2/3. For Symfony 4+, ensure autowiring is configured:
services:
Bcc\AutoMapperBundle\AutoMapper\AutoMapperInterface: '@bcc_auto_mapper.mapper'
How can I help you explore Laravel packages today?