Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Automapper Plus Bundle Laravel Package

mark-gerarts/automapper-plus-bundle

Symfony bundle integrating AutoMapperPlus for fast, configurable object-to-object mapping. Provides service wiring, profiles, and easy mapping between DTOs, entities, and view models with type safety and custom transformations.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Install the Bundle

    composer require mark-gerarts/automapper-plus-bundle
    

    Ensure the bundle is enabled in config/bundles.php:

    return [
        MarkGerarts\AutoMapperPlusBundle\AutoMapperPlusBundle::class => ['all' => true],
    ];
    
  2. Define a Mapping Profile Create a YAML file (e.g., config/automapper/mappings/user_mapping.yaml):

    MarkGerarts\AutoMapperPlusBundle\Mapping\Mapping:
        source: App\Entity\User
        destination: App\DTO\UserDTO
        by_method: 'mapUserToUserDTO'
    

    Or use annotations in your entity/DTO:

    use AutoMapperPlus\Annotation as AMP;
    
    #[AMP\Map(source: User::class, destination: UserDTO::class)]
    class UserDTO {}
    
  3. First Usage Inject the AutoMapperInterface into a service/controller:

    use AutoMapperPlus\AutoMapperInterface;
    
    public function __construct(private AutoMapperInterface $mapper) {}
    
    public function transformUser(User $user): UserDTO {
        return $this->mapper->map($user, UserDTO::class);
    }
    
  4. Verify Configuration Run the bundle’s validation command:

    php bin/console automapper:validate
    

Implementation Patterns

Core Workflows

1. DTO Mapping

Pattern: Map entities to DTOs for API responses or service boundaries.

// In a controller/service
$userDTO = $this->mapper->map($userEntity, UserDTO::class);
return $this->json($userDTO);

Best Practice: Use nested DTOs for complex objects:

# config/automapper/mappings/user_mapping.yaml
MarkGerarts\AutoMapperPlusBundle\Mapping\Mapping:
    source: App\Entity\User
    destination: App\DTO\UserDTO
    nested:
        - { source: address, destination: App\DTO\AddressDTO }

2. Bulk Mapping

Pattern: Optimize performance for collections (e.g., paginated API responses).

$usersDTO = $this->mapper->map($usersEntities, UserDTO::class, true); // true = bulk

Tip: Use true for bulk operations to leverage AutoMapper+’s batch processing.

3. Custom Logic

Pattern: Handle complex transformations with IValueResolver.

use AutoMapperPlus\ValueResolver\ValueResolverInterface;

class FullNameResolver implements ValueResolverInterface {
    public function resolve($source, $destination, $propertyPath, $context) {
        return $source->getFirstName() . ' ' . $source->getLastName();
    }
}

Register in YAML:

MarkGerarts\AutoMapperPlusBundle\Mapping\Mapping:
    source: App\Entity\User
    destination: App\DTO\UserDTO
    value_resolvers:
        - App\Resolver\FullNameResolver

4. Conditional Mapping

Pattern: Skip or transform properties based on conditions.

MarkGerarts\AutoMapperPlusBundle\Mapping\Mapping:
    source: App\Entity\Order
    destination: App\DTO\OrderDTO
    ignore:
        - sensitiveData
    conditional:
        - { property: discountApplied, condition: $source->getTotal() > 100 }

5. Service Integration

Pattern: Use mappings in Symfony services.

// src/Service/UserService.php
public function __construct(
    private AutoMapperInterface $mapper,
    private UserRepository $userRepo
) {}

public function getUserDTO(int $id): UserDTO {
    $user = $this->userRepo->find($id);
    return $this->mapper->map($user, UserDTO::class);
}

Tip: Autowire AutoMapperInterface directly—no manual configuration needed.


Advanced Patterns

Dynamic Mappings

Use Case: Map to different DTOs based on runtime logic.

$destinationClass = $isAdmin ? AdminUserDTO::class : UserDTO::class;
$dto = $this->mapper->map($user, $destinationClass);

Event-Driven Mapping

