Как создать консольную команду в приложении Symfony2
Мне нужно создать консольную команду для приложения Symfony2, и я читаю документы здесь и здесь, хотя я не уверен, что из тех, которым я должен следовать. Так вот что я сделал.
- Создать файл под
/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
файл? Где я терплю неудачу?
2 ответа
Вы читаете статью о Console Component
, Это немного отличается от регистрации команды в вашем комплекте.
Во-первых, ваш класс должен жить в пространстве имен Command
, и он должен включать префикс Command в classname. Вы в основном сделали это. Я покажу вам пример команды, чтобы понять идею, чтобы вы могли продолжить работу с ней в качестве основы.
<?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
вы получите этот вывод
Привет, мир называется без аргументов!
но если вы предоставите имя, как это app/console 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; } }
Наконец, зарегистрируйте свой контроллер в качестве службы в
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
Надеюсь, это поможет!