【问题标题】:How to create a console command in Symfony2 application如何在 Symfony2 应用程序中创建控制台命令
【发布时间】:2015-09-02 17:33:24
【问题描述】:

我需要为 Symfony2 应用程序创建一个控制台命令,并且我阅读了文档 herehere 尽管我不确定我应该遵循哪些文档。所以这就是我所做的。

  • /src/PDI/PDOneBundle/Console/PDOneSyncCommand.php下创建文件
  • 写下这段代码:

    namespace PDI\PDOneBundle\Console\Command;
    
    use Symfony\Component\Console\Command\Command;
    use Symfony\Component\Console\Input\InputArgument;
    use Symfony\Component\Console\Input\InputInterface;
    use Symfony\Component\Console\Input\InputOption;
    use Symfony\Component\Console\Output\OutputInterface;
    
    class PDOneSyncCommand extends Command
    {
        protected function configure()
        {
            $this
                ->setName('pdone:veeva:sync')
                ->setDescription('Some description');
        }
    
        protected function execute(InputInterface $input, OutputInterface $output)
        {
            $name = $input->getArgument('name');
            if ($name) {
                $text = 'Hello '.$name;
            } else {
                $text = 'Hello';
            }
    
            if ($input->getOption('yell')) {
                $text = strtoupper($text);
            }
    
            $output->writeln($text);
        }
    }
    
    • /bin下创建一个文件
    • 写下这段代码:

      ! /usr/bin/env php

      需要 __ DIR __ .'/vendor/autoload.php';

      使用 PDI\PDOneBundle\Console\Command\PDOneSyncCommand; 使用 Symfony\Component\Console\Application;

      $application = new Application(); $application->add(new PDOneSyncCommand()); $application->run();

但是当我通过运行php app/console --shell 并点击ENTER 进入控制台时,我看不到注册的命令,我错过了什么?

注意:比我更有经验的人能否正确格式化第二段代码?

更新 1

好的,按照建议并以答案为起点,我构建了这段代码:

protected function execute(InputInterface $input, OutputInterface $output)
{
    $container = $this->getContainer();

    $auth_url = $container->get('login_uri')."/services/oauth2/authorize?response_type=code&client_id=".$container->get('client_id')."&redirect_uri=".urlencode($container->get('redirect_uri'));

    $token_url = $container->get('login_uri')."/services/oauth2/token";
    $revoke_url = $container->get('login_uri')."/services/oauth2/revoke";

    $code = $_GET['code'];

    if (!isset($code) || $code == "") {
        die("Error - code parameter missing from request!");
    }

    $params = "code=".$code
        ."&grant_type=".$container->get('grant_type')
        ."&client_id=".$container->get('client_id')
        ."&client_secret=".$container->get('client_secret')
        ."&redirect_uri=".urlencode($container->get('redirect_uri'));

    $curl = curl_init($token_url);
    curl_setopt($curl, CURLOPT_HEADER, false);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_POST, true);
    curl_setopt($curl, CURLOPT_POSTFIELDS, $params);

    $json_response = curl_exec($curl);

    $status = curl_getinfo($curl, CURLINFO_HTTP_CODE);

    if ($status != 200) {
        die("Error: call to token URL $token_url failed with status $status, response $json_response, curl_error ".curl_error(
                $curl
            ).", curl_errno ".curl_errno($curl));
    }

    curl_close($curl);

    $response = json_decode($json_response, true);

    $access_token = $response['access_token'];
    $instance_url = $response['instance_url'];

    if (!isset($access_token) || $access_token == "") {
        die("Error - access token missing from response!");
    }

    if (!isset($instance_url) || $instance_url == "") {
        die("Error - instance URL missing from response!");
    }

    $output->writeln('Access Token ' . $access_token);
    $output->writeln('Instance Url ' . $instance_url);
}

但每当我调用任务时,我都会收到此错误:

[Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException] 您请求了一个不存在的服务“login_uri”。

为什么?我不能访问parameter.yml 文件上的参数吗?我哪里失败了?

【问题讨论】:

  • 在您编辑之后,我宁愿使用ContainerAwareCommand 子类来仅运行一项服务。不确定在execute() 命令中包含所有这些代码是一种好习惯。我的回答对你有帮助吗?
  • @D4V1D 是的,这两个答案都对我有帮助,我正在将代码移至您的代码,并将很快进行测试,如果我有任何问题,会通知您。如果我将控制器注册为服务,我还能将其用作普通控制器吗?我想稍后也从网络后端使用它
  • 这很棘手,但可能。告诉我,我会帮助您实现这一目标。

标签: php symfony symfony-2.6 symfony-components symfony-console


【解决方案1】:

您正在阅读有关Console Component 的文章。这与在包中注册命令略有不同。

