-
Notifications
You must be signed in to change notification settings - Fork 7
Concrete classes for mapped objects
It's possible to use your own classes instead of stdClass for any object managed by Maphper. This object will automatically have its properties set when it is created.
For example, if you had a product class:
class Product {
private $name;
private $price;
const TAX_RATE = 0.2;
public function getTax() {
return $this->price * self::TAX_RATE;
}
public function getTotalPrice() {
return $this->price + $this->getTax();
}
public function setName($name) {
$this->name = $name;
}
}
You can instruct Maphper to use this class using the resultClass
option in the $options
array when creating the Maphper instance:
$dataSource = new \Maphper\DataSource\Database($pdo, 'product', 'id');
$products = new \Maphper\Maphper($dataSource, ['resultClass' => 'Product']);
$product = $products[123];
echo get_class($product); //"Product" instance
//And as expected, the methods from Product are available:
$tax = $product->getTax();
$total = $product->getTotalPrice();
Private properties are both saved and loaded as any normal properties.
Similarly, you can create an instance of the Product
class and save it to the mapper.
$product = new Product;
$product->setName('A Product');
//Write the product to the mapper. Even though $product->name is private it will still be stored
$products[] = $product;
Sometimes your result class may have dependencies. In this case, you can specify a method rather than a class name to act as a factory. Consider the following:
class TaxCalculator {
const TAX_RATE = 0.2;
public function getTax($price) {
return $price * self::TAX_RATE;
}
}
class Product {
private $name;
private $price;
private $taxCalculator;
public function __construct(TaxCalculator $taxCalculator) {
$this->taxCalculator = $taxCalculator;
}
public function getTax() {
return $this->taxCalculator->getTax($this->price);
}
public function getTotalPrice() {
return $this->price + $this->getTax();
}
}
In this case using:
$dataSource = new \Maphper\Maphper($database, ['resultClass' => 'Product']);
Will error, because when an instance of Product
is constructed, Maphper isn't smart enough to guess that a TaxCalculator
instance is required as a constructor argument. Instead, you can pass a closure that returns a fully constructed object:
$taxCalculator = new TaxCalculator;
$dataSource = new \Maphper\Maphper($database, ['resultClass' => function() use ($taxCalculator) {
return new Product($taxCalculator);
}]);
Alternatively if you want considerably more control over the dependencies you can use a Dependency Injection Container such as Dice:
$dice = new \Dice\Dice;
$dataSource = new \Maphper\Maphper($database, ['resultClass' => function() use ($dice) {
return $dice->create('Product');
}]);