Search code examples
phpsymfonysymfony-2.6symfony-componentssymfony-console

How to create a console command in Symfony2 application


I need to create a console command for a Symfony2 application and I read docs here and here though I am not sure what of those I should follow. So this is what I did.

  • Create a file under /src/PDI/PDOneBundle/Console/PDOneSyncCommand.php
  • Write this code:

    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);
        }
    }
    
    • Create a file under /bin
    • Write this code:

      ! /usr/bin/env php

      require __ DIR __ .'/vendor/autoload.php';

      use PDI\PDOneBundle\Console\Command\PDOneSyncCommand; use Symfony\Component\Console\Application;

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

But when I go to console by running php app/console --shell and hit ENTER I can't see the command registered, what I am missing?

NOTE: Can someone with more experience than me format the second piece of code properly?

UPDATE 1

Ok, following suggestions and taking answer as a start point I built this piece of code:

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

But any time I invoke the task I got this error:

[Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException] You have requested a non-existent service "login_uri".

Why? Can't I access paramters on parameter.yml file? Where I am failing?


Solution

  • You are reading article about Console Component. This is slightly different than registering a command in your bundle.

    First, your class should live in Namespace Command, and it must include the Command prefix in classname. You've mostly done that. I will show you a sample command to grasp the idea so you can continue working with that as a base.

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

    Now, running app/console hello:world' you should see a simple Hello world at your terminal.

    Hope you got the idea, dont hesitate to ask if you have questions.

    Edit

    In Commands you cant directly access request, because of scopes. But you can pass arguments when you call your command. In my example I've registered optional argument which leads to two different outputs.

    If you call your command like this app/console hello:world you get this output

    Hello world called without arguments passed!

    but if you provide a name like this app/console hello:world Demo you get the following result:

    Hey there Demo