Simple abstraction for object transformations.
$ composer require tonicforhealth/model-transformer
Possible use cases:
- Separate domain model layer from view or presentation layer, but still keep objects.
- Separate domain model from resource representations (in RESTful applications).
Suppose, there are two domain objects:
<?php
class Product
{
/**
* @var string
*/
private $name;
/**
* @var Category
*/
private $category;
// ...
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @return Category
*/
public function getCategory()
{
return $this->category;
}
}
class Category
{
/**
* @var string
*/
private $name;
// ...
/**
* @return string
*/
public function getName()
{
return $this->name;
}
}
And one presentation object which can be used in presentation layer:
<?php
class ProductPresentation
{
/**
* @var string
*/
private $name;
/**
* @var string
*/
private $categoryName;
/**
* @var int
*/
private $purchasedCount;
// ...
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @return string
*/
public function getCategoryName()
{
return $this->categoryName;
}
/**
* @return string
*/
public function getPurchasedCount()
{
return $this->purchased;
}
}
There are lot of solutions for transforming Product
and Category
objects to ProductRepresentation
:
- just create
ProductRepresentation
basedProduct
andCategory
on at the needed place; - create factory for
ProductRepresentation
; - and so on.
This library provides simple and concise solution for this problem:
- Create transformer for objects.
- Register it in transformer manager or use it separately.
Possible transformer for ProductRepresentation
:
<?php
class ProductToProductRepresentationModelTransformer implements ModelTransformerInterface
{
/**
* @var ProductRepository
*/
private $productRepository;
// ...
/**
* {@inheritdoc}
*/
public function supports($object, $targetClass)
{
return ($object instanceof Product) && is_a($targetClass, ProductRepresentation::class, true);
}
/**
* {@inheritdoc}
*/
public function transform($object, $targetClass)
{
/** @var Product $product */
$product = $object;
$purchasedCount = $this->productRepository->computePurchasedCount($product);
return new ProductRepresentation(
$product->getName(),
$product->getCategory()->getName(),
$purchasedCount
);
}
}
Register it:
<?php
$priority = 0;
$modelTransformer->addTransformer($productToProductRepresentationModelTransformer, $priority = 0);
With an optional priority integer (higher equals more important and therefore that the transformer will be triggered earlier) that determines when a transformer is triggered versus other transformers (defaults to 0).
Use it anywhere:
<?php
$productRepresentation = $modelTransformer->transform($product, ProductRepresentation::class);
If you have simple rules of transformation, you can use ObjectTransformerInterface instead. As bonus transformation will work much faster.
All actual documentation is runnable library specifications at /spec
directory.
And to ensure library is not broken, run (under library directory):
bin/phpspec run