Executing seed command dynamically through controller in Laravel - php

I'm trying to build a small application on Laravel with modular approach, I am having a controller method which seeds the database as per the module/plugin name:
I have something like this:
Artisan::call('db:seed --class=Nitseditor\\Plugins\\'.$pluginName.'\\Databases\\seeds\\InstallSeeder');
Whenever I am calling this I am getting this error in my console.
Class NitseditorPluginsConfidenceDatabasesseedsInstallSeeder does not exist
I don't know why it remove \ and concatenate the strings.
How can I achieve this?

You can do:
$fullClassName = "Nitseditor\\Plugins\\${pluginName}\\Databases\\seeds\\InstallSeeder";
Artisan::call("db:seed", ['--class' => $class]);

in my case when i have some module in subfolders
then want to run one of the Seeders directly without running other seeders
php artisan db:seed --class=WM\Common\Seeder\SmsStatusSeeder

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.

Laravel Task schedule with cron column in database

I have a "reportSchedule" model which contains the report name and a cron_request column such as */15 * * * *.
I want to be able to adjust the cron within the database and affect the times which the report is requested. For example, the following is working from directly within the console/Kernel.php:
ReportSchedule::all()->each(function(ReportSchedule $reportSchedule) use($schedule){
if(isset($reportSchedule->cron_request)){
$schedule->call(function() use ($reportSchedule) {
ReportRequestNow::dispatch($reportSchedule);
})->cron($reportSchedule->cron_request);
}
});
However, having the model called from directly within the kernel causes other issues. For example database migrations now do not work and errors are thrown when caching the routes or running route:list. In general, it does not seem to like it!
So my idea was either create a seeder job or put this into its own schedule, however neither work.
// Doesnt work - the every minute schuedle is called but ReportRequestNow is never reached.
$schedule->call(function() use($schedule){
ReportSchedule::all()->each(function(ReportSchedule $reportSchedule) use($schedule){
if(isset($reportSchedule->cron_request)){
$schedule->call(function() use ($reportSchedule) {
ReportRequestNow::dispatch($reportSchedule);
})->cron($reportSchedule->cron_request);
}
});
})->everyMinute();
// Also does not work
$schedule->job(new ReportScheduleSeeder(), 'high')->everyMinute();
Can anyone suggest a why this does not work or how to get it working?
However, having the model called from directly within the kernel
causes other issues. For example database migrations now do not work
and errors are thrown when caching the routes or running route:list.
In general, it does not seem to like it!
Seems that there's some syntax errors (maybe some classes aren't listed in use?)
Have you checked laravel and PHP logs? Most likely there will be some explanations.

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