Doctrine standalone without cli-config.php

2019-03-22 05:15发布

I want to integrate Doctrine ORM into my (non-Symfony) project. I already done this in another project and used the famous cli-config.php into the project root directory.

But now, in my new project, I use the Symfony Console component and the Dependency Injection component (to reference services and commands, by tagging them).

1. I absolutely don't want to have a cli-config.php in the project root. How the Sf Doctrine Bundle do this?

2. Also (but it is less important), I would like to have the Doctrine commands into my project CLI. What would be the best way to do this? Create references to Doctrine commands into my services.yml ? Or create local "decorator commands" that call Doctrine commands via PHP?

1条回答
时光不老,我们不散
2楼-- · 2019-03-22 05:38

Finally, after some googling and experiments, I found a complete solution.

Just read the doctrine.php in vendor/bin. It is very easy to avoid the hardcoded config-cli.php file.

1. Create an entity manager

In my case, I use a factory and this method hydrates the doctrine.em service.

($config is specific to my app, change values to use your own logic.)

use Doctrine\ORM\Tools\Setup;
use Doctrine\ORM\EntityManager;

public function createEntityManager()
{
    $config = $this->get('config');

    $metadataConfig = Setup::createAnnotationMetadataConfiguration(
        [$config->meta('app_path') . '/Entity'],
        $config->oc->doctrine->dev_mode
    );

    return EntityManager::create((array) $config->oc->doctrine->connection, $metadataConfig);
}

2. Merge Doctrine CLI commands in your CLI commands

Somewere in your code, like in some bootstrap.php, you probably declare your Symfony\Component\Console\Application command line interface, that's how I do this (the foreach simply adds commands defined in my services.yml file):

$application = new Application('MyApp CLI', '0.0.1');

$services = $container->findTaggedServiceIds('oc.command');

foreach(array_keys($services) as $serviceId)
{
    $application->add($container->get($serviceId));
}

$application->run();

Now, we simply ask Doctrine to inject its commands into our Application:

$application = new Application('MyApp CLI', '0.0.1');

$helperSet = ConsoleRunner::createHelperSet($container->get('doctrine.em'));
$application->setHelperSet($helperSet);

ConsoleRunner::addCommands($application);

$services = $container->findTaggedServiceIds('oc.command');

foreach(array_keys($services) as $serviceId)
{
    $application->add($container->get($serviceId));
}

$application->run();

That's it! You can also only add a subset of the Doctrine commands by using arsfeld's answer on this GitHub issue.

3. Bonus: only import needed commands and rename them

You can create decorator commands that inherit Doctrine commands (this is useful to redefine the name of Doctrine commands, as Symfony Doctrine Bundle does, eg. orm:validate-schema -> doctrine:schema:validate).

To do this, remove the line ConsoleRunner::addCommands($application); we added in step 2. For each command you want to redefine, you will need to create an register a new command in your app. This command will "extends" the target Doctrine command and will override the configure() method.

Here is an example with orm:validate-schema:

<?php

namespace MyApp\Command\Doctrine;

use Doctrine\ORM\Tools\Console\Command\ValidateSchemaCommand;

class SchemaValidateCommand extends ValidateSchemaCommand
{
    protected function configure()
    {
        parent::configure();
        $this->setName('doctrine:schema:validate');
    }
}

Some Doctrine commands have aliases that will pollute your command namespaces, like orm:generate-entities and orm:generate:entities. To remove these aliases, in configure(), add ->setAliases(array()).

$this->setName('doctrine:generate:entities')->setAliases([]);

Congratulations, you just redone the Symfony Doctrine Bundle :p (jk)

查看更多
登录 后发表回答