cwo
cwo

Reputation: 93

Doctrine store object value that is not an entity

how can I solve this problem. An entity class aggregates an object. Its value should be stored in the database. I have the following entity:

<?php

class Price
{
    private $_amount;

    public function getAmount()
    {
        return $this->_amount;
    }

    public function setAmount($amount)
    {
        $this->_amount = $amount;
        return $this;
    }
}

/**
 * Class Product
 *
 * @Entity
 * @Table(name="product", options={"engine" = "NDBCLUSTER"})
 */
class Product
{
    /**
     * @Id
     * @GeneratedValue
     * @Column(name="id", type="integer")
     * @var int
     */
    private $_id;

    /**
     * @Column(name="price", type="decimal", precision=10, scale=2)
     * @var Price
     */
    private $_price;
}

?>

If I want to store a price in the database, how can I do that? This is obviously not working:

<?php

$price = new Price();
$price->setAmount(19.99);

$product = new Product();
$product->setPrice($price);

$em->persist($product);
$em->flush();

?>

Do I have to implement a new mapping type?

Upvotes: 2

Views: 1645

Answers (3)

Alireza Rahmani Khalili
Alireza Rahmani Khalili

Reputation: 2954

you should create custom type in doctrine, like:

declare(strict_types = 1);

namespace App\Infrastructure\Persistence\Doctrine\Type;

use App\Domain\Model\OrderStatus;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\ConversionException;
use Doctrine\DBAL\Types\TextType;

final class StatusDoctrineType extends TextType
{
    /**
     * @return string
     */
    public function getName()
    {
        return 'status_doctrine_type';
    }

    /**
     * @param                  $value
     * @param AbstractPlatform $platform
     *
     * @return OrderStatus
     * @throws ConversionException
     */
    public function convertToPhpValue($value, AbstractPlatform $platform): OrderStatus
    {
        if (null === $value) {
            throw ConversionException::conversionFailed($value, $this->getName());
        }

        return new OrderStatus($value);
    }

    /**
     * @param mixed            $value
     * @param AbstractPlatform $platform
     *
     * @return null|string
     * @throws ConversionException
     */
    public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string
    {
        if (null === $value) {
            throw ConversionException::conversionFailed($value, $this->getName());
        }
        /** @var OrderStatus $value */
        if (!is_a($value, OrderStatus::class)) {
            throw ConversionException::conversionFailed($value, $this->getName());
        }

        return $value->currentStatus();
    }
} 

and in your entity something like this :

// ...
/**
 * Order constructor.
 *
 * @param Route    $route
 * @param OrderId  $orderId
 * @param Distance $distance
 */
public function __construct(Route $route, OrderId $orderId, Distance $distance)
{
    $this->route = $route;
    $this->id = $orderId;
    $this->distance = $distance->spacing();

    // according to grasp Information Expert pattern.
    $this->status = new OrderStatus(OrderStatus::UNASSIGN);
}
//...
   /**
 * @return OrderStatus
 */
public function status(): OrderStatus
{
    return $this->status;
}

Upvotes: 0

magnetik
magnetik

Reputation: 4431

You can use doctrine Embeddables.

Declare your price as an embeddable like this:

/**
 * @Embeddable 
 */
class Price
{
    /** @Column(type = "decimal") */
    private $_amount;

    ...

and then use it:

class Product
{
    /** @ORM\Embedded(class="Price") */
    private $price;

    ...

Upvotes: 2

Marek
Marek

Reputation: 7433

You can define Custom Mapping Types

Upvotes: -1

Related Questions