如何在 Symfony2 应用程序中创建控制台命令
How to create a console command in Symfony2 application
我需要为 Symfony2 应用程序创建一个控制台命令,我阅读了文档 here and here 虽然我不确定我应该遵循哪些文档。所以这就是我所做的。
- 在
/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/envphp
要求 __ DIR __ .'/vendor/autoload.php';
使用PDI\PDOneBundle\Console\Command\PDOneSyncCommand;
使用 Symfony\Component\Console\Application;
$application = new Application();
$application->add(new PDOneSyncCommand());
$应用程序->运行();
但是当我通过 运行ning 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]
You have requested a non-existent service "login_uri".
为什么?我不能访问 parameter.yml
文件的参数吗?我哪里失败了?
您正在阅读有关 Console Component
的文章。这与在您的包中注册命令略有不同。
首先,您的 class 应该位于命名空间 Command
中,并且它必须在 class 名称中包含命令前缀。你大部分都是这样做的。我将向您展示一个示例命令来掌握这个想法,以便您可以以此为基础继续工作。
<?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 called without arguments passed!
但是如果您提供这样的名称 app/console hello:world Demo
您会得到以下结果:
Hey there Demo
根据 Artamiel 的 和下面的评论,在这里您需要构建一个命令 运行 作为 CRON 任务(至少,我是这样做的):
首先声明你的SalesforceCommand
class:
<?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"]
你终于可以使用 运行 它作为 CRON 作业,方法是将以下内容添加到你的 crontab(每分钟 运行):
* * * * * /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
希望对您有所帮助!
我需要为 Symfony2 应用程序创建一个控制台命令,我阅读了文档 here and here 虽然我不确定我应该遵循哪些文档。所以这就是我所做的。
- 在
/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/envphp
要求 __ DIR __ .'/vendor/autoload.php';
使用PDI\PDOneBundle\Console\Command\PDOneSyncCommand; 使用 Symfony\Component\Console\Application;
$application = new Application(); $application->add(new PDOneSyncCommand()); $应用程序->运行();
- 在
但是当我通过 运行ning 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] You have requested a non-existent service "login_uri".
为什么?我不能访问 parameter.yml
文件的参数吗?我哪里失败了?
您正在阅读有关 Console Component
的文章。这与在您的包中注册命令略有不同。
首先,您的 class 应该位于命名空间 Command
中,并且它必须在 class 名称中包含命令前缀。你大部分都是这样做的。我将向您展示一个示例命令来掌握这个想法,以便您可以以此为基础继续工作。
<?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 called without arguments passed!
但是如果您提供这样的名称 app/console hello:world Demo
您会得到以下结果:
Hey there Demo
根据 Artamiel 的
首先声明你的
SalesforceCommand
class:<?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"]
你终于可以使用 运行 它作为 CRON 作业,方法是将以下内容添加到你的 crontab(每分钟 运行):
* * * * * /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
希望对您有所帮助!