提问者:小点点

如何在Symfony2应用程序中创建控制台命令


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

>

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
  • 下创建文件
  • 写这段代码:

    需要目录/供应商/自动加载。php′;

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

    $应用=新应用();$应用-

    但是当我运行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]您请求了一个不存在的服务“登录uri”。

    为什么啊?我不能访问parameter.yml文件上的参数?我失败的地方?


  • 共2个答案

    匿名用户

    您正在阅读有关控制台组件的文章。这与在捆绑包中注册命令略有不同。

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

    <?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);
        }
    
    }
    

    现在,运行应用/控制台Hello: world',您应该会在终端上看到一个简单的Hello world

    希望你明白了,如果你有问题,尽管问。

    编辑

    在命令中,由于作用域的原因,您无法直接访问请求。但在调用命令时可以传递参数。在我的示例中,我注册了可选参数,它会导致两个不同的输出。

    如果您像这样调用命令app/console hello:world,您将得到以下输出

    你好世界叫没有争论通过!

    但是,如果您提供这样的名称应用程序/控制台hello:world Demo,则会得到以下结果:

    嘿,演示

    匿名用户

    下面是Artamiel的回答和下面的评论,这里是构建作为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;
            }
        }
    

    最后,将您的Controller注册为app/config/services.yml中的Service

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

    (在Symfony 2.4中,您应该注入request_stack服务,并通过调用getMONtRequest()方法访问请求,而不是注入请求服务)

    >

  • 通过将以下内容添加到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
    

    希望有帮助!