PHP code example of mark-gerarts / auto-mapper-plus

1. Go to this page and download the library: Download mark-gerarts/auto-mapper-plus library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

mark-gerarts / auto-mapper-plus example snippets




class Employee
{
    private $id;
    private $firstName;
    private $lastName;
    private $birthYear;
    
    public function __construct($id, $firstName, $lastName, $birthYear)
    {
        $this->id = $id;
        $this->firstName = $firstName;
        $this->lastName = $lastName;
        $this->birthYear = $birthYear;
    }

    public function getId()
    {
        return $this->id;
    }

    // And so on...
}

class EmployeeDto
{
    // While the properties are public for this example, we can map to private
    // or protected properties just the same.
    public $firstName;
    public $lastName;
    public $age;
}



use AutoMapperPlus\Configuration\AutoMapperConfig;
use AutoMapperPlus\AutoMapper;

$config = new AutoMapperConfig();

// Simply registering the mapping is enough to convert properties with the same
// name. Custom actions can be registered for each individual property.
$config
    ->registerMapping(Employee::class, EmployeeDto::class)
    ->forMember('age', function (Employee $source) {
        return date('Y') - $source->getBirthYear();
    })
    ->reverseMap(); // Register the reverse mapping as well.
                            
$mapper = new AutoMapper($config);

// With this configuration we can start converting our objects.
$john = new Employee(10, "John", "Doe", 1980);
$dto = $mapper->map($john, EmployeeDto::class);

echo $dto->firstName; // => "John"
echo $dto->lastName; // => "Doe"
echo $dto->age; // => 37



use AutoMapperPlus\Configuration\AutoMapperConfig;
use AutoMapperPlus\AutoMapper;

$config = new AutoMapperConfig();
$config->registerMapping(Source::class, Destination::class);
$mapper = new AutoMapper($config);



$mapper = AutoMapper::initialize(function (AutoMapperConfig $config) {
    $config->registerMapping(Source::class, Destination::class);
    $config->registerMapping(AnotherSource::class, Destination::class);
    // ...
});



$john = new Employee("John", "Doe", 1980);

// Map the source object to a new instance of the destination class.
$mapper->map($john, EmployeeDto::class);

// Mapping to an existing object is possible as well.
$mapper->mapToObject($john, new EmployeeDto());

// Map a collection using mapMultiple
$mapper->mapMultiple($employees, EmployeeDto::class);



$config->registerMapping(Employee::class, EmployeeDto::class);



$config->registerMapping(Employee::class, EmployeeDto::class)
    ->forMember('fullName', function (Employee $source) {
        return $source->getFirstName() . ' ' . $source->getLastName();
    });



$getName = function ($source, AutoMapperInterface $mapper) { return 'John'; };

$mapping->forMember('name', $getName);
// The above is a shortcut for the following:
$mapping->forMember('name', Operation::mapFrom($getName));
// Which in turn is equivalent to:
$mapping->forMember('name', new MapFrom($getName));

// Other examples:
// Ignore this property.
$mapping->forMember('id', Operation::ignore());
// Map this property to the given class.
$mapping->forMember('employee', Operation::mapTo(EmployeeDto::class));
// Explicitly state what the property name is of the source object.
$mapping->forMember('name', Operation::fromProperty('unconventially_named_property'));
// The `FromProperty` operation can be chained with `MapTo`, allowing a
// differently named property to be mapped to a class.
$mapping->forMember(
    'address',
    Operation::fromProperty('adres')->mapTo(Address::class)
);
// SetTo sets the property to the given value.
$mapping->forMember('type', Operation::setTo('employee'));

// An extended example showing you can access the mapper in `MapFrom`.
$getColorPalette = function(SimpleXMLElement $XMLElement, AutoMapperInterface $mapper) {
    /** @var SimpleXMLElement $palette */
    $palette = $XMLElement->xpath('/product/specification/palette/colour');
    return $mapper->mapMultiple($palette, Color::class);
};
$mapping->forMember('palette', $getColorPalette);



// This assumes address is an object, or a collection of mappable
// objects if the source is an array/iterable.
$mapping->forMember('address', Operation::mapTo(Address::class));
// This is equivalent to:
$mapping->forMember('address', Operation::mapTo(Address::class, false));
// If you want to be very specific about the source being a collection, you
// can use `mapCollectionTo`. This is purely syntactic sugar; it is equivalent
// to the declarations above as well.
$mapping->forMember('addresses', Operation::mapCollectionTo(Address::class));

// On the other hand, if the source is an array that represents an object, you
// can use the following:
$mapping->forMember('address', Operation::mapTo(Address::class, true));
// Or nicer
$mapping->forMember('address', Operation::mapArrayTo(Address::class));