首先,你的类应该存在于命名空间Command,并且它必须在类名中包含命令前缀。你大部分都是这样做的。我将向您展示一个示例命令来掌握这个想法,以便您可以继续以此为基础。

<?php

namespace AppBundle\Command;

use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

// I am extending ContainerAwareCommand so that you can have access to $container
// which you can see how it's used in method execute
class HelloCommand extends ContainerAwareCommand {

    // This method is used to register your command name, also the arguments it requires (if needed)
    protected function configure() {
        // We register an optional argument here. So more below:
        $this->setName('hello:world')
            ->addArgument('name', InputArgument::OPTIONAL);
    }

    // This method is called once your command is being called fron console.
    // $input - you can access your arguments passed from terminal (if any are given/required)
    // $output - use that to show some response in terminal
    protected function execute(InputInterface $input, OutputInterface $output) {
        // if you want to access your container, this is how its done
        $container = $this->getContainer();

        $greetLine = $input->getArgument('name') 
            ? sprintf('Hey there %s', $input->getArgument('name')) 
            : 'Hello world called without arguments passed!'
        ;

        $output->writeln($greetLine);
    }

}

现在,运行app/console hello:world',您应该会在终端上看到一个简单的Hello world

希望您明白这一点,如果您有任何问题,请不要犹豫。

编辑

在命令中,您不能直接访问请求,因为范围。但是您可以在调用命令时传递参数。在我的示例中,我注册了导致两个不同输出的可选参数。

如果你像这样app/console hello:world 调用你的命令,你会得到这个输出

Hello world 调用时没有传递参数!

但如果您提供这样的名称 app/console hello:world Demo 您会得到以下结果:

嘿,演示

【讨论】:

  • 效果很好,我还有一个疑问,我如何在这里访问请求?我正在创建一个命令来执行类似here 所示的任务,其中包括来自 Salesforce 的 cURL 调用和响应,我应该如何处理?你能用一个简单的例子来改进你的问题吗?
  • 您应该在一个控制器中进行所有操作,并将该控制器注册为服务。您可以通过 $this-&gt;get('my_service'); 在控制器中注入所需的任何内容并调用它(在此 HelloCommand 类中)。
  • @D4V1D 我的意图是构建一个命令,因为我需要将它作为 CronJob 任务运行,您的建议在这种情况下是否有效?你能写一个例子吗? (一小部分只是为了了解整个想法?)
  • @ReynierPM 我会写一个答案,如果它对你有帮助,请不要犹豫(因为你已经接受了这个答案)。
  • @ReynierPM 我添加了更多关于参数及其使用的信息。
【解决方案2】:

按照 Artamiel 的 answer 和下面的 cmets,您需要构建作为 CRON 任务运行的命令(至少,我是这样做的):

  • 首先,声明你的SalesforceCommand 类:

    <?php
    class SalesforceCommand extends ContainerAwareCommand
    {
        protected function configure()
        {
            $this
                ->setName('pdone:veeva:sync')
                ->setDescription('Doing some tasks, whatever...');
        }
    
        protected function execute(InputInterface $input, OutputInterface $output)
        {    
            $myService = $this->getContainer()->get('my.service');
    
            $returnValue = $myService->whateverAction();
    
            if($returnValue === true)
                $output->writeln('Return value of my.service is true');
            else
                $output->writeln('An error occured!');
        }
    }
    
  • 然后,在任何你想要的包中创建你的控制器:

        <?php
        namespace My\MyBundle\Service;          
    
        use Symfony\Component\HttpFoundation\RequestStack;
    
        class ServiceController extends Controller
        {
            private $_rs;
    
            public function __construct(RequestStack $rs)
            {
                $this->_rs = $rs;
            }
    
            public function whateverAction()
            {
                $request = $this->_rs->getCurrentRequest();
    
                // do whatever is needed with $request.
    
                return $expectedReturn ? true : false;
            }
        }
    
  • 最后,在app/config/services.yml注册你的控制器作为服务

    services:
        my.service:
            class: My\MyBundle\Service\ServiceController
            arguments: ["@request_stack"]
    

(as of Symfony 2.4, instead of injecting the request service, you should inject the request_stack service and access the Request by calling the getCurrentRequest() method)

  • 您终于可以通过将以下内容添加到您的 crontab(使其每分钟运行一次)将其作为 CRON 作业运行:

    * * * * * /usr/local/bin/php /path/to/your/project/app/console pdone:veeva:sync 1>>/path/to/your/log/std.log 2>>/path/to/your/log/err.log
    

希望有帮助!

【讨论】:

    猜你喜欢
    • 2013-09-01
    • 2014-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-24
    • 2015-10-06
    • 1970-01-01
    • 2023-04-05
    相关资源
    最近更新 更多