Use Case: Trigger mappings on Symfony events (e.g., kernel.request).

use Symfony\Component\HttpKernel\Event\ViewEvent;

public function onKernelView(ViewEvent $event) {
    $data = $event->getControllerResult();
    if ($data instanceof User) {
        $event->setControllerResult($this->mapper->map($data, UserDTO::class));
    }
}

Testing Mappings

Pattern: Unit test mappings with AutoMapperTestCase.

use AutoMapperPlus\Tests\AutoMapperTestCase;

class UserMappingTest extends AutoMapperTestCase {
    public function testUserToUserDTO() {
        $user = new User('John', 'Doe');
        $dto = $this->mapper->map($user, UserDTO::class);
        $this->assertEquals('John Doe', $dto->getFullName());
    }
}

Gotchas and Tips

Pitfalls

  1. Circular References

    • Issue: Mapping objects with bidirectional relationships (e.g., User ↔ Address) causes infinite loops.
    • Fix: Use ignore_circular_references: true in YAML or configure globally:
      # config/packages/automapper_plus.yaml
      automapper_plus:
          ignore_circular_references: true
      
  2. Property Name Mismatches

    • Issue: AutoMapper+ throws PropertyNotFoundException if property names differ (e.g., createdAt vs. created_at).
    • Fix: Use property_mappings in YAML:
      MarkGerarts\AutoMapperPlusBundle\Mapping\Mapping:
          source: App\Entity\User
          destination: App\DTO\UserDTO
          property_mappings:
              - { source: createdAt, destination: created_at }
      
  3. Performance Overhead

    • Issue: Reflection-based mapping slows down bulk operations.
    • Fix: Cache mappings globally:
      automapper_plus:
          cache_enabled: true
          cache_dir: '%kernel.cache_dir%/automapper'
      
  4. Configuration Overrides

    • Issue: Local mapping files override global settings unexpectedly.
    • Fix: Use priority in YAML to control precedence:
      MarkGerarts\AutoMapperPlusBundle\Mapping\Mapping:
          source: App\Entity\User
          destination: App\DTO\UserDTO
          priority: 100 # Higher = overrides lower-priority mappings
      
  5. Doctrine Proxy Issues

    • Issue: Mapping fails with LazyLoadingException for Doctrine proxies.
    • Fix: Initialize proxies before mapping:
      $user->getAddress(); // Force-load proxy
      $dto = $this->mapper->map($user, UserDTO::class);
      

Debugging Tips

  1. Enable Debug Mode Set environment variable:

    export AM_DEBUG=true
    

    Or in config/packages/automapper_plus.yaml:

    automapper_plus:
        debug: true
    
  2. Validate Mappings Run the validation command to catch misconfigurations early:

    php bin/console automapper:validate
    
  3. Log Mapping Steps Use a custom IValueResolver to log transformations:

    class DebugResolver implements ValueResolverInterface {
        public function resolve($source, $destination, $propertyPath, $context) {
            \Log::debug("Mapping $propertyPath: " . print_r($source, true));
            return $source;
        }
    }
    
  4. Check Cache Clear the cache if mappings behave unexpectedly:

    php bin/console cache:clear
    

Extension Points

  1. Custom Type Converters Use Case: Convert between non-standard types (e.g., DateTimeCarbon).

    use AutoMapperPlus\TypeConverter\TypeConverterInterface;
    
    class CarbonConverter implements TypeConverterInterface {
        public function convert($source, $destinationType, $context) {
            return Carbon::instance($source);
        }
    }
    

    Register in YAML:

    automapper_plus:
        type_converters:
            - App\Converter\CarbonConverter
    
  2. Event Listeners Use Case: Trigger actions before/after mapping (e.g., sanitize data).

    use AutoMapperPlus\Event\MappingEvent;
    
    public function onPreMap(MappingEvent $event) {
        if ($event->getSource() instanceof User) {
            $event->setSource($this
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
besmartand-pro/php-quality-config
sentix/ai-chatbot
terminal42/code-quality-tools
codifyo/ts-generator-bundle
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity