È possibile definire un proprio tipo di campo se si dice alla doctrina come gestirlo. Per spiegare questo ho inventato un "negozio" e un "ordine" dove un "denaro" - ValueObject viene usato.
Per iniziare abbiamo bisogno di un entità e un ValueObject, che viene utilizzato nel soggetto:
order.php:
<?php
namespace Shop\Entity;
/**
* @Entity
*/
class Order
{
/**
* @Column(type="money")
*
* @var \Shop\ValueObject\Money
*/
private $money;
/**
* ... other variables get defined here
*/
/**
* @param \Shop\ValueObject\Money $money
*/
public function setMoney(\Shop\ValueObject\Money $money)
{
$this->money = $money;
}
/**
* @return \Shop\ValueObject\Money
*/
public function getMoney()
{
return $this->money;
}
/**
* ... other getters and setters are coming here ...
*/
}
Money.php:
<?php
namespace Shop\ValueObject;
class Money
{
/**
* @param float $value
* @param string $currency
*/
public function __construct($value, $currency)
{
$this->value = $value;
$this->currency = $currency;
}
/**
* @return float
*/
public function getValue()
{
return $this->value;
}
/**
* @return string
*/
public function getCurrency()
{
return $this->currency;
}
}
Finora niente di speciale. La "magia" viene qui:
MoneyType.php:
<?php
namespace Shop\Types;
use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Shop\ValueObject\Money;
class MoneyType extends Type
{
const MONEY = 'money';
public function getName()
{
return self::MONEY;
}
public function getSqlDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
{
return 'MONEY';
}
public function convertToPHPValue($value, AbstractPlatform $platform)
{
list($value, $currency) = sscanf($value, 'MONEY(%f %d)');
return new Money($value, $currency);
}
public function convertToDatabaseValue($value, AbstractPlatform $platform)
{
if ($value instanceof Money) {
$value = sprintf('MONEY(%F %D)', $value->getValue(), $value->getCurrency());
}
return $value;
}
public function canRequireSQLConversion()
{
return true;
}
public function convertToPHPValueSQL($sqlExpr, AbstractPlatform $platform)
{
return sprintf('AsText(%s)', $sqlExpr);
}
public function convertToDatabaseValueSQL($sqlExpr, AbstractPlatform $platform)
{
return sprintf('PointFromText(%s)', $sqlExpr);
}
}
quindi è possibile utilizzare il seguente codice:
// preparing everything for example getting the EntityManager...
// Store a Location object
use Shop\Entity\Order;
use Shop\ValueObject\Money;
$order = new Order();
// set whatever needed
$order->setMoney(new Money(99.95, 'EUR'));
// other setters get called here.
$em->persist($order);
$em->flush();
$em->clear();
Si potrebbe scrivere un mapper che mappa l'input proveniente dal campo monetario di Symfony in un Money-ValueObject per semplificare ulteriormente.
un altro paio di dettagli sono spiegati qui: http://doctrine-orm.readthedocs.org/en/latest/cookbook/advanced-field-value-conversion-using-custom-mapping-types.html
testato, ma ho usato questo concetto prima e ha funzionato. Fammi sapere se hai domande.
Avete bisogno di memorizzare numeri interi o numeri floating? Penso che avrai un numero limitatore di tipi di campo. –
@ A.L Non importa molto. Posso sempre usare l'opzione [divisor] (http://symfony.com/doc/2.5/reference/forms/types/money.html#divisor) per convertire i valori in float. Per ora sto usando 'int' (importo) +' stringa' (valuta) ma è così imbarazzante. – SiliconMind
Cosa fai con il segno '+'? Hai un campo per l'importo e un campo per la valuta? Se devi lavorare con valute diverse, ti suggerisco di aggiungere una nota nella tua domanda perché lo rende un po 'più complesso rispetto a una sola valuta. –