How to execute console command from the controller - symfony

I am using symfony 2.3
I have command in ACME\TopBundle\Command\CrawlerCommand.php
I use this command from console.
$ app/console top:crawler
But now I want to execute command from the Controller.
public function indexAction(){
// I want to execute command
}
How can I make it?
I am trying the solution that #Amine suggested.
I have two quesions.
1) How can I check the console output?
I have checked the console output class method.
but
$output->getStream()
it doesnt show the console log.

the best way is to declare your command as service
MyCommandService:
class: MyBundle\Command\MyCommand
calls:
- [setContainer, ["#service_container"] ]
and in your controller call it like this
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Output\ConsoleOutput;
.
.
public function myAction() {
$command = $this->get('MyCommandService');
$input = new ArgvInput(array('arg1'=> 'value'));
$output = new ConsoleOutput();
$command->run($input, $output);
}
or you can use this exemple: https://gist.github.com/predakanga/3487705
i prefer first solution.

Related

symfony get container not in controller and without service

i have problem with get my class function to which i send files from terminal. It's see that:
terminal: // php src/AppBundle/Provider/CommissionCost.php test.csv
in CommissionCost i want only put data to my function in Parser/CommissionDataParser.php
global $kernel;
$data = $kernel->getContainer()->get('data.parser')->getData($argv[1]);
var_dump($data);
//Uncaught Error: Call to a member function getContainer() on null
// this example i see in stackoverflow in topic about container : )
service:
services:
data.parser:
class: AppBundle\Parser\CommissionDataParser
arguments: ["#doctrine.orm.entity_manager"]
You need to add this in the configure method:
$this->addArgument('arg1', InputArgument::REQUIRED, 'Your first arg');
Then, you can access to it in the execute method by:
$input->getArgument('arg1');

Doctrine load fixtures --no-interaction flag is not working when running in a Symfony command

The --no-interaction flag on the doctrine:fixtures:load command is not working running within a Symfony command. It is working however via the terminal. I'm I calling it correctly?
When I run this from a bundle:
/**
* Loads the fixtures
* #param \Symfony\Component\Console\Output\OutputInterface $oOutput
* #return \Symfony\Component\Console\Output\OutputInterface
*/
protected function loadFixturesCommand($oOutput) {
$oOutput->writeln('<fg=white>Attempting to load fixtures</fg=white>');
$updateCommand = $this->getApplication()->find('doctrine:fixtures:load');
$updateArguments = array(
'command' => 'doctrine:fixtures:load',
'--no-interaction' => true,
);
$updateInput = new ArrayInput($updateArguments);
$updateCommand->run($updateInput, $oOutput);
try {
$updateCommand->run($updateInput, $oOutput);
} catch (ContextErrorException $e) {
//..
}
return $this;
}
I get prompted to load the fixtures
But running this:
php app/console doctrine:fixtures:load --no-interaction
Doesn't prompt me.
What am I doing wrong?
I've found the solution.
Simply call:
$input->setInteractive(false);
Like so:
protected function loadFixturesCommand($oOutput) {
$oOutput->writeln('<fg=white>Attempting to load fixtures</fg=white>');
$updateCommand = $this->getApplication()->find('doctrine:fixtures:load');
$updateArguments = array(
'command' => 'doctrine:fixtures:load'
);
$updateInput = new ArrayInput($updateArguments);
$updateInput->setInteractive(false);
$updateCommand->run($updateInput, $oOutput);
try {
$updateCommand->run($updateInput, $oOutput);
} catch (ContextErrorException $e) {
//..
}
return $this;
}
If you make a drop from your database you could also use this command I think, to be confirmed.
By default Doctrine Data Fixtures uses DELETE statements to drop the existing rows from the database.
If you want to use a TRUNCATE statement instead you can use the --purge-with-truncate flag:
php bin/console doctrine:fixtures:load --purge-with-truncate
You can use --append param to suppress interaction.
i.e. doctrine:fixtures:load --append

The Console Component in Symfony

I want to run a task using console. I checked http://symfony.com/doc/2.0/components/console/introduction.html
It asks to create GreetCommand.php.
namespace Acme\DemoBundle\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 GreetCommand extends Command
{
protected function configure()
{
$this
->setName('demo:greet')
->setDescription('Greet someone')
->addArgument(
'name',
InputArgument::OPTIONAL,
'Who do you want to greet?'
)
->addOption(
'yell',
null,
InputOption::VALUE_NONE,
'If set, the task will yell in uppercase letters'
)
;
}
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);
}
}
and create another file to run the command as given below.
#!/usr/bin/env php
# app/console
<?php
use Acme\DemoBundle\Command\GreetCommand;
use Symfony\Component\Console\Application;
$application = new Application();
$application->add(new GreetCommand);
$application->run();
But the command to run it is like app/console demo:greet Fool
The thing I won't understand is that why we need to create the second file?
Sometimes, I feel Symfony is the most difficult framework to learn.
In first file you have defined your Command class.
Second file is needed to register/initialize instance of that command. You just tell there that your application will have GreetCommand with name "demo:greet" (name defined in command itself).
BTW When you use full-stack Symfony2 with FrameworkBundle you do not have to create second file (if we follow Symfony2 conventions) cause Command is registered automatically by FrameworkBundle Console Application using HttpKernel component

How to send spool from swiftmailer without using command

