A way to call a command prompt function from controller in Laravel? - php

I'm trying to make a thumbnail in a Laravel project and I tried a lot other ways but with no success - Libraries, APIs... The problem is that the project is developed in Windows and the professor needs it in Windows as well.
So far, I experimented to integrate different libraries (wkhtmltoimage, spatie/browsershot, mpdf and s.o.) but in the most of the cases, there are problems with the path.
The required function, which I need, works very good in command prompt and I thought that I must find a way to call it in the controller.
I've tried with:
shell_execute($call);
system($call);
exec($call);
// with $call = "{func_name} {path_to_input_file} {name_of_output_file}";
// Example: $call = "wkhtmltoimage C:\xampp\htdocs\app\public\test.html img.jpg"
But no result. The function generates an image, which I want to store in the database.
Is there an other way to make a call to the command prompt?
Maybe SSH call?

You can execute Artisan commands directly via your controller.
Look at this example from the Laravel documentation:
Route::get('/foo', function () {
$exitCode = Artisan::call('email:send', [
'user' => 1, '--queue' => 'default'
]);
//
});

Related

Artisan::call command package throws error exception will calling through web page

I'm using docker for running a Laravel project and i have this command in Laravel that writes into a file in storage folder
Artisan::call(
'app:cache',
[
"--message" => 'this is a command',
"--seconds" => 0
]
)
when i call it through web like
Route::get('/', function () {
\Artisan::call(
'app:cache',
[
"--message" => 'this is a command',
"--seconds" => 0
]
);
});
an exception from /src/vendor/symfony/console/Input/ArrayInput.php file is generated with this message: "Trying to access array offset on value of type int"
but in command line this command is working completely OK.
the issue was coming from my using version of PHP, the PHP version was 7.4.1 and the package that Laravel was using for this version of PHP was changed and that caused the error to happen, I changed my using PHP version to 7.2 and got worked.
I have been given the code but normally, programmers should not use this kind of packages this way, for example in this one, WEB should not call Artisan commands directly, because if a situation like this happens you will need to override your code like everywhere. Instead, use your own code and put what you want behind it, as an example:
imaging you have this artisan command that writes some information in a file and you want to use it in your WEB section then you must put your code into a class or function outside of your artisan command and use your class/function in your artisan and web for work. then code like bellow
Route::get('/', function () {
\Artisan::call(
'app:cache',
[
"--message" => 'this is a command',
"--seconds" => 0
]
);
});
will become to code like
Route::get('/', function () {
$cache = new \App\Custom\Cache(
$message = 'this is a command',
$seconds = 0
);
});
In this way, your functioning code is separated from your framework and if you even use some packages in your class/function and a package needs to change like it was to call Artisan command then there is just one place to update, not multiple places.
Try calling it like this:
Artisan::call('app:cache --message="this is a command" --seconds=0');
and if you want to put dynamic variables in it:
Artisan::call('app:cache --message=' . $yourMessage . '--seconds=' . $seconds);
You will not have to handle any arrays by passing your variables in a single string line like this. It still makes it simple to read as a single string.

How can I execute shell script file from laravel app

I have commands in a shell script file and I need to execute it when certain event happen in my app, I search in google to find a better way to do it so I found Symfony library called process, but I don't know how to send parameters to the shell script file cause my file will receive some arguments actually three arguments, and file located in path /home/user/myfile.sh.
Inside my controller look like :
public function store()
{
$process = new Process('/home/user/myfile.sh', null, [
'a',
'b',
'c'
]);
$process->run();
return $process->getOutput();
}
when executing my function nothing happen jus get a response 200, can someone help me what is going on what is my fault or anything?
Your codes look good. Problem at your myfile.sh. Please make sure bash script returns somethings.

Laravel small standalone one-off script without artisan command?

