Symfony2 Programmatically console command call does not work with namespaces - symfony

I have a problem with execution of the Command in the Symfony2, mainly I have a command 'php app/console lets:do:this
which is executing the existing commands:
$this->dumpToXml($input, $output);
$this->dumpToAnnotation($input, $output);
$this->dumpToEntity($input, $output);
But the second command 'dumpToAnnotation' fails. It indeed generates the php entity files but without the namespace (the namespace is included in the orm.xml files).
That is the method that fails:
private function dumpToAnnotation(InputInterface $input, OutputInterface $output)
{
// check if the command exists
$command = $this->getApplication()->find('doctrine:mapping:convert');
// collect all arguments and options
$arguments = array(
'command' => 'doctrine:mapping:convert',
'to-type' => 'annotation',
'dest-path' => './src',
'--force' => true
);
// core objects
$input = new ArrayInput($arguments);
// execute the command
$command->run($input, $output);
}
It gives the output of Processing entity 'Users' instead of Processing entity 'MyApp/MyBundle/Entity/Users.
When I execute the command from the CLI, there is no problem at all, it's just does not work in the Command of Symfony2.
I hope someone can help me with that.
Regards, Greg.

Related

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

Symfony Profiler on Console Command

When running a Symfony app in the dev environment, the web debug toolbar allows me to see how many queries that Doctrine generated. Is there a similar profiler option for Console commands?
As described in the docs, the profiler only collects information for all requests. I believe there is no collector for the console commands. One of the ways to get more insight into the queries executed by Doctrine is to check your log files. For example, you can do something like this on Unix based systems:
tail -f app/logs/dev.log | grep doctrine
Also see: http://symfony.com/doc/current/book/internals.html#profiler
Yeah, --verbose is useful as #manolo mentioned. You can control what gets output in -v -vv -vvv from the monolog handler config
monolog:
handlers:
main:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: debug
console:
type: console
bubble: false
verbosity_levels:
VERBOSITY_VERBOSE: INFO
VERBOSITY_VERY_VERBOSE: DEBUG
channels: ["!doctrine"]
console_very_verbose:
type: console
bubble: false
verbosity_levels:
VERBOSITY_VERBOSE: NOTICE
VERBOSITY_VERY_VERBOSE: NOTICE
VERBOSITY_DEBUG: DEBUG
channels: ["doctrine"]
Notice how you can even disable a channel -v or --verbose will only output non doctrine logs at the specified verbose levels.
First of all, symfony profiler depends on Request. Thats why its cant be used in console commands out of the box and, probably, it will not be fixed. Related symfony issue
But you still can access default DBAL profiling logger. It should be instance of Doctrine\DBAL\Logging\DebugStack
It have public queries property, which hold all executed queries, parameters, execution time etc.
Whenever you will need to debug actual queries - you can do in such a way
/** #var $em Registry */
$em = $this->getContainer()->get('doctrine')->getManager();
$profiler = $this->getContainer()->get('doctrine.dbal.logger.profiling.default');
$shop = $em->getRepository(Shop::class)->find(7);
$sku = $em->getRepository(Sku::class)->find(45);
// clear profiles data, we want to profile Criteria below
$profiler->queries = [];
$shopWares = $shop->getShopWarePagesForSku($sku);
$output->writeln(var_export($profiler->queries));
It would generate output like
array (
3 =>
array (
'sql' => 'SELECT ...... FROM ShopWarePage t0 WHERE (t0.sku_id = ? AND t0.sku_id = ?)',
'params' =>
array (
0 => 45,
1 => 7,
),
'types' =>
array (
0 => 'integer',
1 => 'integer',
),
'executionMS' => 0.00075292587280273438,
),
)
It's possible to run a command from the controller or other services. So all command information will be in the profiler.
There is an example from symfony docs
// src/Controller/DebugTwigController.php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\BufferedOutput;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\KernelInterface;
class DebugTwigController extends AbstractController
{
public function debugTwig(KernelInterface $kernel): Response
{
$application = new Application($kernel);
$application->setAutoExit(false);
$input = new ArrayInput([
'command' => 'debug:twig',
// (optional) define the value of command arguments
'fooArgument' => 'barValue',
// (optional) pass options to the command
'--bar' => 'fooValue',
]);
// You can use NullOutput() if you don't need the output
$output = new BufferedOutput();
$application->run($input, $output);
// return the output, don't use if you used NullOutput()
$content = $output->fetch();
// return new Response(""), if you used NullOutput()
return new Response($content);
}
}

Unable to run two migration execute commands together within a single console command

For development we have a single Symfony console command that executes other console commands in order to rebuild db, run fixtures etc.
As part of the process I need to run a few cherry-picked doctrine migration commands, but for some reason I'm unable to run multiple execute commands within the same process.
To confirm, I can run these tasks without issue manually, and can run one of either command within the console execute and then the other manually without issue.
$this->getApplication()->run(new ArrayInput(array(
'command' => 'doctrine:migrations:execute',
'version' => '20140310162336',
'--no-interaction' => true
)), $output);
$this->getApplication()->run(new ArrayInput(array(
'command' => 'doctrine:migrations:execute',
'version' => '20140310170437',
'--no-interaction' => true
)), $output);
The error returned is:
[Doctrine\DBAL\Migrations\MigrationException]
Migration version 20140310162334 already registered with class Doctrine\DBAL\Migrations\Version
The version being the first version file that exists, can confirm that one is not in the migration_versions table, nor is it wanted in this scenario. Suggesting it is just loaded into the migrations object.
Can anyone offer input if I'm doing something wrong of if this is perhaps a bug somewhere.
Running Symfony 2.2.* and migrations bundle using dev-master.
I had the same problem on symfony 2.6 and the solution described by Alexei Tenitski didn't work althought it seemed a valid one.
This is the solution that worked for me.
/**
* Loop thorugh the config and path config for migrations
* and execute migrations for each connection
*/
foreach (array_keys($this->migrationsConfig) as $configEm) {
if (
(empty($ems) || in_array($configEm, $ems))
&& !in_array($configEm, $ignoreEms)
) {
try {
// new instance of the command you want to run
// to force reload MigrationsConfig
$command = new MigrateSingleCommand($this->migrationsConfig);
$command->setApplication($this->getApplication());
$arguments = [
'command' => $commandString,
'--em' => $configEm,
];
$input = new ArrayInput($arguments);
$command->run($input, $output);
} catch (\Exception $e) {
$output->writeln(sprintf("<error>Error: %s</error>", $e->getMessage()));
}
}
}
if you use $this->getApplication()->run() it will take the command from $this->application->commands where the commands are initialized only once and (when the command calling is initialized) so the MigrationsConfig will stay the same on all iterations.
The problem is that application uses same instance of command for each call and Doctrine migrate commands are not designed to work in such environment. One way to work around it is to clone command and work with its instance directly:
$commandName = 'doctrine:migrations:execute';
$prototypeCommand = $this->getApplication()->get($commandName);
// This is required to avoid merging of application definition for each cloned command
$prototypeCommand->mergeApplicationDefinition();
// Create a clone for a particular run
$command1 = clone $prototypeCommand;
// Run the command with specific params
$command1->run($input1, $output)
// Create another clone
$command2 = clone $prototypeCommand;
// Run the command with another set of params
$command2->run($input2, $output)
My guess is that it is because you are trying to run the migration command multiple times at once.
You might want to try using a work queue system, there is probably even a bundle that does that.

How to execute console command from the controller

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.

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

Resources