简体   繁体   English

如何使用zf3和symfony控制台实现控制台命令

[英]How can I implement a console command with zf3 and symfony console

The zend console is deprecated. zend控制台已弃用。 I will use symfony/console (as suggested): composer require symfony/console 我将使用symfony / console(如建议的那样): composer require symfony/console

With the ZF 2 & 3 I have some years of experience. 使用ZF 2和3,我拥有多年的经验。 With Symfony I have done different things, even several console commands. 使用Symfony,我可以做不同的事情,甚至可以执行几个控制台命令。

My skeleton for a symfony console command: 我的symfony控制台命令框架:

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class InstallCommand extends Command
{
    /**
     * @var string The name of the command (the part after "bin/console")
     */
    protected static $defaultName = 'app:modulename-install';

    protected function configure()
    {
        $this->addArgument('test', InputArgument::REQUIRED, 'Only a test.');
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $text = 'your argument: ' . $input->getArgument('test');
        $output->writeln($text);
    }
}

1. problem : symfony console has none *Action() 's in classes *Command . 1.问题 :symfony控制台在*Command类中没有*Action() How can i configure a route? 如何配置路线?

2 problem : there is no /vendor/bin/console file. 2问题 :没有/vendor/bin/console文件。

How can I implement symfony 4.x console command in Zend Framework 3? 如何在Zend Framework 3中实现symfony 4.x控制台命令?

...the internet is silent on this topic ...互联网对此话题保持沉默

According to Symfony documentation each console command is a separate class inherited from Symfony\\Component\\Console\\Command\\Command and you need to implement your command runtime code inside execute() method. 根据Symfony文档,每个控制台命令都是从Symfony\\Component\\Console\\Command\\Command继承的单独类,您需要在execute()方法内实现命令运行时代码。 Because of this there is no routing is involved. 因此,不涉及路由。 Actually you can think about your console command class itself as an action because Symfony's console Application includes routing . 实际上,您可以将控制台命令类本身视为一个动作,因为Symfony的控制台应用程序包含routing

Question about bin/console file is a bit tricky. 有关bin/console文件的问题有些棘手。 Normally when you're working with Symfony 4 itsef you're usually using Symfony Flex . 通常,当您使用Symfony 4 itef时,通常会使用Symfony Flex Flex itself connects Composer packages with so called "recipes" that resides into separate service . Flex本身将Composer软件包与驻留在单独服务中的所谓“配方”相连。 Flex uses these recipes to allow automatic configuration of packages that are installed for Symfony application through Composer. Flex使用这些配方来允许自动配置通过Composer为Symfony应用程序安装的软件包。 Because of this fact bin/console command is not a part of Composer package, but instead part of Flex recipe for symfony/console package. 因此, bin/console命令不是Composer软件包的一部分,而是symfony/console软件包的Flex配方的一部分。 You can fine it out by yourself inside official recipes repository. 您可以在官方食谱存储库中自行调整。

I have almost zero knowledge about ZF3, but in a case if you're using console as a standalone component you may decide either to deal with Symfony's DI container and store all services (including commands) inside it or to manually register every command in console application by using Application::add() method. 我对ZF3的知识几乎为零,但是如果您将控制台用作独立组件,则可能会决定处理Symfony的DI容器并在其中存储所有服务(包括命令),或者在控制台中手动注册每个命令通过使用Application :: add()方法来应用程序

It's been a realllllyyy long time since I created/updated this, so not too sure how this all fit together anymore. 自从我创建/更新此代码以来,已经很长时间了,所以不太确定如何将它们组合在一起。

But! 但! I can give you an example. 我可以举一个例子。


This is this no longer maintained module on Github which I found quite handy in the days of ZF2, and I've sort of upgraded it in a few projects of mine where I wanted it, but never into a fully blown ZF3 module. 这是在Github上不再维护的模块 ,我在ZF2时代发现它非常方便,并且我已经在我想要的几个项目中对其进行了升级,但从未升级为完全成熟的ZF3模块。 But it works :) 但这有效:)

Purpose: run fixtures (yea I know, php bin/console doc:fix:load -n in SF4 :p) 目的:运行固定装置(是的,我知道, php bin/console doc:fix:load -n在SF4中:p)

If I remember right, you could use this with: ./vendor/bin/doctrine-module data-fixture:import from the project root and have your Fixture classes registered like so: 如果我没记错的话,可以将其与以下./vendor/bin/doctrine-module data-fixture:import一起使用: ./vendor/bin/doctrine-module data-fixture:import从项目根目录开始,并像下面这样注册Fixture类:

...,
'doctrine' => [
    ...,
    'fixture' => [
        FQCN::class,
        FQCN2::class,
    ],
],

So, here it goes (if you copy this, mind the namespaces for folder structure, based on ZF3 with all in src/ folder): 因此,就可以了(如果您复制此内容,请注意基于ZF3的文件夹结构的命名空间,所有内容都在src/文件夹中):

