oscarricardosan / mapper
Paquete PHP que mapea los DocComments de la clase y permite definir mutators y accessors
Installs: 4 139
Dependents: 1
Suggesters: 0
Security: 0
Stars: 0
Watchers: 1
Forks: 0
Open Issues: 0
Requires
- php: >=5.6.4
Requires (Dev)
- phpunit/phpunit: ~5.0
This package is not auto-updated.
Last update: 2025-02-01 22:03:10 UTC
README
#Mapper
Paquete PHP agnóstico a frameworks provee una forma fácil con la cual mapear los atributos especificado en los DocComments de una clase, también permite agregar funcionalidad extra a través de mutators y accesors (setNameAttribute, getNameAttribute) al estilo de los Modelos de Laravel.
##1. Por qué Mapper?
El Principio de lo Explicito establece: Intenta siempre favorecer lo explícito sobre lo implícito.
Ser explicito a la hora de hacer código es algo que ayudara a quien hace el código y a sus posibles sucesores a la hora de entender que es lo que esta pasando. Ejemplo:
class Customer{
public function store($name, $city){
.....
}
}
Pero cuando tenemos un objeto con demasiados atributos ya no es tan fácil. ¡NO! la solución no es crear una función con más de 10 atributos. , en la mayoría de casos la solución es pasar un array con todos los atributos. Algo así:
class Customer{
public function store(array $data){
//En laravel
$customer = new Customer();
$customer->fill($data);
$customer->save();
}
}
Sin embargo, esto no es para nada explicito, cualquiera que llegue tendrá que hacer seguimiento para poer entener que es lo que esta llegando en el array $data.
Con Mapper podrías hacer:
class Customer{
public function store(CustomerMap $customerMap){
//Option A
$customer = new Customer();
$customer->name = $customerMap->name;
$customer->city = $customerMap->city;
$customer->country = $customerMap->country;
.....
$customer->save();
//Option B
$customer = new Customer();
$customer->fill($customerMap->getAttributes());
$customer->save();
}
}
##2. Instalación
Ejecutar en consola
composer require oscarricardosan/mapper
##3. Uso
###3.1. Definir una clase que extienda Mapper y tenga DocComments
Crea una clase que extienda a Mapper y en DocComments define las propiedades que van a ser mapeadas:
use Oscarricardosan\Mapper\Mapper;
/**
* @property $name
* @property $company "PHP Company"
* @property $document_type
* @property $document_number
* @property $city
* @property $state
* @property $country
* @property $car
*/
class CustomerMap extends Mapper
{
}
$customerMap = new CustomerMap();
Con lo anterior $customerMap ha quedado con las propiedades que estaban en los DocComments incluyendo los valores por defecto:
echo($customerMap->company); => "PHP Company"
echo($customerMap->name); => null
###3.2. Cargar valores
Existen dos formas para cargar valores a una clase que extiende de Mapper:
####3.2.1. Forma masiva
Ya sea por el __construct o por setAttributesFromArray, si la propiedad que viene en el array no esta declarada en los DocComments el la omitirá.
$sample = [
'name' => 'oscar',
'document_type' => 'cc',
'document_number' => '000255',
'country' => 'Colombia',
'city' => 'Moscú',
'state' => 'Bogota',
'car' => 'toyota',
];
Desde el constructor
$customerMap = new CustomerMap($sample);
echo($customerMap->name); => oscar
Con el método setAttributesFromArray
$customerMap = new CustomerMap();
$customerMap->setAttributesFromArray($ssample);
echo($customerMap->name); => oscar
####3.2.2. Como propiedad
$customerMap = new CustomerMap();
$customerMap->name = 'oscar';
echo($customerMap->name); => oscar
NOTAS:
- Si asignas un valor a una propiedad que no esta definida en los DocComments no tendrá efecto y la propiedad retornara null.
$customerMap->otherProperty = 'value'; var_dump($customerMap->otherProperty); => NULL
- Los valores por defecto establecidos en DocComments permaneceran hasta que no los remplazes ya sea por un array[] o de forma directa ->.
echo($customerMap->company); => PHP Company $customerMap->company = 'Cbot' echo($customerMap->company); => Cbot
###3.3. Mutators y Accessors
Siguiendo la sintaxis de los modelos en Laravel podemos declarar mutators y accessors en la clase que extiende Mapper. En ellos puedes dejar la lógica para depurar los datos que generalmente nos llegan por request y que se pierde en el controlador al no ser reutilizable.
use Oscarricardosan\Mapper\Mapper;
/**
* @property $name
* @property $company "PHP Company"
* @property $document_type "cc"
* @property $document_number
* @property $city
* @property $state
* @property $country
* @property $car
*/
class CustomerMap extends Mapper
{
public function getDocumentTypeAttribute($value)
{
return strtoupper($value);
}
public function setCityAttribute($value)
{
if($value == 'Moscú')
$this->attributes['country'] = 'Rusia';
}
}
//Accessor default value
echo($customerMap->document_type); => CC
//Accessor new value
$customerMap->document_type = 'ti';
echo($customerMap->document_type); => TI
//Mutator
$customerMap->city = 'Moscú';
echo($customerMap->country); => Rusia
###3.4. Alias
En ocaciones leemos datos desde un csv, excel u otros donde los datos de entrada vienen en vector el cual PHP covierte en una array con clave númerica. Para ello mutator permite establecer alias a las propiedades. Para usarlo solo debes usar la propiedad $alias de la clase que extiende mapper y !listo¡, con ellos los mutator y accessors funcionan comun y corriente, con lo cual no solo mapeas el vector y lo a asignas a su correspondiente propiedad sino que también lo puedes validar.
/**
* @property $name
* @property $car
* @property $document_type
*/
class CustomerMap extends Mapper
{
protected $alias = [
0 => 'name',
1 => 'car',
2 => 'document_type'
];
public function getDocumentTypeAttribute($value)
{
return strtoupper($value);
}
}
//Passing vector
$customerMap = new CustomerMap(['Oscar', 'Tesla S', 'ti']);
echo($customerMap->name); => Oscar
echo($customerMap->car); => Tesla S
echo($customerMap->document_type); => TI
##4. Ejemplo usando un Controlador y un Repositorio
#Laravel
/***
* REPOSITORY
***/
class CustomerRepository{
public function store(CustomerMap $customerMap)
{
$customer = new Customer();
$customer->fill($customerMap->getAttributes());
$customer->save();
}
public function update(CustomerMap $customerMap)
{
$customer = new Customer();
$customer->name = $customerMap->name;
$customer->name = $customerMap->company;
$customer->save();
}
}
/***
* CONTROLLER
***/
class CustomerController{
$repository;
public function __construct(){
$this->repository = new CustomerRepository();
}
public function store($request)
{
$customerMap = new CustomerMap($request->all());
$this->repository->store($customerMap);
}
public function update($request)
{
$customerMap = new CustomerMap($request->all());
$this->repository->update($customerMap);
}
}