Dynamically Register Commands in Laravel - laravel

I am able to register Events programmatically Illuminate\Support\Facades\Event and it's listener method. I would like to register command dynamically a similar way. Is there a way to do it in Laravel? Or what is the best way of doing in Laravel except for registering it inside app/Console/Kernel.php ?
Update
I am able to register a single class via the following code.
use Illuminate\Console\Application as Artisan;
if (app()->runningInConsole()) {
Artisan::starting(function ($artisan) use ($commandClass) {
$artisan->resolveCommands($commandClass);
});
}

If you look into your app/Console/Kernel.php you should see a statement like this:
$this->load(__DIR__.'/Commands');
This means that all command classes saved in app/Console/Commands/ will be automatically loaded and registered. Furthermore, if you create a command using artisan, Ex: php artisan make:command MyCommand, the class will be stored in app/Console/Commands/MyCommand.php.

While method provided by Pablo could be a better option for a single directory but if you have commands spread across different namespaces and directories one may end up adding multiple entries in app/Console/Kernel.php
In my use case the $commandClass is pulled from multiple xml files spread across multiple composer packages, therefore, I had to use this approach:
use Illuminate\Console\Application as Artisan;
// fetch command classes from different sources and register it here.
if (app()->runningInConsole()) {
Artisan::starting(function ($artisan) use ($commandClass) {
$artisan->resolveCommands($commandClass);
});
}

Related

Generate routes from controllers' (resources) functions

It has been a while I began to think if it's possible to create functions (resources) in Laravel Controller, and then use some kind of command to generate Routes automatically.
For example, with -r command we generate basic controller resources. Is there any way to generate routes automatically even with external libraries to look in the route/web file like this;
Route::get('/index', 'ProductController#index')->name('product.index');
Route::get('/edit', 'ProductController#edit')->name('product.edit');
Route::get('/create', 'ProductController#create')->name('product.create');
Route::get('/show', 'ProductController#show')->name('product.show');
Route::get('/store', 'ProductController#store')->name('product.store');
Route::get('/update', 'ProductController#update')->name('product.update');
Route::get('/destroy', 'ProductController#destroy')->name('product.destroy');
Thank you.

Two models, two fields, return preferred if present

