Laravel - call Artisan command and wait for the result - laravel

I'm trying to call in a controller a very time-consuming Artisan command (it executes in 20-90 s ), but I have two problems. First of all it seems like the command does not execute at all (if I return the output it just returns "0").
Secondly the other part (returning the file) does not wait for the command to execute (but it can be related to the first part). Here's my code:
public function returnZip()
{
// just a failsafe, in case if scheduled command did not created the file yet
if( ! file_exists( storage_path( '/app/exports/' . date('Y_m_d') . '.zip' ) ) ){
Artisan::call('maximus:export');
}
return response()->file( storage_path( '/app/exports/' . date('Y_m_d') . '.zip' ) );
}
How can I properly execute the Artisan command from route/controller and wait for it to finish it's task?
EDIT
I tried to debug this problem a little more and found out that the command is not being executed at all when called from a route/controller.
Tried this:
Route::get('/test', function(){
Artisan::call('maximus:export');
return ['ok'];
});
And my command is supposed to create a file:
public function handle()
{
exec('touch /some/path/storage/app/exports/test');
}
When I run this command in terminal, the file is being created, but when I hit the route, it isn't. Any ideas?

Okay, I fired up Laravel and tested it. My command is:
public function handle()
{
exec('touch ' . storage_path(str_random(16) . '.txt'));
}
It works perfectly both in terminal and in a route by calling Artisan::call().
A wild guess: does the www-data user (or whatever user the PHP used by your webserver is running as) have sufficient privilege to write the file?

I'm pretty sure that the artisan command is being handled asynchronously, so it isn't going to wait for the command to finish. Therefore your response is likely to be empty/malformed.
You may want to look into Events and Listeners to ensuring your order of operations is correct (https://laravel.com/docs/5.4/events).
For example, in your maximus:export command you could fire an event immediately after the file has been created.
Example:
Create an event called ZipCreated and a listener called SendZip. Then in your artisan command handler call the event:
event(new ZipCreated($file));
Then link it to a listener in your EventServiceProvider.php:
protected $listen = [
Events\Repository\ZipCreated::class => [
Listeners\Repository\SendZip::class,
],
];
This way ZipCreated will provide SendZip with the zipped file (or a filepath if you want) and SendZip can handle returning the file to the user.
Now whenever the command is run, the creation of the file and the handling of response will always happen in the correct order.

if I return the output it just returns "0"
Let me point out just in case that the call method doesn't return the output of the command, but its exit code ("0" meaning success). Instead, Artisan::output() will return the output.
I'd say check the logs to see what's going on, also check you are in fact useing the Artisan facade. Otherwise, try a debugger or alternatively insert informative dd() statements ;) (the entry point being Illuminate\Foundation\Console\Kernel::call).

try this:
dd(Artisan::output());

Related

How to get Artisan::call('command:name') output in a variable?

Is it possible to get $output as follows:
$output = Artisan::call('command:name');
I have tried many solutions in different posts but it didn't work on my Laravel 5.2.
You can call the output method on Artisan
Artisan::call('command:name');
$output = Artisan::output();
Make sure you are using one of the available output methods like $this->line('output'); in the actual Artisan command. More info in the docs.
There are several ways to accomplish this, but as your are using such old version of Laravel maybe the best for your case is one that will not require a rewrite when you finally migrate to a newer version. Have you tried perhaps the vanilla PHP methods system, shell_exec and passthru?
system will return just the last line of the command on succes and FALSE on failure
shell_exec will return the entire output but without a way to fetch the output status code
passthru will not return any output instead it will output all on stdout. Although it can be put into a variable using output cache methods (i.e. ob_start and ob_get_contents)
In any case you should call those methods using as argument the CLI version of the command you wish to run:
$output = shell_exec("php artisan command:here");
P.S. If you by any chance have a user input that you want to pass as parameter to a artisan command, make sure you escape it with escapeshellcmd first.

Php artisan - custom command

I would like to create my own php artisan command so when I write
php artisan env:[variable]
I want to get that variable, so I can check fast if I'm getting the right variable from .env file
Is this possible? How to do it?
You can create a console command with:
php artisan make:console
As per the docs.
You are probably better off creating a static signature and passing in the field you want to return.
protected $signature = 'env:return {field}';
This will allow you to type php artisan env:return APP_DEBUG.
You can retrieve the input like so:
public function handle()
{
$envVariable = $this->argument('field');
//
}
You can then write some code to output the field, perhaps something like:
$this->info(env($envVariable));
This could all be condensed down into something like the below, as an example only:
protected $signature = 'env:return {field}';
public function handle()
{
$this->info(env($this->argument('field')));
}
I would suggest you read the docs I linked above as this will help you understand what is happening here a lot more.
This should get you started though, and you can then shape it to be exactly what you need.

How to send an argument when using Artisan::call?

I'm trying to run an Artisan command with an argument, but I can't figure out how. How do you do it? If I run php artisan video:webmtomp4 N in the terminal, it works fine.
Artisan::call(
'video:webmtomp4',
[$data['videoId']],
new StreamOutput(fopen(storage_path() . '/logs/artisan.log', 'w'))
);
How do you send an argument to the command when using Artisan::call? $data['videoId'] is set, so that is not a problem.
Changing my comment to an answer after checking the documentation. :)
The parameters array should be associative, e.g. ['argument' => $data['videoId']],.