// This iterates over every property of the source property
// 'polymorphicChildren'. Each value will be mapped to the first existing
// mapping from the value to one of the given classes.
$config->createMapping(ChildA::class, ChildADto::class);
$config->createMapping(ChildB::class, ChildBDto::class);
$config->createMapping(Parent::class, ParentDto::class)
    ->forMember(
        'polymorphicChildren',
        Operation::mapToAnyOf([ChildADto::class, ChildBDto::class]
    ));



$config->registerMapping(Child::class, ChildDto::class);
$config->registerMapping(Parent::class, ParentDto::class)
    ->forMember('child', Operation::mapTo(ChildDto::class));



$config->registerMapping(Source::class, Destination::class)
    ->beConstructedUsing(function (Source $source, AutoMapperInterface $mapper): Destination {
        return new Destination($source->getProperty());
    });



// Either set it in the options:
$config->getOptions()->skipConstructor();
$mapper = new AutoMapper($config);

// Or set it on the mapping directly:
$config->registerMapping(Source::class, Destination::class)->skipConstructor();



// reverseMap() returns the new mapping, allowing to continue configuring the
// new mapping.
$config->registerMapping(Employee::class, EmployeeDto::class)
    ->reverseMap()
    ->forMember('id', Operation::ignore());

$config->hasMappingFor(Employee::class, EmployeeDto::class); // => True
$config->hasMappingFor(EmployeeDto::class, Employee::class); // => True



// Source class properties:         Destination class properties:
// - 'some_property',               - 'some_property'
// - 'some_alternative_property'    - 'some_other_property'
// - 'the_last_property'            - 'the_last_property'
//
$config->registerMapping(Source::class, Destination::class)
    ->forMember('some_property', Operation::ignore())
    ->forMember('some_other_property', Operation::fromProperty('some_alternative_property'))
    ->reverseMap();

// When mapping from Source to Destination, the following will happen:
// - some_property gets ignored
// - some_other_property gets mapped by using the value form some_alternative_property
// - the_last_property gets mapped because the names are equal.
//
// Now, when we go in the reverse direction things are different:
// - some_property gets mapped, because Ignore is not reversible
// - some_alternative_property gets mapped because FromProperty is reversible
// - the_last_property gets mapped as well



$detailMapping = $config->registerMapping(Employee::class, EmployeeDetailView::class)
    // Define operations and options ...
    ->forMember('age', function () {
        return 20;
    });

// You can copy a mapping by passing source and destination class. This will
// search the config for the relevant mapping.
$listMapping = $config->registerMapping(Employee::class, EmployeeListView::class)
    ->copyFrom(Employee::class, EmployeeDetailView::class)
    // Alternatively, copy a mapping by passing it directly.
    // ->copyFromMapping($detailMapping)
    //
    // You can now go ahead and define new operations, or override existing
    // ones.
    ->forMember('name', Operation::ignore())
    ->skipConstructor();



$config->getOptions()->createUnregisteredMappings();



use AutoMapperPlus\NameConverter\NamingConvention\CamelCaseNamingConvention;
use AutoMapperPlus\NameConverter\NamingConvention\SnakeCaseNamingConvention;

$config->registerMapping(CamelCaseSource::class, SnakeCaseDestination::class)
    ->withNamingConventions(
        new CamelCaseNamingConvention(), // The naming convention of the source class.
        new SnakeCaseNamingConvention() // The naming convention of the destination class.
    );

$source = new CamelCaseSource();
$source->propertyName = 'camel';

$result = $mapper->map($source, SnakeCaseDestination::class);
echo $result->property_name; // => "camel"



$config->registerMapping(Source::class, Destination::class)
    ->forMember('id', Operation::fromProperty('identifier'));



class Uppercase
{
    public $IMAPROPERTY;
}

class Lowercase
{
    public $imaproperty;
}

$uppercaseResolver = new CallbackNameResolver(function ($targetProperty) {
    return strtolower($targetProperty);
});

$config->registerMapping(Uppercase::class; Lowercase::class)
    ->withNameResolver($uppercaseResolver);

$uc = new Uppercase();
$uc->IMAPROPERTY = 'value';

$lc = $mapper->map($uc, Lowercase::class);
echo $lc->imaproperty; // => "value"



$config = new AutoMapperConfig();
$config->getOptions()->setDefaultMappingOperation(Operation::ignore());

$defaultMapping = $config->registerMapping(Source::class, Destination::class);
$overriddenMapping = $config->registerMapping(AnotherSource::class, Destination::class)
    ->withDefaultOperation(new DefaultMappingOperation());

$defaultMapping->getOptions()->getDefaultMappingOperation(); // => Ignore
$overriddenMapping->getOptions()->getDefaultMappingOperation(); // => DefaultMappingOperation