How to send spool from swiftmailer without using command?
php app/console swiftmailer:spool:send --env=prod
I need to put this somehow into php file so that Server admin can add this to Schedule.
This can also be achieved by How can I run symfony 2 run command from controller , so you don't duplicate code. Worked for me.
services.yml:
services:
swiftmailer.command.spool_send:
class: Symfony\Bundle\SwiftmailerBundle\Command\SendEmailCommand
calls:
- [ setContainer, ["#service_container"] ]
Controller code (simplified):
$this->get('swiftmailer.command.spool_send')->run(new ArgvInput(array()), new ConsoleOutput());
Just do the same that the command does. From the command Execute() function:
$mailer = $this->getContainer()->get('mailer');
$transport = $mailer->getTransport();
if ($transport instanceof \Swift_Transport_SpoolTransport) {
$spool = $transport->getSpool();
if ($spool instanceof \Swift_ConfigurableSpool) {
$spool->setMessageLimit($input->getOption('message-limit'));
$spool->setTimeLimit($input->getOption('time-limit'));
}
if ($spool instanceof \Swift_FileSpool) {
if (null !== $input->getOption('recover-timeout')) {
$spool->recover($input->getOption('recover-timeout'));
} else {
$spool->recover();
}
}
$sent = $spool->flushQueue($this->getContainer()->get('swiftmailer.transport.real'));
$output->writeln(sprintf('sent %s emails', $sent));
}
You need to remove the $output->... line (maybe you can do something useful with the $sent variable). Also, this code looks for two kinds of spool, maybe you donĀ“t need all the code if your spool is not one of these kinds.

Symfony2 custom console command not working

I created a new Class in src/MaintenanceBundle/Command, named it GreetCommand.php and put the following code in it:
<?php
namespace SK2\MaintenanceBundle\Command;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
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 GreetCommand extends ContainerAwareCommand
{
protected function configure()
{
$this
->setName('maintenance:greet')
->setDescription('Greet someone')
->addArgument('name', InputArgument::OPTIONAL, 'Who do you want to greet?')
->addOption('yell', null, InputOption::VALUE_NONE, 'If set, the task will yell in uppercase letters')
;
}
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);
}
}
?>
And tried to call it via
app/console maintenance:greet Fabien
But i always get the following error:
[InvalidArgumentException]
There are no commands defined in the "maintenance" namespace.
Any ideas?
I had this problem, and it was because the name of my PHP class and file didn't end with Command.
Symfony will automatically register commands which end with Command and are in the Command directory of a bundle. If you'd like to manually register your command, this cookbook entry may help: http://symfony.com/doc/current/cookbook/console/commands_as_services.html
I had a similar problem and figured out another possible solution:
If you override the default __construct method the Command will not be auto-registered by Symfony, so you have to either take the service approach as mentioned earlier or remove the __construct override and make that init step in the execute method or in the configure method.
Does actually anyone know a good best practice how to do init "stuff" in Symfony commands?
It took me a moment to figure this out.
I figured out why it was not working: I simply forgot to register the Bundle in the AppKernel.php. However, the other proposed answers are relevant and might be helpful to resolve other situations!
By convention: the commands files need to reside in a bundle's command directory and have a name ending with Command.
in AppKernel.php
public function registerBundles()
{
$bundles = [
...
new MaintenanceBundle\MaintenanceBundle(),
];
return $bundles;
}
In addition to MonocroM's answer, I had the same issue with my command and was silently ignored by Symfony only because my command's constructor had 1 required argument.
I just removed it and call the parent __construct() method (Symfony 2.7) and it worked well ;)
If you are over-riding the command constructor and are using lazy-loading/autowiring, then your commands will not be automatically registered. To fix this you can add a $defaultName variable:
class SunshineCommand extends Command
{
protected static $defaultName = 'app:sunshine';
// ...
}
Link to the Symfony docs.
I think you have to call parent::configure() in your configure method
I had this same error when I tried to test my command execution with PHPUnit.
This was due to a wrong class import :
use Symfony\Component\Console\Application;
should be
use Symfony\Bundle\FrameworkBundle\Console\Application;
cf. Other stack thread
In my case it was complaining about the "workflow" namespace although the WorkflowDumpCommand was correctly provided by the framework.
However, it was not available to run because I have not defined any workflows so the isEnabled() method of the command returned false.
I tried to use a service passed via constructor inside the configure method:
class SomeCommand extends Command {
private $service;
public function __construct(SomeService $service) {
$this->service = $service;
}
protected function configure(): void {
$this->service->doSomething(); // DOES NOT WORK
}
}
Symfony uses Autoconfiguration that automatically inject dependencies into your services and register your services as Command, event,....
So first just make sure that you have services.yaml in your config folder. with autoconfigure:true.
this is the default setting
Then Make sure That All your files are exactly the same name as Your Class.
so if you have SimpleClass your file must be SimpleClass.php
If you have a problem because of a __constructor,
go to services.yml and add something like this:
app.email_handler_command:
class: AppBundle\Command\EmailHandlerCommand
arguments:
- '#doctrine.orm.entity_manager'
- '#app.email_handler_service'
tags:
- { name: console.command }
For newer Symfony-Version (5+) commands must be registered as services.
What I do frequently forget while setting it up, is to tag it properly:
<service id="someServiceCommand">
<tag name="console.command"/>
</service>
Without this litte adaptation, your command name will not be displayed and therefore not accessible.

Resources