Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Symfony bridge: Use PHP Attributes for Doctrine configuration #236

Open
michnovka opened this issue Oct 16, 2024 · 1 comment
Open

Symfony bridge: Use PHP Attributes for Doctrine configuration #236

michnovka opened this issue Oct 16, 2024 · 1 comment

Comments

@michnovka
Copy link
Contributor

I have a proposal: right now we require to list manually all types that we want to integrate with doctrine inside elao_enum.yaml file.

Let's introduce a new attribute Elao\Attribute\DBALType.

#[DBALType]
enum Status: string implements ReadableEnumInterface
{
    use ReadableEnumTrait;

    case DRAFT = 'draft';
    case PUBLISHED = 'published';
    case ARCHIVED = 'archived';
}

We can take advantage of autoconfiguration:

namespace Elao\Attribute;

use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag;

#[\Attribute(\Attribute::TARGET_CLASS)]
class DBALType extends AutoconfigureTag
{
    public function __construct(
        public ?string $name = null, // if null, use enum FQCN as name
        public string $type = 'single',
        public \BackedEnum|int|string|null $defaultOnNull = null,
    )
    {
        parent::__construct('elao.dbal_type');
    }
}

then its easy to find inside CompilerPass

     public function process(ContainerBuilder $container)
    {
        // Find all services tagged with 'your_bundle.dbal_type'
        $taggedServices = $container->findTaggedServiceIds('elao.dbal_type');

        $enums = [];

        foreach ($taggedServices as $id => $tags) {
            $definition = $container->getDefinition($id);
            $class = $definition->getClass();

            if (class_exists($class)) {
                $reflection = new \ReflectionClass($class);

                if ($reflection->isEnum()) {
                    $enums[] = $class;
                }
            }
        }

        // Process $enums as needed
        $this->registerDBALTypes($enums);
    }

I just think this is more flexible approach than always remembering to add a config type to yaml config.

And, as an added benefit, because of the reflection used in PHP code, this allows us to use TypedFieldMapper to map all such enums to their types. So we can then use

    #[ORM\Column]
    private Status $status;

instead of

    #[ORM\Column(type: Status::class)]
    private Status $status;

WDYT?

We have to agree what to do with the yaml config, especially if we have conflicts. Will one take precedence? Will we throw?

@ogizanagi
Copy link
Member

Sounds interesting indeed. TIL about the type field mappers, thanks 👌🏻

We have to agree what to do with the yaml config, especially if we have conflicts. Will one take precedence? Will we throw?

Usually, YAML config wins over PHP attributes. It is meant to allow overriding the config per Symfony env easily. Despite I don't see much use-case for it, I guess we should stick to the convention here.

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

No branches or pull requests

2 participants