Add custom type for doctrine

Reading Time: 2 minutes
Learn how to create custom types using value objects and setup configuration for doctrine in PHP-based applications.
custom types for doctrine

Table of Contents

Create the value object that you want to use as your custom type.

In my case the file module/Geo/src/Domain/Address/Id.php

				
					namespace SwarmTech\Geo\Domain\Address;

use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;

final class Id
{
    private UuidInterface $value;

    public function __construct(UuidInterface $value)
    {
        $this->value = $value;
    }

    public function value(): UuidInterface
    {
        return $this->value;
    }

    public static function random(): self
    {
        $uuid = Uuid::uuid4();

        return new self($uuid);
    }

    public static function fromString(string $value): self
    {
        $uuid = Uuid::fromString($value);

        return new self($uuid);
    }

    public function equals(self $other): bool
    {
        return $this->value->equals($other->value());
    }

    public function __toString(): string
    {
        return $this->value->__toString();
    }
}

				
			

Create the doctrine type class. 

In my case in module/Geo/src/Doctrine/Type/

				
					namespace SwarmTech\Geo\Infrastructure\Doctrine\Type;

use SwarmTech\Geo\Domain\Address\Id as AddressId;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\ConversionException;
use Doctrine\DBAL\Types\Type;
use InvalidArgumentException;

class AddressIdType extends Type
{
    public const NAME = 'address_id';

    public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform): string
    {
        return $platform->getGuidTypeDeclarationSQL($fieldDeclaration);
    }

    public function convertToPHPValue($value, AbstractPlatform $platform):?AddressId
    {
        if ($value === null || $value === '') {
            return null;
        }

        if ($value instanceof AddressId) {
            return $value;
        }

        try {
            $addressId = AddressId::fromString($value);
        } catch (InvalidArgumentException $e) {
            throw ConversionException::conversionFailed($value, self::NAME);
        }

        return $addressId;
    }

    public function convertToDatabaseValue($object, AbstractPlatform $platform): ?string
    {
        if (null === $object || '' === $object) {
            return null;
        }

        if ($object instanceof AddressId) {
            return $object->__toString();
        }

        throw ConversionException::conversionFailed($object, self::NAME);
    }

    public function getName(): string
    {
        return self::NAME;
    }

    public function requiresSQLCommentHint(AbstractPlatform $platform): bool
    {
        return true;
    }
}

				
			

Setup the configuration for doctrine in the ConfigProvider class of your module.

In my case module/Geo/src/ConfigProvider.php

				
					namespace SwarmTech\Geo;

use Swarmtech\Geo\Infrastructure\Doctrine\Type\AddressIdType;

class ConfigProvider
{
    public function __invoke(): array
    {
        return [
           'doctrine'
               'configuration' => [
                    'orm_default' => [
                        'types' => [
                            AddressIdType::NAME => AddressIdType::class,
                        ]
                    ]
                ]
            ]
        ];
    }
}

				
			

Use your type in a doctrine entity.

In my case in the file module/Geo/src/Domain/Address.php

				
					namespace SwarmTech\Geo\Domain;

use SwarmTech\Geo\Domain\Address\Id as AddressId;
use DateTimeImmutable;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Table(name="geo_address")
 * @ORM\Entity
 */
class Address
{
    /**
     * @ORM\Id
     * @ORM\Column(name="address_id", type="address_id")
     */
    private AddressId $id;
    
    public function __construct(AddressId $id) 
    {
        $this->id = $id;
    }
}

				
			

Share it on:

Twitter
LinkedIn
Facebook
WhatsApp

About the Author

Gary Gitton
Hello, I'm Gary Gitton - an accomplished Software Engineer, Tech Lead, specializing in PHP, API Engineering, DevOps, and Cloud Management. Throughout my career, I've had the privilege to enhance multiple software solutions with my expertise in multiple languages and platforms. I bring my unique blend of technical and business acumen to every project, ensuring efficient, scalable, and innovative outcomes. I'm also passionate about fostering a culture of continuous learning, mentoring developers, and leading projects with agile methodologies. Whether concocting a bespoke API or orchestrating cloud environments, I'm committed to delivering quality and excellence. Let's connect and transform your vision into a digital reality.

You might also like