Been struggling with how to do this the most optimized way possible...
I have two models: Catalog and Application.
Catalog has a field called name.
Application has a field called name.
Both have a relationship with each other.
I am struggling to find a way to create a function i could use across my Laravel application which i would pass application.id to it and it would return a $app->name value based on the following logic:
if $application->name exists, use this value as the $app->name for the $application object
otherwise, get the $catalog->name value and use it as the $app->name
Note that I would like to create a component #application() where i can simply pass the $application->id and build the display logic (theming/styling) into it.
Since i display this $app->name in many places, i would like to make it as lightweight as possible to avoid unnecessary queries.
I hope this makes sense! There are probably so many ways to go with it, i am lost at figuring out the way way to do this :(
I'm not completely sure to understand your model/DB design, but you could use a custom Helper to use that function through the whole app.
For that, you can create a simple PHP class Helper.php file in app/Http/Helpers folder or whatever location you want. Something like:
<?php
use App\Catalog;
use App\Application;
if (! function_exists('getAppName')) {
function getAppName($id){
// Do your logic here to return the name
$catalog = Catalog::find($id);
return $catalog->name;
}
}
?>
Then in any controller or view, you just do
getAppName($application->id)
Do no forget to add your helpers file to the composer autoload. So in composer.json in Laravel's root folder, add the helper path to the autoload array:
"files": [
"app/Http/Helpers/helpers.php"
],
Last but not least, run the following command:
composer dump-autoload
Please note that function logic is just for sample purposes since I don't know your model structure.
In my opinion, I care about the database cost.
Use ternary expression will be elegant. But it took two times IO costs from database if application name is empty.
$app_name = Application::find($id)->name;
$app_name = empty($app_name) ? Catalog::where('application_id', $id)->first()->name;
And this will more complicated, but the catalog_query only execute when application.name is empty, it execute in database and the result is taken out only once;
And Database will only find the name from one table or two table.
Something like this:
$catalog_query = Catalog::where('catalogs.application_id', $id)->select('catalogs.name')->groupBy('catalogs.name');
// if catalogs and applications relationship is 1:1, use ->limit(1) or remove groupBy('name') is better.
Application::where("applications.id", $id)
->selectRaw("IF(application.name IS NULL OR application.name = '', (" . $catalog_query->toSql() ."), applications.name ) AS app_name")
->mergeBindings($catalog_query->getQuery())
->first()
->app_name;
Hope this will help you.

Laravel call method on any artisan command

Is it possible to set a method that changes a value in my database automatically when I run a php artisan command? What I'm trying to accomplish is change the value of the first row in my "domains" table to suit the url from my .env file automatically whenever I push codes to my live/staging environment. Are there any ways to do this automatically without me manually going into my DB and changing it.
You could setup a Listener for the native event CommandFinished and check if the command is the config:cache.
Event::listen('Illuminate\Console\Events\CommandFinished', function ($event) {
if ($event->command == 'config:cache') {
// Change domains table data using Eloquent or Query Builder
}
});
To learn more about Events, see: https://laravel.com/docs/5.7/events#generating-events-and-listeners

Best Practices for Laravel 4 Helpers and Basic Functions?

I'm trying to understand the best place to put a global function in Laravel 4. For example, date formatting. I don't think making a facade is worth it as facades are too modular. I've read articles about creating a library folder and storing classes there but that also seems like a lot for a simple function. Shouldn't a 'tool' like this be available in Blade templates?
What are the best practices for something like this and how do I make it available to Blade templates?
The ugly, lazy and awful way: At the end of bootstrap/start.php , add an include('tools.php') and place your function in that new file.
The clean way: Create a library. That way it'll be autoloaded ONLY when you actually use it.
Create a libraries folder inside your app folder
Create your library file, create a class in it, and add static functions to it
Option 1: Edit start/global.php to add app_path().'/libraries' to the ClassLoader::addDirectories( array.
Option 2: Edit composer.json to add "app/libraries" to the autoload array. Run composer dump-autoload
Call your class and static functions from your views.
About your options, quoted from the global.php file
In addition to using Composer, you may use the Laravel class loader to
load your controllers and models. This is useful for keeping all of
your classes in the "global" namespace without Composer updating.
You can combine both options, where the Laravel class loader will automatically search for classes in the registered directories (Option 1, easier) and Composer will keep record of all the classes but only after you update it (Option 2, might improve performance).
My way of doing this is to create a new folder in the /app directory in the root of your Laravel 4 project. Then add this folder to the first array of the /app/start/global.php file like so:
<?php
ClassLoader::addDirectories(array(
app_path().'/commands',
app_path().'/controllers',
app_path().'/models',
app_path().'/database/seeds',
app_path().'/classes', // This line is the one I've added.
));
As long as the folder structure within the new /app/classes folder follows your namespacing convention. Laravel 4 will autoload all the classes/files within this folder. This way there's no need to dig into any composer files or run composer command.
Not sure if this is best practice but it certainly works.
If you created a simple file called /app/classes/Helpers/Helper.php such as this:
<?php namespace Helpers;
class Helper {
public static function helloWorld()
{
return 'Hello World';
}
}
All you would need to do is call Helpers\Helper::helloWorld();
You could also alias this helper class in your /app/config/app.php file. Just add something like this to the end of the aliases array:
'Helper' => 'Helpers\Helper'
Laravel's helpers.php method is to add it to your "files" in composer.json (https://github.com/laravel/framework/blob/master/composer.json):
"autoload": {
"classmap": [
...
],
"files": [
"app/libraries/helpers.php"
],
},
What I do is to create small classes (a few methods per class, one line per method, everything extended from something and DRY, that's my goal),
class ExtendedCarbon extends Carbon\Carbon {
public function formatDDMMAAAA($date)
{
/// format and return
}
}
save them to them in app/libraries and add to composer.json:
"autoload": {
"classmap": [
...
"app/libraries",
...
],
},
Execute
composer dump
And then just use them wherever you need
$formatted = (new ExtendedCarbon)->formatDDMMAAAA($date);
Watch this video about refactoring: http://www.youtube.com/watch?v=DC-pQPq0acs
By the way, I'm kind of sure it was just an example, but you might not need a helper to format dates, since all dates in Laravel are instances of Carbon (https://github.com/briannesbitt/Carbon) and it has loads of methods to format date and time.
You can also use View::share() together with closures to achieve this - I just posted about this: http://www.develophp.org/2014/07/laravel-4-blade-helper-functions/
Added benefit: You don't need to create an extra class and also keep the global namespace clean.

Debugging Grocery_CRUD Callbacks

I have seen many people referring to the usage of call_user_func() to debug the problems in a Grocery_CRUD callback, but unfortunately no one has come off with a complete example to actually how to use it like where to to place a call to the test function [just_a_test()] in the controller an example of what I am trying to discover is here.
I am unable to understand where do we call this
just_a_test(),
how are we able to pass on the desired parameters using call_user_func(array($this,'insert_coupon_codes')); when there are no para's being passed to the just_a_test()?
how come the insert_coupon_codes will be able to get the desired para's?
Grocery CRUD add the parameters automatically from the library. You are not able (till now at version 1.1.8) to add more parameters at your callback.
Update: At the latest version of Grocery CRUD now you CAN pass as many parameters as you need. This is a functionality that PHP is offering from version PHP 5.4 or later. More specifically with the use keyword. More specifically if you have the callback callback_after_insert:
usually you would use it like this:
$crud->callback_after_insert(function ($post_array,$primary_key) {
// Your code here
});
From PHP 5.4 version and later you can add more parameters with the use so for example you could have:
$my_variable = 'test';
$another_variable = 'hello';
$crud->callback_after_insert(function ($post_array,$primary_key) use ($my_variable, $another_variable) {
// Now you can use the variables $my_variable and $another_variable at your callback
});

Resources