I need to check something small in Laravel, so I just want to make a small script to check it.
I know that I can do it with
php artisan make:console ...
But It will add a file to the App/Console/Command, and I will need to update app/Console/Kernel.php. It means that I will have do commit it to source control, which is really not needed.
Is there a way to have a standalone laravel script which will give me access to the Laravel Components?
I am using Laravel 5.2, (make:command doesn't exists, only make:console)
Just an example for what I tried:
<?php
use App\User;
use DB;
require __DIR__.'/../vendor/autoload.php';
require __DIR__.'/..//bootstrap/app.php';
echo "hello world\n";
$res=User::where('id',5)->first();
echo "end!\n";
?>
But I am getting an error:
PHP Fatal error: Uncaught Error: Call to a member function connection() on null in /var/www/html/dpriceit/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:3314
Stack trace:
#0 /var/www/html/dpriceit/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(3280): Illuminate\Database\Eloquent\Model::resolveConnection(NULL)
#1 /var/www/html/dpriceit/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(1880): Illuminate\Database\Eloquent\Model->getConnection()
#2 /var/www/html/dpriceit/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(1853): Illuminate\Database\Eloquent\Model->newBaseQueryBuilder()
#3 /var/www/html/dpriceit/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(1823): Illuminate\Database\Eloquent\Model->newQueryWithoutScopes()
#4 /var/www/html/dpriceit/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(3524): Illuminate\Database\Eloquent\Model->newQuery()
UPDATE
I tried creating a console command
php artisan make:console MyTempTest
But when I do php artisan list I don't see its signature in the list of available commands.
To fix the error you're getting, boot up the application's kernel and handle the response like so
app\script.php
<?php
use App\User;
require __DIR__.'/../vendor/autoload.php';
$app = require_once __DIR__.'/../bootstrap/app.php';
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
$response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
);
echo "hello world\n";
$res = User::find(5)->name;
var_dump($res);
echo "end!\n";
Then from a terminal, run php app/script.php
Result:
~/Sites/laravel (master ✗) ✹ ★ ᐅ php app/script.php
hello world
string(11) "Khalid Bins"
end!
When I want to try/test something in Laravel, I usually do one of three things:
If the "something" I want to try is a simple one-liner I use Tinker: artisan tinker. This gives you the fully booted Laravel Framework, ready to use any class or function you want. This is usually my go-to when I want to: Test a global helper function I just created; Create a model using a factory, to check if my factory is setup correctly; Check if my $casts array on a model is setup the right way;
Another scenario might involve a bit more code, maybe a few lines to retrieve some data from the database, mutate it and show it on a page. For this you can simply create a closure based route in the file routes/web.php:
Route::get('test-url', function () {
$user = User::where('email', 'user#example.com')->first();
$user->makeAdmin()->save();
// I can see on the page if the attributes have been changed, as a result of the makeAdmin() call.
return $user->getAttributes();
});
The same is possible for console routes. Add a structure like this in your routes/console.php file:
Artisan::command('test:functionality', function () {
$instance = new BusinessLogic();
$result = $instance->someVeryInterestingMethod();
dump($result);
});
You can then call this function from the command line with php artisan test:functionality. You can, of course, call the command whatever you like.
Then the last scenario; when I want to try something new (like a new package, library, plugin) and it will be more than a few lines of code. I create a new test class with php artisan make:test ThrowawayTest (or another randomly chosen name). I can then add a few lines of code and run it with PHPUnit. I have set my editor to launch the test that my cursor is on with the key-combination CTRL-T so that I can re-run it quickly when some code changed.
This means I can let some code stay in its function, and write a new function to elaborate on the things I just learned about the new package. When I am finished I can either leave the code and commit it to the repository, so that I can check the code later on when I need to use some of it again for production code. I can also throw away the test file if it seems like I won't need the code for reference in the future.
This last solution also gives me the added benefit of being able to use assert statements from PHPUnit.
Hope this gives you some insight on the different possibilities with the Laravel Framework when it comes to trying or testing out new stuff.

How to get currently used Artisan console command name in Laravel 5?

Problem / What I've tried:
Getting the currently used controller and action in Laravel 5 is easy (but not as easy as it should be), however I'm stuck with getting the currently used artisan console command.
To fetch the controller name I do this:
$route = Route::getRoutes()->match(Request::capture());
$listAction = explode('\\', $route->getActionName());
$rawAction = end($listAction);
// controller name and action in a simple array
$controllerAndAction = explode('#', $rawAction);
But when calling from a console action, it always returns the default index controller's name ("IndexController" or so in Laravel). Does anybody know how to make this ?
By the way I've also worked throught Request::capture() but this still gives no info about the command.
The simplest way is to just to look at the arguments specified on the command line:
if (array_get(request()->server(), 'argv.1') === 'cache:clear') {
// do things
}
Yes, you can use $_SERVER directly, but I like to use the helper functions or the Facades, as those will give you the current data.
I go from the assumption that - during unit tests - the superglobals might not always reflect the currently tested request.
By the way: Obviously can also do array_get(request()->server('argv'), '1') or something alike. (request()->server('argv.1') doesnt work at this point). Or use \Request::server(). Depends on what you like most.
As per the Symfony\Component\Console\Command\Command class, the method to return the name of the command (eg. my:command) is:
$this->getName();
You should use it from within an Artisan command extending Illuminate\Console\Command (default on Artisan commands).
Remember that it will return only the command name and not the available parameters (eg. for the command signature my:command {--with-params=} it will only return my:command).
Reflection might be of help? Try this:
$var = new \ReflectionClass($this);
dd($var);

How laravel classes are included?

I want to run custom php code in laravel directly without using any routes or http requests..
I hope I can make it clear, I mean, like those online tools that runs php code by writing php code in browser, and then run it, and view result..
I found this handy project (Run-PHP-Code) to run PHP in browser directly, but I can't use models of my laravel project in PHP code..
How can I include laravel 's environment, so that I can for example:
$tag= new Tag;
where Tag is a model in laravel project, that would result into:
Fatal error: Class 'Tag' not found in D:\xampp\htdocs\widgetsRepository\app\controllers\Run-PHP-Code-master\index.php(49) : eval()'d code on line 3
Any idea? this would be very useful!
EDIT
I tried Brian suggestion at his answer, but I got this error now:
Call to a member function connection() on null
at vendor\laravel\framework\src\Illuminate\Database\Eloquent\Model.php
public static function resolveConnection($connection = null)
{
return static::$resolver->connection($connection);
}
so, I think I only need to get database sorted, then I can do experiments easily..
I've never tried to run code from a laravel project directly, I just copy and paste parts of the code into Run PHP Code.
That being said, it should be possible to run the code using the method taken from this StackOverflow question:
The Composer autoload script, to autoload all of your classes:
require __DIR__.'/../bootstrap/autoload.php';
And if you need things from the IoC container, you'll:
$app = require_once __DIR__.'/../bootstrap/start.php';
Then you will be able to do things like:
$post = Post::find(1);

Categories