$config = new AutoMapperConfig();
$config->getOptions()->dontSkipConstructor();



// This will set the options for this specific mapping.
$config = new AutoMapperConfig(function (Options $options) {
    $options->dontSkipConstructor();
    $options->setDefaultMappingOperation(Operation::ignore());
    // ...
});



$config->registerMapping(Source::class, Destination::class)
    ->skipConstructor()
    ->withDefaultOperation(Operation::ignore());



$config->registerMapping(Source::class, Destination::class)
    ->setDefaults(function (Options $options) {
        $options->dontSkipConstructor();
        // ...
    });



// Register the mapping.
$config->registerMapping(\stdClass::class, Employee::class);
$mapper = new AutoMapper($config);

$employee = new \stdClass();
$employee->firstName = 'John';
$employee->lastName = 'Doe';

$result = $mapper->map($employee, Employee::class);
echo $result->firstName; // => "John"
echo $result->lastName; // => "Doe"



// Operations can still be registered.
$config->registerMapping(Employee::class, \stdClass::class)
    ->forMember('id', Operation::ignore());
$mapper = new AutoMapper($config);

$employee = new Employee(5, 'John', 'Doe', 1978);
$result = $mapper->map($employee, \stdClass::class);

echo $result->firstName; // => "John"
echo $result->lastName; // => "Doe"
var_dump(isset($result->id)); // => bool(false)



$config->registerMapping(CamelCaseSource::class, \stdClass::class)
    ->withNamingConventions(
        new CamelCaseNamingConvention(),
        new SnakeCaseNamingConvention()
    )
    // Operations have to be defined using the target property name.
    ->forMember('some_property', function () { return 'new value'; });
$mapper = new AutoMapper($config);

$source = new CamelCaseSource();
$source->someProperty = 'original value';
$source->anotherProperty = 'Another value';
$result = $mapper->map($employee, \stdClass::class);

var_dump(isset($result->someProperty)); // => bool(false)
echo $result->some_property; // => "new value"
echo $result->another_property; // => "Another value"



class YourObjectCrate { }

$config = new AutoMapperConfig(); // (Or pass a callable to the constructor)
$config->getOptions()->registerObjectCrate(YourObjectCrate::class);
$config->registerMapping(Employee::class, YourObjectCrate::class);
$mapper = new AutoMapper($config);

$employee = new Employee(5, 'John', 'Doe', 1978);
$result = $mapper->map($employee, YourObjectCrate::class);

echo $result->firstName; // => "John"
echo $result->lastName; // => "Doe"
echo get_class($result); // => "YourObjectCrate"



$config->registerMapping('array', Employee::class); // Alternatively, use the enum DataType::ARRAY
// Adding operations works just as you would expect.
$config->registerMapping(DataType::ARRAY, Employee::class)
    ->forMember('id', Operation::ignore())
    ->forMember('type', Operation::setTo('employee'))
    // Since arrays are oftentimes snake_case'd.
    ->withNamingConventions(
        new SnakeCaseNamingConvention(),
        new CamelCaseNamingConvention()
    );

// It is now possible to map an array to an employee:
$employee = [
    'id' => 5,
    'first_name' => 'John',
    'last_name' => 'Doe'
];
$result = $mapper->map($employee, Employee::class);
echo $result->firstName; // => "John"
echo $result->id; // => null
echo $result->type; // => "employee"



// You can either extend the CustomMapper, or just implement the MapperInterface
// directly.
class EmployeeMapper extends CustomMapper
{
    /**
     * @param Employee $source
     * @param EmployeeDto $destination
     * @return EmployeeDto
     */
    public function mapToObject($source, $destination)
    {
        $destination->id = $source->getId();
        $destination->firstName = $source->getFirstName();
        $destination->lastName = $source->getLastName();
        $destination->age = date('Y') - $source->getBirthYear();

        return $destination;
    }
}

$config->registerMapping(Employee::class, EmployeeDto::class)
    ->useCustomMapper(new EmployeeMapper());
$mapper = new AutoMapper($config);

// The AutoMapper can now be used as usual, but your custom mapper class will be
// called to do the actual mapping.
$employee = new Employee(10, 'John', 'Doe', 1980);
$result = $mapper->map($employee, EmployeeDto::class);



// This example shows how for example the current locale can be passed to alter
// the mapping behaviour.
$config->registerMapping(Employee::class, EmployeeDto::class)
    ->forMember(
        'honorific',
        function ($source, AutoMapperInterface $mapper, array $context): string {
            $translationKey = "honorific.{$source->getGender()}";
            return $this->translator->trans($translationKey, $context['locale']);
        }
    );

// Usage:
$mapper->map($employee, EmployeeDto::class, ['locale' => $request->getLocale()]);