How to execute Zend Framework 3 action with zf-console?

徘徊边缘 提交于 2019-12-05 16:11:52

The zend-mvc-console module does seem to be on the edge of deprecation. Just like you I was trying to implement zfcampus/zf-console. Since the mvc-console module seems to be (almost) deprecated, I suggest you use something different than (mvc) controllers for your console work. I used a class that can handle the call (in a way zf-console expects).

This is a dummy example I was working on for my project;

This is script that is called on the command line:

use Zend\Console\Console;
use Zend\ServiceManager\ServiceManager;
use Zend\Stdlib\ArrayUtils;
use Zend\Stdlib\Glob;
use ZF\Console\Application;
use ZF\Console\Dispatcher;

require_once __DIR__ . '/vendor/autoload.php'; // Composer autoloader

$configuration = [];
foreach (Glob::glob('config/{{*}}{{,*.local}}.php', Glob::GLOB_BRACE) as $file) {
    $configuration = ArrayUtils::merge($configuration, include $file);
}

// Prepare the service manager
$smConfig = isset($config['service_manager']) ? $configuration['service_manager'] : [];
$smConfig = new \Zend\Mvc\Service\ServiceManagerConfig($smConfig);

$serviceManager = new ServiceManager();
$smConfig->configureServiceManager($serviceManager);
$serviceManager->setService('ApplicationConfig', $configuration);

// Load modules
$serviceManager->get('ModuleManager')->loadModules();

$routes = [
    [
        'name' => 'dumb',
        'route' => '[--foo=]',
        'description' => 'Some really cool feature',
        'short_description' => 'Cool feature',
        'options_descriptions' => [
            'foo'   => 'Lorem Ipsum',
        ],
        'defaults' => [
            'foo'   => 'bar',
        ],
        'handler' => function($route, $console) use ($serviceManager) {
            $handler = new \Application\Command\DumbCommand();
            return $handler($route, $console);
        }
    ],
];

$config = $serviceManager->get('config');
$application = new Application(
    $config['app'],
    $config['version'],
    $routes,
    Console::getInstance(),
    new Dispatcher()
);

$exit = $application->run();
exit($exit);

The handler function can use the service manager to inject any dependencies to the command handler:

'handler' => function($route, $console) use ($serviceManager) {
    /** @var \Doctrine\ORM\EntityManager $entityManager */
    $entityManager = $serviceManager->get(\Doctrine\ORM\EntityManager::class);
    /** @var mixed $repository */
    $contactRepository = $entityManager->getRepository(\Application\Entity\Contact::class);
    $handler = new \Application\Command\DumbCommand($contactRepository);
    return $handler($route, $console);
}

The command class is placed in a Command folder, it looks like:

<?php

namespace Application\Command;

use Application\Entity\Contact;
use Application\Repository\ContactRepository;
use Zend\Console\Adapter\AdapterInterface;
use ZF\Console\Route;

class DumbCommand
{
    /** @var ContactRepository */
    private $contactRepository;

    public function __construct($contactRepository)
    {
        $this->contactRepository = $contactRepository;
    }

    /**
     * @param Route $route
     * @param AdapterInterface $console
     * @throws \Doctrine\ORM\ORMException
     */
    public function __invoke(Route $route, AdapterInterface $console)
    {
        $console->writeLine('Bob was here');
        foreach ($this->contactRepository->findAll() as $item) {
            /** @var Contact $item */
            $console->writeLine($item->getFirstName() . ' was here');
        }
    }
}

(

This is my solution:

  1. I addedd console command routes to my module.config.php files
'console' => array(
    'commands' => array(
        array(
            'name' => 'sendemail',
            'handler' => PostCommand::class,
        ),
        array(
            'name' => 'sendsms',
            'handler' => SmsTransferCommand::class,
        )
    )
),
  1. I created a console.php in /public (this will be run with arguments to start a CLI app)
use Zend\Console\Console;
use Zend\ServiceManager\ServiceManager;
use ZF\Console\Application;
use ZF\Console\Dispatcher;

chdir(dirname(__DIR__));

require_once 'vendor/autoload.php'; // Composer autoloader

// Prepare application and service manager
$appConfig = require 'config/application.config.php';
$application = Zend\Mvc\Application::init($appConfig);
$serviceManager = $application->getServiceManager();

// Load modules
$serviceManager->get('ModuleManager')->loadModules();
$config = $serviceManager->get('config');
$routes = $config['console']['commands']; // This depends on your structure, this is what I created (see. 1.)

$application = new Application(
    $config['app'],
    $config['version'],
    $routes,
    Console::getInstance(),
    new Dispatcher($serviceManager)  // Use service manager as a dependency injection container
);

$exit = $application->run();
exit($exit);
  1. I separated my CLI command handlers into the src/Command folder. My CLI command handlers are services I have defined, created by factories. (This is why I use the service manager as the container - see. 2.)

[serviceEmail here is a local class variable, which is loaded by the factory of this command handler.]

/**
 * @param Route            $route
 * @param AdapterInterface $console
 *
 * @return int
 */
public function __invoke(Route $route, AdapterInterface $console)
{
    $mails = $this->serviceEmail->sendMailFromDb();
    $console->writeLine('Sent mails: ' . \count($mails), ColorInterface::WHITE, ColorInterface::RED);
    return 0;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!