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

Auto Mapper Plus Laravel Package

mark-gerarts/auto-mapper-plus

AutoMapper+ transfers data between PHP objects with minimal boilerplate, inspired by .NET AutoMapper. Define mappings with custom callbacks and operations, handle nested objects, construction, naming conventions, and map arrays/stdClass with configurable options.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require mark-gerarts/auto-mapper-plus
    

    For Laravel, consider using the Symfony bundle if applicable.

  2. Basic Setup: Initialize the mapper in a service provider (e.g., AppServiceProvider):

    use AutoMapperPlus\AutoMapper;
    use AutoMapperPlus\Configuration\AutoMapperConfig;
    
    public function boot()
    {
        $config = new AutoMapperConfig();
        $this->app->singleton(AutoMapper::class, function () use ($config) {
            return AutoMapper::initialize(function (AutoMapperConfig $config) {
                // Register mappings here (see below).
            });
        });
    }
    
  3. First Use Case: Map an entity to a DTO in a controller or service:

    $mapper = app(AutoMapper::class);
    $dto = $mapper->map($entity, EmployeeDto::class);
    

Implementation Patterns

Core Workflows

  1. Mapping Entities to DTOs: Register mappings in a dedicated config class (e.g., MappingConfig) or service provider:

    $config->registerMapping(Employee::class, EmployeeDto::class)
        ->forMember('age', function (Employee $source) {
            return date('Y') - $source->getBirthYear();
        });
    
  2. Collection Mapping: Use mapMultiple for arrays/collections:

    $dtos = $mapper->mapMultiple($employees, EmployeeDto::class);
    
  3. Nested Mappings: Handle relationships recursively:

    $config->registerMapping(Employee::class, EmployeeDto::class)
        ->forMember('address', Operation::mapTo(AddressDto::class));
    
  4. Polymorphic Mappings: Map to multiple possible child classes:

    $config->registerMapping(Parent::class, ParentDto::class)
        ->forMember('children', Operation::mapToAnyOf([
            ChildADto::class,
            ChildBDto::class
        ]));
    

Integration Tips

  • Dependency Injection: Bind AutoMapper as a singleton in Laravel’s service container.
  • Configuration Organization: Group mappings by domain (e.g., UserMapping, OrderMapping) and load them in the provider.
    $this->app->afterResolving(AutoMapper::class, function ($mapper) {
        $mapper->getConfiguration()->addMappings([new UserMapping(), new OrderMapping()]);
    });
    
  • Contextual Mapping: Pass context (e.g., locale, user) via closures:
    $config->registerMapping(Employee::class, EmployeeDto::class)
        ->forMember('name', function ($source, AutoMapper $mapper, $context) {
            return $mapper->translate($source->getName(), $context['locale']);
        });
    

Gotchas and Tips

Pitfalls

  1. Circular References: Avoid bidirectional mappings between the same classes (e.g., A → B and B → A with nested properties). Solution: Use ignore() or break cycles manually.

  2. Private Property Access: The mapper accesses private properties via reflection. Ensure your IDE/IDE helper (e.g., barryvdh/laravel-ide-helper) is configured to recognize them.

  3. Performance with Large Collections: mapMultiple processes items sequentially. For bulk operations, consider batching or parallel processing.

  4. Overriding Default Mappings: Explicitly register mappings for classes to avoid unexpected behavior with similar property names.

Debugging

  • Enable Verbose Logging:

    $config->getOptions()->setDebug(true);
    

    Logs mapping operations to storage/logs/automapper.log.

  • Validate Mappings: Use hasMappingFor() to check if a mapping exists:

    if (!$config->hasMappingFor(Source::class, Destination::class)) {
        throw new \RuntimeException("Mapping not registered!");
    }
    

Extension Points

  1. Custom Operations: Implement MappingOperationInterface for reusable logic (e.g., validation, formatting):

    class UppercaseOperation implements MappingOperationInterface {
        public function execute($source, $destinationProperty, $context) {
            return strtoupper($source);
        }
    }
    
  2. Dynamic Property Resolution: Use callbacks for runtime property name resolution:

    $config->registerMapping(Source::class, Destination::class)
        ->forMember('dynamicProp', Operation::fromProperty(function ($source) {
            return 'prop_' . $source->getType();
        }));
    
  3. Conditional Mapping: Skip properties based on conditions:

    $config->registerMapping(Source::class, Destination::class)
        ->forMember('sensitiveData', function ($source) {
            return app('auth')->check() ? $source->getData() : null;
        });
    

Laravel-Specific Tips

  • Service Provider Binding: Bind the mapper with context (e.g., request, auth):

    $this->app->singleton(AutoMapper::class, function ($app) {
        return AutoMapper::initialize(function (AutoMapperConfig $config) use ($app) {
            $config->getOptions()->setContext(['request' => $app['request']]);
        });
    });
    
  • Testing: Mock the mapper in tests:

    $mapper = Mockery::mock(AutoMapper::class);
    $mapper->shouldReceive('map')->andReturn(new EmployeeDto());
    
  • Caching Mappings: Cache the AutoMapperConfig in Laravel’s cache:

    $config = Cache::remember('automapper_config', 60, function () {
        return new AutoMapperConfig();
    });
    
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.
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle