elaitech / data-mapper
Elaitech DataMapper - A reusable data mapping and transformation component for Laravel.
Installs: 3
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/elaitech/data-mapper
Requires
- php: ^8.4
- illuminate/support: ^12.0
- spatie/laravel-data: ^4.19
Requires (Dev)
- laravel/pint: ^1.24
- orchestra/testbench: ^10.0
- phpunit/phpunit: ^11.5.3
This package is auto-updated.
Last update: 2026-02-16 02:06:12 UTC
README
A reusable data mapping and transformation library for Laravel 12. Maps source fields to target fields with chained value transformers, dot-notation and wildcard field extraction, value mapping lookups, and full support for both associative and indexed (header-based) data rows.
Namespace:
Elaitechx\DataMapper
Requires: PHP 8.4+ ยท Laravel 12 ยทspatie/laravel-data^4.19
๐ Table of Contents
- Installation
- Architecture
- Quick Start
- Core Components
- Built-in Transformers
- Field Extraction
- Value Mapping
- Creating Custom Transformers
- DTOs
- Contracts
- Testing
- License
๐ Installation
As a local Composer package
In your root composer.json, add the package as a path repository:
{
"repositories": [
{
"type": "path",
"url": "./packages/data-mapper",
"options": { "symlink": true }
}
],
"require": {
"elaitech/data-mapper": "@dev"
}
}
Then install:
composer update elaitech/data-mapper
The DataMapperServiceProvider is auto-discovered by Laravel. It registers:
DataMapperInterfaceโDataMapperService(binding)ValueTransformerโ singleton with 10 built-in transformersFieldExtractorโ singleton
๐ Architecture
src/
โโโ DataMapperService.php # Main entry point โ maps data rows using rules
โโโ DataMapperServiceProvider.php # Laravel auto-discovery provider
โโโ FieldExtractor.php # Dot-notation & wildcard field extraction
โโโ ValueTransformer.php # Transformer registry & value transformation engine
โ
โโโ Contracts/
โ โโโ DataMapperInterface.php # Main service contract
โ โโโ TransformerInterface.php # Interface for all transformers
โ
โโโ DTO/
โ โโโ MappingConfigurationData.php # Input: data + rules + headers
โ โโโ MappingRuleData.php # Single mapping rule definition
โ โโโ DataMappingResultData.php # Output: mapped data + errors
โ
โโโ Transformers/ # 10 built-in transformers
โโโ NoneTransformer.php
โโโ TrimTransformer.php
โโโ UpperTransformer.php
โโโ LowerTransformer.php
โโโ IntegerTransformer.php
โโโ FloatTransformer.php
โโโ BooleanTransformer.php
โโโ DateTransformer.php
โโโ ArrayFirstTransformer.php
โโโ ArrayJoinTransformer.php
โก Quick Start
use Elaitech\DataMapper\Contracts\DataMapperInterface; use Elaitech\DataMapper\DTO\MappingConfigurationData; use Elaitech\DataMapper\DTO\MappingRuleData; use Spatie\LaravelData\DataCollection; $mapper = app(DataMapperInterface::class); $config = new MappingConfigurationData( data: [ ['name' => 'John Doe', 'email' => 'john@example.com', 'age' => '30'], ['name' => 'Jane Smith', 'email' => 'jane@example.com', 'age' => '25'], ], mappingRules: MappingRuleData::collection([ new MappingRuleData( sourceField: 'name', targetField: 'full_name', transformation: 'trim', ), new MappingRuleData( sourceField: 'email', targetField: 'contact_email', transformation: 'lower', ), new MappingRuleData( sourceField: 'age', targetField: 'user_age', transformation: 'integer', ), ]), ); $result = $mapper->map($config); // $result->data = [ // ['full_name' => 'John Doe', 'contact_email' => 'john@example.com', 'user_age' => 30], // ['full_name' => 'Jane Smith', 'contact_email' => 'jane@example.com', 'user_age' => 25], // ] // $result->errors = []
๐งฉ Core Components
DataMapperService
The main service class. Implements DataMapperInterface.
public function map(MappingConfigurationData $config): DataMappingResultData
Behaviour:
- Automatically detects whether rows are associative (
['name' => 'John']) or indexed (['John', 'john@example.com']) - For indexed rows, uses the
headersarray to resolve field positions - Wraps each row in a try/catch โ failed rows are captured as errors, not exceptions
- Returns
DataMappingResultDatawith mapped data and any per-row errors
FieldExtractor
Extracts values from data using:
| Pattern | Example | Description |
|---|---|---|
| Direct access | name |
Top-level field |
| Dot notation | address.city |
Nested field traversal |
| Wildcard | items.*.name |
Extract from all array elements |
$extractor = app(FieldExtractor::class); $data = [ 'user' => ['profile' => ['name' => 'John']], 'items' => [ ['name' => 'A', 'price' => 10], ['name' => 'B', 'price' => 20], ], ]; $extractor->extractValue($data, 'user.profile.name'); // 'John' $extractor->extractArrayValues($data, 'items.*.name'); // ['A', 'B'] $extractor->hasField($data, 'user.profile.name'); // true
ValueTransformer
The transformer registry and execution engine. Manages all registered transformers and applies transformation chains.
$transformer = app(ValueTransformer::class); // Check available transformers $transformer->getTransformerOptions(); // ['none' => 'None', 'trim' => 'Trim', ...] // Register a custom transformer $transformer->registerTransformer(new MyCustomTransformer());
Transformation flow:
- Check if value is empty โ return
defaultValue(unless it's an array transformer) - Apply value mapping if configured (lookup table)
- Apply transformer (type conversion, formatting)
- If result is empty string and
defaultValueis set โ returndefaultValue
๐ง Built-in Transformers
| Name | Label | Description | Requires Format |
|---|---|---|---|
none |
None | Pass-through, no transformation | โ |
trim |
Trim | Remove leading/trailing whitespace | โ |
upper |
Uppercase | Convert to UPPERCASE | โ |
lower |
Lowercase | Convert to lowercase | โ |
integer |
Integer | Cast to int |
โ |
float |
Float | Cast to float with precision control |
โ (decimals) |
boolean |
Boolean | Cast to bool (handles "true", "1", "yes", etc.) |
โ |
date |
Date | Parse and reformat dates | โ (date format) |
array_first |
Array First | Extract first element from array | โ |
array_join |
Array Join | Join array elements with separator | โ (separator) |
๐บ Field Extraction
Dot Notation
Access nested fields in associative arrays:
// Source data ['address' => ['street' => '123 Main St', 'city' => 'NYC']] // Mapping rule: sourceField = 'address.city' // Extracted value: 'NYC'
Wildcard Notation
Extract values from arrays of objects:
// Source data ['images' => [ ['url' => 'img1.jpg', 'alt' => 'First'], ['url' => 'img2.jpg', 'alt' => 'Second'], ]] // Mapping rule: sourceField = 'images.*.url' // Extracted value: ['img1.jpg', 'img2.jpg']
Indexed (Header-Based) Rows
For data without keys (e.g., CSV rows), provide headers:
$config = new MappingConfigurationData( data: [ ['John', 'john@example.com', '30'], ['Jane', 'jane@example.com', '25'], ], mappingRules: MappingRuleData::collection([ new MappingRuleData(sourceField: 'name', targetField: 'full_name'), new MappingRuleData(sourceField: 'email', targetField: 'contact'), ]), headers: ['name', 'email', 'age'], );
๐ Value Mapping
Map specific values using a lookup table. Useful for code-to-label conversions:
new MappingRuleData( sourceField: 'condition_code', targetField: 'condition', transformation: 'none', valueMapping: [ ['from' => '0', 'to' => 'Used'], ['from' => '1', 'to' => 'New'], ['from' => '2', 'to' => 'Refurbished'], ], ); // Input: '1' โ Output: 'New' // Input: '0' โ Output: 'Used' // Input: '99' โ Output: '99' (unmapped values pass through)
Value mapping is applied before the transformer, so you can combine both:
new MappingRuleData( sourceField: 'status', targetField: 'display_status', transformation: 'upper', valueMapping: [['from' => '1', 'to' => 'active'], ['from' => '0', 'to' => 'inactive']], ); // Input: '1' โ mapped to 'active' โ transformed to 'ACTIVE'
๐ Creating Custom Transformers
Implement the TransformerInterface:
use Elaitech\DataMapper\Contracts\TransformerInterface; final class SlugTransformer implements TransformerInterface { public function getName(): string { return 'slug'; } public function getLabel(): string { return 'Slugify'; } public function getDescription(): string { return 'Converts text to URL-friendly slug'; } public function transform($value, ?string $format = null, $defaultValue = null) { if ($value === null) { return $defaultValue; } return \Illuminate\Support\Str::slug((string) $value); } public function requiresFormat(): bool { return false; } }
Register it:
$transformer = app(ValueTransformer::class); $transformer->registerTransformer(new SlugTransformer());
Or register in a service provider for global availability:
public function boot(): void { $this->app->make(ValueTransformer::class) ->registerTransformer(new SlugTransformer()); }
๐ DTOs
MappingConfigurationData
Input to the mapper:
| Property | Type | Description |
|---|---|---|
data |
array |
Array of rows to map |
mappingRules |
DataCollection<MappingRuleData> |
Mapping rules to apply |
headers |
?array |
Column headers for indexed rows |
MappingRuleData
A single field mapping rule:
| Property | Type | Default | Description |
|---|---|---|---|
sourceField |
string |
โ | Source field name (supports dot/wildcard notation) |
targetField |
string |
โ | Target field name in output |
transformation |
string |
'none' |
Transformer name to apply |
isRequired |
bool |
false |
Throw if source field is missing |
defaultValue |
mixed |
null |
Fallback for empty values |
format |
?string |
null |
Format parameter for transformers (e.g., date format) |
valueMapping |
?array |
null |
Value lookup table ([['from' => ..., 'to' => ...]]) |
DataMappingResultData
Output from the mapper:
| Property | Type | Description |
|---|---|---|
data |
array |
Successfully mapped rows |
errors |
array |
Per-row error messages |
๐ Contracts
DataMapperInterface
interface DataMapperInterface { public function map(MappingConfigurationData $config): DataMappingResultData; }
TransformerInterface
interface TransformerInterface { public function getName(): string; public function getLabel(): string; public function getDescription(): string; public function transform($value, ?string $format = null, $defaultValue = null); public function requiresFormat(): bool; }
๐งช Testing
# From the package directory ./vendor/bin/phpunit # From the root project php artisan test
๐ฆ Dependencies
| Package | Version | Purpose |
|---|---|---|
illuminate/support |
^12.0 | Laravel framework support |
spatie/laravel-data |
^4.19 | Typed DTOs with auto-mapping |
๐ License
MIT