CodeIgniter Cron Job through Cpanel

Ok I looked at every other thread and have done exactly what they've done and what it says in the manual and I can NOT figure this out for the life of me.
The results of the cron job are being emailed to one of my emails. ALL it is doing is printing out the html markup of the layout... And printing the base page content... It's like it's not registering anything.
php /home/jdstable/public_html/dev/index.php cron decrease_pets_stats
That's my command line.. I tried replacing php with the user/local/bin/php thing as well and it didn't work. The thing is is that I have other cron jobs running off procedural PHP code that work FINE with php path/to/cron.php... But it won't work with CI..
My controller is Cron and my method is decrease_pets_stats..
//decrease pets stats
public function decrease_pets_stats() {
$this->load->model('Cron_model', 'cron');
$this->cron->decrease_pets_stats();
echo 'Decreased pet stats';
}
And here is the logic of the method:
//decrease pets stats
//runs every hour
public function decrease_pets_stats() {
$this->db->set('hunger', 'hunger - 5');
$this->db->set('happiness', 'happiness - 5');
$this->db->set('loyalty', 'loyalty - 5');
$this->db->update('user_creature');
}
Does anyone have any idea why it's just printing the layout markup? My constructor looks like this:
public function __construct() {
parent::__construct();
if( ! $this->input->is_cli_request()) show_error('Direct access is not allowed');
$this->load->model('Cron_model', 'cron');
}
And my parent constructor holds quite a bit of stuff (loading helpers and libraries along with getting the user information to appear on each page if they are logged in.
Does it matter if this is at the top of the controller before even opening the controller Cron class?
if ( ! defined('BASEPATH')) exit('No direct script access allowed');
The default PHP install you are using was probably compiled as CGI-FCGI, not for CLI. It depends on your host and/or server, but you'll need to search for your PHP install for the command line interface, and then use that in your cron job. I had the exact same problem on Hostmonster, and my cron command ended up being:
/ramdisk/bin/php5-cli ~/public_html/sitefolder/index.php controller method
For me, the PHP I needed was in /ramdisk/bin/php5-cli.
For CodeIgniter 2.2.0
You can try this two method:
php-cli /home/username/public_html/index.php controller method
wget http://www.example.com/controller/method
or at your case
php-cli /home/username/public_html/index.php Cron decrease_pets_stats
wget http://www.example.com/Cron/decrease_pets_stats
It works fine with me..
Cheers!
Had the same issue and after trying whatever I could thing the obvious worked...
/usr/local/bin/php /absolute/path/to/index.php cron
/usr/local/bin/php /home/jdstable/public_html/dev/index.php cron decrease_pets_stats
This fixed it.
Here is solution first you need to find path from phpinfo document_root file name
php5 /home/abc/public_html/index.php folder_name controller function

Doctrine 2 CLI commands from within PHP

Hey all. I am writing a program that will transform some data in our database, and then call Doctrine to build YAML files from said Mysql Database structure. I have Doctrine working from within PHP. However I can't figure out how to call the CLI commands from within PHP. Following is the Doctrine 2 CLI command that does what I need.
php ./doctrine orm:convert-mapping --filter="users" --from-database yml ./test
This command works from the Linux command line, but how to I do this same thing via Doctrine objects? I don't want to just use the PHP exec statement to send a command to the shell. I wish to use the Doctrine object model.
Don!:
Apparently this is not a very common programming method. However, I have used Doctrine from PHP by calling it via the PHP EXEC command. I know you said that you would not like to do it this way. However, it actually works quite well. Below is an example of such a solution.
$cmd_string = "php ./doctrine orm:generate-entities --generate-annotations=1 --regenerate-entities=1 $this->entity_file_dir";
$result = array();
exec($cmd_string, &$result);
Hope this helps,
-Don!
I stumbled upon this question when trying to execute a command directly from a PHP script, without using the CLI.
Particularly, I was needing to call orm:ensure-production-settings.
Each Doctrine command has its own class: http://www.doctrine-project.org/api/orm/2.4/namespace-Doctrine.ORM.Tools.Console.Command.html
I solved it the following way:
$entityManager = ...; // Get the entity manager somehow in your application
// Creates the helper set
$helperSet = \Doctrine\ORM\Tools\Console\ConsoleRunner::createHelperSet($entityManager);
// Initializes the desired command and sets the helper set
// In your case it should be ConvertMappingCommand instead
$command = new \Doctrine\ORM\Tools\Console\Command\EnsureProductionSettingsCommand();
$command->setHelperSet($helperSet);
// Initializes the input
// Alternatives: http://api.symfony.com/2.0/Symfony/Component/Console/Input.html
$input = new \Symfony\Component\Console\Input\ArgvInput(); // Input coming from the CLI arguments
// Initializes the output
// Alternatives: http://api.symfony.com/2.0/Symfony/Component/Console/Output.html
$output = new \Symfony\Component\Console\Output\ConsoleOutput(); // Prints the output in the console
// Runs the command
$command->run($input, $output);
I'm new to Doctrine so I'm not exactly sure how this works, but it does. Any comment is appreciated.

Resources