If I execute a task using the console I can add --no-debug:
php app/console app:task-name web-user --no-debug
This is the function inside Controller that call the task 'task-name ' and it works properly
public function generateSomethingAction() {
$kernel = $this->get('kernel');
$application = new Application($kernel);
$application->setAutoExit(false);
$input = new ArrayInput(array(
'command' => 'app:task-name'
));
$output = new BufferedOutput();
$application->run($input, $output);
......
I would like to know if is possible to add --no-debug if I call the command from a controller?
To pass additional parameters that don't need values, you can just add them to the ArrayInput array with a value of "true".
E.g.
$input = new ArrayInput([
'command' => 'app:task-name',
'--yell' => true,
'--no-debug' => true,
]);
Related
firstly this function will be executed after below code will be execute for formatting code
public function formatCode(): bool
{
$output = [];
exec(
'php '.storage_path('php-cs-fixer.phar').' fix --config='.base_path('.php-cs-fixer.dist.php'), $output);
return true;
}
This is my code for the format of all files of my project, I am currently using this package https://github.com/FriendsOfPHP/PHP-CS-Fixer
$finder = PhpCsFixer\Finder::create()
->ignoreVCSIgnored(true)
->exclude('tests/Fixtures')
->in(__DIR__.'/../laravel8')
->ignoreDotFiles(true)
->ignoreVCS(true)
->append([
__DIR__.'/dev-tools/doc.php',
__FILE__,
]);
$config = new PhpCsFixer\Config();
$config
->setRiskyAllowed(true)
->setRules([
'#PSR12' => true,
])
->setFinder($finder);
I'm working on a Symfony 4.2 project and I'm looking for the best practice to achieve a reset of the database when the admin needs to do it via a button in backoffice.
Explanation :
The project is a temporary event website.
This means that, people will visit the website only for a day / a week and then the website is off. Per example, a website for spectators into a stadium during a basketball tournament.
When the tournament is over, the administrator would like to reset all datas sent during it via a button.
Right now I did it like this but I don't know if it's the better way in production environment.
I created a service which get the KernelInterface in constructor :
public function resetDB() {
$application = new Application($this->kernel);
$application->setAutoExit(false);
$input = new ArrayInput([
'command' => 'doctrine:schema:drop',
'--force' => true
]);
$output = new BufferedOutput();
$application->run($input, $output);
$responseDrop = $output->fetch();
if (strpos($responseDrop, 'successfully') !== false) {
$input = new ArrayInput([
'command' => 'doctrine:schema:create',
]);
$application->run($input, $output);
$responseCreate = $output->fetch();
if (strpos($responseCreate, 'successfully') !== false)
return new Response();
}
return new \ErrorException();
}
Firstly, is it good to do it like this in a production environment ? (Nobody else the administrator will use the website when doing this operation)
Secondly, I'm not really satisfied with the method I used to check if the operation has been successfully done (strpos($responseCreate, 'successfully') !== false). Does someone know a better way ?
Thanks a lot for your help
If it works for you, its ok. About the "successful" check part. Simply surround your call in a try-catch block and check for exceptions. If no exception was thrown, assume it did execute successfully.
$application = new Application($this->kernel);
$application->setAutoExit(false);
try {
$application->run(
new StringInput('doctrine:schema:drop --force'),
new DummyOutput()
);
$application->run(
new StringInput('doctrine:schema:create'),
new DummyOutput()
);
return new Response();
} catch (\Exception $exception) {
// don't throw exceptions, use proper responses
// or do whatever you want
return new Response('', Response::HTTP_INTERNAL_SERVER_ERROR);
}
Is PostgreSQL good enough at DDL transactions? Force a transaction then:
$application = new Application($this->kernel);
$application->setAutoExit(false);
// in case of any SQL error
// an exception will be thrown
$this->entityManager->transactional(function () use ($application) {
$application->run(
new StringInput('doctrine:schema:drop --force'),
new DummyOutput()
);
$application->run(
new StringInput('doctrine:schema:create'),
new DummyOutput()
);
});
return new Response();
I'm not sure about the way you executing the commands, but there is a single command alternative to consider, using DoctrineFixturesBundle. You need to install it for use in the production environment (technically not recommended, I think because of risk of deleting prod data, but that's what you want to do).
Install:
$ composer require doctrine/doctrine-fixtures-bundle
Config:
// config/bundles.php
return [
...
Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['all' => true],
...
];
You do need to create a fixture and it must have a load() method that is compatible with Doctrine\Common\DataFixtures\FixtureInterface::load(Doctrine\Common\Persistence\ObjectManager $manager), but it can be empty exactly like below:
<?php // src/DataFixtures/AppFixtures.php
namespace App\DataFixtures;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\Persistence\ObjectManager;
class AppFixtures extends Fixture
{
public function load(ObjectManager $manager){}
}
The command:
$ php bin/console doctrine:fixtures:load -n --purge-with-truncate --env=prod
Help:
$ php bin/console doctrine:fixtures:load --help
Firstly, is it good to do it like this in a production environment ?
I don't think so! For example the commands below would warn you with: [CAUTION] This operation should not be executed in a production environment!. However, everything is possible in wild programming world as shown below.
Try Symfony's The Process Component.
This is the basic example so it is up to you make it cleaner and duplication free. I tested and it works. You can stream the output as well.
# DROP IT
$process = new Process(
['/absolute/path/to/project/bin/console', 'doctrine:schema:drop', '--force', '--no-interaction']
);
$process->run();
if (!$process->isSuccessful()) {
throw new ProcessFailedException($process);
}
# RECREATE IT
$process = new Process(
['/absolute/path/to/project/bin/console', 'doctrine:schema:update', '--force', '--no-interaction']
);
$process->run();
if (!$process->isSuccessful()) {
throw new ProcessFailedException($process);
}
Per http://twig.sensiolabs.org/doc/api.html#using-extensions:
When creating a new Twig_Environment instance, you can pass an array
of options as the constructor second argument:
$twig = new Twig_Environment($loader, array('debug' => true));
How would this be implemented when used with Slim? My attempt is below, however, {{ dump(foo) }} results in an Unknown "dump" function in "forms.html" at line 35. error. I have tried adding the script on the Twig website, however, I don't know what to use for $loader and where to insert $twig.
$container['view'] = function ($c) {
$view = new \Slim\Views\Twig('../application/templates', [
//'cache' => 'path/to/cache' // See auto_reload option
'debug' => true,
'strict_variables'=> true
]);
$view->addExtension(new \Slim\Views\TwigExtension(
$c['router'],
$c['request']->getUri()
));
return $view;
};
I need to run a command asynchronously. To do this, I'm trying to use Process Component.
The command I'm trying to start is calling a function that needs somes parameters. These parameters are given by Controller that launches the Process.
Problem is I don't know how to pass parameters to my command with Process Component.
Command :
protected function configure()
{
$this
->setName('generationpdf:classement')
->setDescription('Génère le PDF d\'un classement.');
}
protected function execute(InputInterface $input, OutputInterface $output)
{
ini_set('memory_limit','4000M');
$pdf = $this->imprimerAction();
$this->sendClassement($pdf);
$output->writeln('PDF envoyé.');
}
Controller :
$command = new PDFClassementCommand();
$input = new ArrayInput(array('id' => $id, 'errata' => $errata, 'precision' => $precision, 'group' => $group, 'logoAnnee' => $logoAnnee));
$output = new NullOutput();
$process = new Process($command);
$process->disableOutput();
$process->start();
Parameters I need to use are in ArrayInput but Process doesn't take array argument.
The process is expecting first argument to be string.
Example:
$process = new Process('ls');
To run command you will need to execute symfony console command
$process = new Process('/var/www/my-project/bin/console generationpdf:classement')
You don't have to hardcode the path, see how-to-get-the-root-dir.
You can pass parameters normally, like running command from cli
$process = new Process('/var/www/my-project/bin/console generationpdf:classement --id=5 --errata=someValue')
I am migrating my Laravel 4.2 app to 5.1 (starting with 5.0) and am a lot of trouble with my console command unit tests. I have artisan commands for which I need to test the produced console output, proper question/response handling and interactions with other services (using mocks). For all its merits, the Laravel doc is unfortunately silent with regards to testing console commands.
I finally found a way to create those tests, but it feels like a hack with those setLaravel and setApplication calls.
Is there a better way to do this? I wish I could add my mock instances to the Laravel IoC container and let it create the commands to test with everything properly set. I'm afraid my unit tests will break easily with newer Laravel versions.
Here's my unit test:
Use statements:
use Mockery as m;
use App\Console\Commands\AddClientCommand;
use Symfony\Component\Console\Tester\CommandTester;
Setup
public function setUp() {
parent::setUp();
$this->store = m::mock('App\Services\Store');
$this->command = new AddClientCommand($this->store);
// Taken from laravel/framework artisan command unit tests
// (e.g. tests/Database/DatabaseMigrationRollbackCommandTest.php)
$this->command->setLaravel($this->app->make('Illuminate\Contracts\Foundation\Application'));
// Required to provide input to command questions (provides command->getHelper())
// Taken from ??? when I first built my command tests in Laravel 4.2
$this->command->setApplication($this->app->make('Symfony\Component\Console\Application'));
}
Input provided as command arguments. Checks console output
public function testReadCommandOutput() {
$commandTester = new CommandTester($this->command);
$result = $commandTester->execute([
'--client-name' => 'New Client',
]);
$this->assertSame(0, $result);
$templatePath = $this->testTemplate;
// Check console output
$this->assertEquals(1, preg_match('/^Client \'New Client\' was added./m', $commandTester->getDisplay()));
}
Input provided by simulated keyboard keys
public function testAnswerQuestions() {
$commandTester = new CommandTester($this->command);
// Simulate keyboard input in console for new client
$inputs = $this->command->getHelper('question');
$inputs->setInputStream($this->getInputStream("New Client\n"));
$result = $commandTester->execute([]);
$this->assertSame(0, $result);
$templatePath = $this->testTemplate;
// Check console output
$this->assertEquals(1, preg_match('/^Client \'New Client\' was added./m', $commandTester->getDisplay()));
}
protected function getInputStream($input) {
$stream = fopen('php://memory', 'r+', false);
fputs($stream, $input);
rewind($stream);
return $stream;
}
updates
This doesn't work in Laravel 5.1 #11946
I have done this before as follows - my console command returns a json response:
public function getConsoleResponse()
{
$kernel = $this->app->make(Illuminate\Contracts\Console\Kernel::class);
$status = $kernel->handle(
$input = new Symfony\Component\Console\Input\ArrayInput([
'command' => 'test:command', // put your command name here
]),
$output = new Symfony\Component\Console\Output\BufferedOutput
);
return json_decode($output->fetch(), true);
}
So if you want to put this in it's own command tester class, or as a function within TestCase etc... up to you.
use Illuminate\Support\Facades\Artisan;
use Symfony\Component\Console\Output\BufferedOutput;
$output = new BufferedOutput();
Artisan::call('passport:client', [
'--password' => true,
'--name' => 'Temp Client',
'--no-interaction' => true,
], $output);
$stringOutput = $output->fetch();