Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Using Value Objects as Custom Doctrine DBAL Type as Identifier in Symfony
# Doctrine Configuration
doctrine:
dbal:
driver: "%database_driver%"
host: "%database_host%"
server_version: 5.1
port: "%database_port%"
dbname: "%database_name%"
user: "%database_user%"
password: "%database_password%"
charset: UTF8
# if using pdo_sqlite as your database driver, add the path in parameters.yml
# e.g. database_path: "%kernel.root_dir%/data/data.db3"
# path: "%database_path%"
types:
guttercolorid: Sps\DormerCalculation\Infrastructure\Persistence\Doctrine\GutterColorIdType
<?php
namespace Sps\DormerCalculation\Infrastructure\Persistence\Doctrine;
use Doctrine\ORM\EntityRepository;
/**
* Class DoctrineGutterColorRepository
* @package Sps\DormerCalculation\Infrastructure\Persistence\Doctrine
*/
final class DoctrineGutterColorRepository
extends EntityRepository
implements GutterColorRepository
{}
<?xml version="1.0" encoding="UTF-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="Sps\DormerCalculation\Domain\Model\Gutter\GutterColor" table="gutter_color"
repository-class="Sps\DormerCalculation\Infrastructure\Persistence\Doctrine\DoctrineGutterColorRepository">
<id type="guttercolorid" name="id" />
<field name="name" column="name" length="50" />
</entity>
</doctrine-mapping>
<?php
namespace Sps\DormerCalculation\Domain\Model\Gutter;
use Sps\DormerCalculation\Domain\Model\Gutter\GutterColorId;
/**
* Class GutterColor
* @package Sps\DormerCalculation\Domain\Model\Gutter
*/
final class GutterColor
{
/** @var GutterColorId $id */
private $id;
/** @var string $name */
private $name;
}
<?php
namespace Sps\DormerCalculation\Infrastructure\Persistence\Doctrine;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\GuidType;
use Doctrine\DBAL\Types\Type;
use Sps\DormerCalculation\Domain\Model\Gutter\GutterColorId;
/**
* Class GutterColorIdType
* @package Sps\DormerCalculation\Infrastructure\Persistence\Doctrine
*/
#final class GutterColorIdType extends Type
final class GutterColorIdType extends GuidType
{
const GUTTER_COLOR_ID = 'guttercolorid';
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
{
return $platform->getGuidTypeDeclarationSQL($fieldDeclaration);
}
public function convertToPHPValue($value, AbstractPlatform $platform)
{
if (empty($value)) {
return null;
}
if ($value instanceof GutterColorId) {
return $value;
}
return GutterColorId::fromInteger($value);
}
public function convertToDatabaseValue($value, AbstractPlatform $platform)
{
if (empty($value)) {
return null;
}
return $value->toInteger();
}
public function getName()
{
return self::GUTTER_COLOR_ID;
}
/**
* {@inheritdoc}
*
* @param \Doctrine\DBAL\Platforms\AbstractPlatform $platform
* @return boolean
*/
public function requiresSQLCommentHint(AbstractPlatform $platform)
{
return true;
}
}
@webdevilopers

This comment has been minimized.

Copy link
Owner Author

@webdevilopers webdevilopers commented Mar 10, 2019

I tried several generator strategies for the custom type. Still I get the following error when passing a value object to the repository:

$this->gutterColorRepository->find(GutterColorId::fromInteger(1));

Catchable Fatal Error: Object of class Sps\DormerCalculation\Domain\Model\Gutter\GutterColorId could not be converted to string

Any ideas @carlosbuenosvinos, @tgalopin, @Ocramius maybe ?

@webdevilopers

This comment has been minimized.

Copy link
Owner Author

@webdevilopers webdevilopers commented Mar 10, 2019

Solved as discussed on twitter:

it’s possible to use Objects as identifiers for Entities as long as they implement the magic method __toString()

@yvoyer

This comment has been minimized.

Copy link

@yvoyer yvoyer commented Mar 10, 2019

why not just use a none strategy, set the Id to the string value of your VO. this would avoid the need to define a new type, and would still work in query, as long as you use the toInteger().

ie.

// entity
private $id; // int
public function __construct(GutterColorId $id) 
{
    $this->id = $id->toInteger();
}
public function getId(): GutterColorId
{
    return GutterColorId::fromInt($this->id);
}

or another option if you wish to keep the property as an object, us @Embedable thought I never tried it on a Identity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment