Skip to content

Doctrine 2.14 TypedFieldMapper #213

@michnovka

Description

@michnovka

With the introduction of Doctrine 2.14, we can now create our own TypedFieldMapper implementation.

This will allow us to replace

#[ORM\Entity]
class Card
{
    #[ORM\Column(Suit::class)]
    protected Suit $suit;
}

with

#[ORM\Entity]
class Card
{
    #[ORM\Column]
    protected Suit $suit;
}

I propose we create our own that will check if the enum is specified in types list

elao_enum:
  doctrine:
    types:
      App\Enum\Suit: ~ # Defaults to `{ class: App\Enum\Suit, default: null, type: single }`
      permissions: { class: App\Enum\Permission } # You can set a name different from the enum FQCN
      permissions_bag: { class: App\Enum\Permissions, type: flagbag } # values are stored as an int and retrieved as FlagBag object
      App\Enum\RequestStatus: { default: 200 } # Default value from enum cases, in case the db value is NULL
    prepend_typed_field_mapper: true #default false

If elao_enum.doctrine.types.prepend_typed_field_mapper is set to true (maybe we can make this a default?) then I would inject our typed field mapper into doctrine config. The way to do this would be:

/** @var Doctrine\ORM\Configuration $configuration */
$currentTypedFieldMapper = $configuration->getTypedFieldMapper();
$newTypedFieldMapper = new Doctrine\ORM\Mapping\ChainTypedFieldMapper(
    new ElaoTypedFieldMapper(),
    $currentTypedFieldMapper
);
$configuration->setTypedFieldMapper($newTypedFieldMapper);

This will ensure that the already used typed field mapper is kept, and ElaoTypedFieldMapper will only take care of the elao enum types.

The actual typed field mapper is simple, can look sth like this:

<?php
final class ElaoTypedFieldMapper implements TypedFieldMapper
{
    /**
     * {@inheritdoc}
     */
    public function validateAndComplete(array $mapping, ReflectionProperty $field): array
    {
        $type = $field->getType();

        if (
            ! isset($mapping['type'])
            && ($type instanceof ReflectionNamedType)
        ) {
            $implementsReadableEnumInterface = // find out using reflection or is_subclass_of
            if (! $type->isBuiltin() && enum_exists($type->getName()) && $implementsReadableEnumInterface) {
                $mapping['type'] = 'the correctly derived enum DBAL type class name';
            }
        }

        return $mapping;
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions