Doctrine Custom Types

Another option is to handle the Value Object persistence using a Doctrine Custom Type. A Custom Type adds a new mapping type to Doctrine — one that describes a custom transformation between an Entity field and the database representation, in order to persist the former.

As the Doctrine DBAL 2 Documentation explains:

Just redefining how database types are mapped to all the existing Doctrine types is not at all that useful. You can define your own Doctrine Mapping Types by extending DoctrineDBALTypesType. You are required to implement 4 different methods to get this working.

With the object type, the serialization step includes information, such as the class, that makes it quite difficult to safely refactor our code.

Let's try to improve on this solution. Think about a custom serialization process that could solve the problem.

One such way could be to persist the Money Value Object as a string in the database encoded in amount|isoCode format:

use DddDomainModelCurrency;
use DddDomainModelMoney;
use DoctrineDBALTypesTextType;
use DoctrineDBALPlatformsAbstractPlatform;

class MoneyType extends TextType
{
const MONEY = 'money';

public function convertToPHPValue(
$value,
AbstractPlatform $platform
) {
$value = parent::convertToPHPValue($value, $platform);
$value = explode('|', $value);
return new Money(
$value[0],
new Currency($value[1])
);
}

public function convertToDatabaseValue(
$value,
AbstractPlatform $platform
) {
return implode(
'|',
[
$value->amount(),
$value->currency()->isoCode()
]
);
}

public function getName()
{
return self::MONEY;
}
}

Using Doctrine, you're required to register all Custom Types. It's common to use an EntityManagerFactory that centralizes this EntityManager creation.

Alternatively, you could perform this step by bootstrapping your application:

use DoctrineDBALTypesType;
use DoctrineORMEntityManager;
use DoctrineORMToolsSetup;

class EntityManagerFactory
{
public function build()
{
Type::addType(
'money',
'DddInfrastructurePersistenceDoctrineTypeMoneyType'
);

return EntityManager::create(
[
'driver' => 'pdo_mysql',
'user' => 'root',
'password' => '',
'dbname' => 'ddd',
],
Setup::createXMLMetadataConfiguration(
[__DIR__.'/config'],
true
)
);
}
}

Now we need to specify in the mapping that we want to use our Custom Type:

<?xml version = "1.0" encoding = "utf-8"?>
<doctrine-mapping>
<entity
name = "Product"
table = "product">

<!-- ... -->
<field
name = "price"
type = "money"
/>
</entity>
</doctrine-mapping>
Why Use XML Mapping? 
Thanks to the XSD schema validation in the headers of the XML mapping file, many Integrated Development Environment (IDEs) setups provide auto-complete functionality for all the elements and attributes present in the mapping definition. However, in other parts of the book, we use YAML to show a different syntax.

Let's check the database to see how the price was persisted using this approach:

mysql> select * from products G
*************************** 1. row***************************
id: 1
name: Domain-Driven Design in PHP
price: 999|USD
1 row in set (0.00 sec)

This approach is an improvement on the one before in terms of future refactoring. However, searching capabilities remain limited due to the format of the column. With the Doctrine Custom types, you can improve the situation a little, but it's still not the best option for building your DQL queries. See Doctrine Custom Mapping Types for more information.

Time to Discuss
Think about and discuss with a peer how would you create a Doctrine Custom Type using JMS to serialize and unserialize a Value Object.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.147.65.247