A Module.php class: 一个Module.php类:

<?php

namespace DoctrineFixture;

use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Tools\Console\ConsoleRunner;
use DoctrineFixture\Command\ImportCommand;
use DoctrineFixture\Service\FixtureFactory;
use Interop\Container\ContainerInterface;
use Zend\EventManager\EventInterface;
use Zend\ModuleManager\Feature\ServiceProviderInterface;
use Zend\ModuleManager\ModuleManager;

class Module implements ServiceProviderInterface
{    
    public function init(ModuleManager $e)
    {
        $events = $e->getEventManager()->getSharedManager();

        // Attach to helper set event and load the entity manager helper.
        $events->attach(
            'doctrine',
            'loadCli.post',
            function (EventInterface $e) {
                /* @var $cli \Symfony\Component\Console\Application */
                $cli = $e->getTarget();

                /* @var $sm ContainerInterface */
                $sm    = $e->getParam('ServiceManager');
                $em    = $sm->get(EntityManager::class);
                $paths = $sm->get('doctrine.configuration.fixtures');

                $importCommand = new ImportCommand();
                $importCommand->setObjectManager($em);
                $importCommand->setPaths($paths);
                ConsoleRunner::addCommands($cli);
                $cli->addCommands(
                    [
                        $importCommand,
                    ]
                );
            }
        );
    }

    public function getServiceConfig()
    {
        return [
            'factories' => [
                'doctrine.configuration.fixtures' => new FixtureFactory(),
            ],
        ];
    }

    public function getConfig()
    {
        $config = [];

        foreach (glob(__DIR__ . '/config/*.php') as $filename) {
            $config = array_merge_recursive($config, include $filename);
        }

        return $config;
    }

    public function getAutoloaderConfig()
    {
        return [
            'Zend\Loader\StandardAutoloader' => [
                'namespaces' => [
                    __NAMESPACE__ => __DIR__ . DIRECTORY_SEPARATOR . 'src',
                ],
            ],
        ];
    }
}

Class ImportCommand ImportCommand

<?php

namespace DoctrineFixture\Command;

use Doctrine\Common\DataFixtures\Executor\ORMExecutor;
use Doctrine\Common\DataFixtures\Loader;
use Doctrine\Common\DataFixtures\Purger\ORMPurger;
use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * Command for generate migration classes by comparing your current database schema
 * to your mapping information.
 */
class ImportCommand extends Command
{
    const PURGE_MODE_TRUNCATE = 0; // 1 = DELETE FROM, 2 = TRUNCATE

    /** @var array */
    protected $paths;

    /** @var ObjectManager|EntityManager */
    protected $objectManager;

    /**
     * @return int|null|void
     */
    public function execute(InputInterface $input, OutputInterface $output)
    {
        $loader = new Loader();
        $purger = new ORMPurger();

        if ($input->getOption('purge-with-truncate')) {
            $purger->setPurgeMode(self::PURGE_MODE_TRUNCATE);
        }

        $executor = new ORMExecutor($this->getObjectManager(), $purger);

        foreach ($this->getPaths() as $key => $value) {
            $loader->loadFromDirectory($value);
        }

        $executor->execute($loader->getFixtures(), $input->getOption('append'));
    }

    public function getPaths(): array
    {
        return $this->paths;
    }

    public function setPaths(array $paths): ImportCommand
    {
        $this->paths = $paths;

        return $this;
    }

    /**
     * @return ObjectManager|EntityManager
     */
    public function getObjectManager()
    {
        return $this->objectManager;
    }

    /**
     * @param ObjectManager|EntityManager $objectManager
     */
    public function setObjectManager($objectManager): ImportCommand
    {
        $this->objectManager = $objectManager;

        return $this;
    }

    /**
     * Register command
     */
    protected function configure(): void
    {
        parent::configure();

        $this->setName('data-fixture:import')
             ->setDescription('Import Data Fixtures')
             ->setHelp(
                 <<<EOT
The import command Imports data-fixtures
EOT
             )
             ->addOption('append', null, InputOption::VALUE_NONE, 'Append data to existing data.')
             ->addOption('purge-with-truncate', null, InputOption::VALUE_NONE, 'Truncate tables before inserting data');
    }

}

And a class FixtureFactory to tie it all together: 还有一个FixtureFactory类,将它们结合在一起:

<?php

namespace DoctrineFixture\Service;

use Interop\Container\ContainerInterface;
use Zend\ServiceManager\Factory\FactoryInterface;

class FixtureFactory implements FactoryInterface
{
    /**
     * @return array|object
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
    {
        $options = $container->get('config');
        if (! isset($options['doctrine']['fixture'])) {

            return [];
        }

        return $options['doctrine']['fixture'];
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM