Installation:
composer require pourbahrami/mapper
No publisher or service provider is required—use the package directly via the Mapper facade or helper.
First Use Case: Map an array to an object (e.g., API response → Eloquent model):
use Pourbahrami\Mapper\Facades\Mapper;
$data = ['name' => 'John', 'email' => '[email protected]'];
$user = Mapper::map($data, new \App\Models\User());
Or map between objects:
$source = new \App\Models\ApiUser($data);
$destination = new \App\Models\User();
Mapper::map($source, $destination);
Where to Look First:
Basic Mapping:
Use Mapper::map() for simple array-to-object or object-to-object transformations.
// Array → Model
$model = Mapper::map($request->all(), new \App\Models\Post());
// Object → Object
$apiUser = new \App\DTOs\ApiUser($apiResponse);
$user = new \App\Models\User();
Mapper::map($apiUser, $user);
Custom Mappers:
Extend \Pourbahrami\Mapper\Contracts\Mapper for domain-specific logic:
class UserMapper extends \Pourbahrami\Mapper\AbstractMapper
{
protected $sourceClass = \App\DTOs\ApiUser::class;
protected $destinationClass = \App\Models\User::class;
public function map()
{
$this->mapProperty('name', 'full_name');
$this->mapProperty('email', 'email_address');
}
}
Register via config or service provider.
Nested Objects: Handle nested structures with dot notation:
$data = ['author' => ['name' => 'Jane']];
$post = new \App\Models\Post();
Mapper::map($data, $post, ['author.name' => 'author_name']);
Conditional Mapping:
Use when() to apply logic:
Mapper::map($data, $model)
->when(fn($src) => $src['is_admin'], fn($dst) => $dst->setRole('admin'));
public function store(StoreUserRequest $request)
{
$user = Mapper::map($request->validated(), new \App\Models\User());
$user->save();
}
$apiUsers = Mapper::mapCollection($apiResponse['data'], \App\DTOs\ApiUser::class);
$users = Mapper::mapCollection($apiUsers, \App\Models\User::class);
Property Mismatches:
ignoreMissingProperties() or define explicit mappings:
Mapper::map($data, $model, ['name' => 'full_name'])->ignoreMissingProperties();
Circular References:
Mapper::map() with depth parameter or implement Serializable in custom mappers.Type Conflicts:
Mapper::cast():
Mapper::map($data, $model)->cast('published_at', 'datetime');
Performance:
Mapper::batchMap() for collections.Mapper::debug(true); // Logs all mapping operations to Laravel logs.
Mapper::getMappings() to verify registered property mappings.Custom Strategies:
Override \Pourbahrami\Mapper\Strategies\PropertyMapper for custom property handling (e.g., encryption).
Event Hooks:
Bind to mapping.before/mapping.after events for pre/post-processing:
event(new \Pourbahrami\Mapper\Events\MappingEvent($source, $destination));
Configuration:
Override defaults in config/mapper.php:
'default_strategy' => \App\Strategies\CustomMapper::class,
'ignore_properties' => ['password', 'api_token'],
Testing:
Mock the Mapper facade or use Mapper::shouldReceive('map')->once() in PHPUnit tests.
How can I help you explore Laravel packages today?