symfonydoctrine-ormsymfony-dependency-injection

How do I autoload Doctrine entities mappings in a Symfony compiler pass?


I'm trying to automatically load entity mappings based on a folder structure. My loader class returns a map like this array below. My goal is to find all "capabilities" and map their domain folder to the doctrine ORM entity mapping when the app is initialized.

[
  "UploadsDomain" => [
    "alias" => "SomeNameDomain",
    "dir" => "/home/someName/projects/video-service/src/Capability/SomeName/Domain",
    "is_bundle" => false,
    "prefix" => "App\Capability\SomeName\Domain",
    "type" => "attribute",
   ]
 ]

My compiler pass is this, and I'm calling it in my Kernel.php $container->addCompilerPass(new DoctrineMappingPass());.

namespace App\DependencyInjection\Compiler;

use App\Doctrine\CapabilityMappingLoader;
use Doctrine\ORM\Mapping\Driver\AttributeDriver;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;

class DoctrineMappingPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container): void
    {
        if (!$container->hasDefinition('doctrine.orm.default_configuration')) {
            return;
        }

        $definition = $container->getDefinition('doctrine.orm.default_configuration');

        // Instantiate the mapping loader
        $loader = new CapabilityMappingLoader();
        $mappings = $loader->loadMappings();

        foreach ($mappings as $alias => $mapping) {
            $definition->addMethodCall('addEntityNamespace', [$alias, $mapping['prefix']]);
            $definition->addMethodCall('setMetadataDriverImpl', [
                new AttributeDriver([$mapping['dir']]),
            ]);
        }
    }
}

However, for some reason I get this error message:

Symfony\Component\DependencyInjection\Exception\RuntimeException: Unable to dump a service container if a parameter is an object or a resource, got "Doctrine\ORM\Mapping\Driver\AttributeDriver".

Any idea how I can get this to work?


Solution

  • You are passing a concrete instance of AttributeDriver to addMethodCall.

    Try creating a service definition for each needed AttributeDriver instance.

    I think this should get you going, or at least moving in the right direction:

    (This incorporates a couple of fixes from floriank after they tested the code).

    class DoctrineMappingPass implements CompilerPassInterface
    {
    
        public function process(ContainerBuilder $container): void
        {
            if (!$container->hasDefinition('doctrine.orm.default_configuration')) {
                return;
            }
        
            $definition = $container->getDefinition('doctrine.orm.default_configuration');
        
            // Instantiate the mapping loader
            $loader   = new CapabilityMappingLoader();
            $mappings = $loader->loadMappings();
        
            foreach ($mappings as $mapping) {
                $paths = [$mapping['dir']];
                $attributeDefinition = new Definition(AttributeDriver::class, [$paths]);
        
                $array = [$mapping['prefix']];
                $definition->addMethodCall('setEntityNamespaces', [$array]);
                $definition->addMethodCall('setMetadataDriverImpl', [$attributeDefinition]);
            }
        }
    }