Generate routes from controllers' (resources) functions - laravel

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.

Related

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.

Dynamically Register Commands in 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);
});
}

laravel routing based on convention

I'm trying to setup a simple routing system based on convention.
My app will have this structure
Http
--Controllers
----Admin
------User.php
----Books
------Add.php
----etc...
I want to be able to add new Folders and controllers without adding routes manually to the web.php file.
For example I want the route to respond to /Admin/User URL with User.php controller.
I'm trying something like this, but I don't understand how to write the internal router...
Route::any('/{module}/{action?}', function($module, $action = 'index') {
Route::get('*',$module.'\'.$action.'#index' );
});
It seems that Rout:get('*'... never matches.
PS the controller namespace is correct and I reloaded with composer.
The controller works if called harcoded.
I tried also to escape '\'
$r=$module.'\\'.$action.'\\'.$action.'Ctl#index';
Route::get('/',$r );
But no result. The route is intercepted but nothing i served
It seems I came up with this
Route::get('/{module}/{action}', function($module,$action) {
return App::make('\App\Http\Controllers\\'
.$module.'\\'.$action)->callAction('index', []);
});
Any other better way?

Subfolder routing in laravel 5

I am having trouble routing with controllers in subfolders. I have tried the solution proposed in Laravel Controller Subfolder routing, but I can't get it to work.
Folder structure
HTTP
Controllers
Admin
AdminControllers
User
UserControllers
BaseController
Admincontrollers are defined in the 'App\HTTP\Controllers\Admin' namespace
Routes file
Route::group(['middleware'=> 'admin','prefix' => 'admin'], function() {
Route::get('home', 'AdminHomeController#index');
Route::get('home', 'Admin\AdminHomeController#index');
Route::resource('events', 'AdminEventController');
Route::resource('events', 'Admin\AdminEventController');
Route::get('myevents', 'AdminEventController#myevents');
Route::get('myevents', 'Admin\AdminEventController#myevents');
Route::resource('groups', 'AdminGroupController');
Route::resource('users', 'AdminUserController');
});
This does seem weird, but it is the only way to keep it working right now.
If I delete
Route::get('myevents', 'Admin\AdminEventController#myevents');
//errormessage Class App\Http\Controllers\AdminEventController does not exist
If I delete
Route::get('myevents', 'AdminEventController#myevents');
//errormessage Action App\Http\Controllers\AdminEventController#myevents not defined.
If I put the controllers in the controller namespace (not the admin one)
I still get
//errormessage Class App\Http\Controllers\AdminEventController does not exist
When the only route added is
Route::resource('events', 'AdminEventController');
The problem were the calls in the views:
changing
<td>{!!Html::linkAction('AdminEventController#show', $event->name, $event->slug)!!}</td>
to
<td>{!!Html::linkAction('Admin\AdminEventController#show', $event->name, $event->slug)!!}</td>
fixed it.
The Laravel 5 solution in Laravel Controller Subfolder routing is correct. The problem was not in the routes file or controllers.
Yes If your application gets bigger like this, it makes sense to structure Controllers with sub-folders. But it takes a little more effort than just moving the files here and there. Let me explain the structure.
For example, we want to have a sub-folder app/Http/Controllers/Admin and then inside of it we have our AdminController.php, that’s fine. What we need to do inside of the file itself:
Correct namespace – specify the inner folder:
namespace App\Http\Controllers\Admin;
Use Controller – from your inner-namespace Laravel won’t “understand” extends Controller, so you need to add this:
use App\Http\Controllers\Controller;
Routes – specify full path
This wouldn’t work anymore:
Route::get('admin', 'AdminController#index');
This is the correct way:
Route::get('admin', 'Admin\AdminController#index');
And that’s it – now you can use your controller from sub-folder.
Reference (Tested):
http://laraveldaily.com/moving-controllers-to-sub-folders-in-a-correct-way/
By: Povilas Korop

makes a script run for every call to a package Laravel4

I am developing an application with Laravel 4 framework, I developed an admin package for my application,
Question:
how can I make a piece of code executable for every single call to one of the routes of this specific package? where should I put this piece of code?
Use a route filter.
Route::filter('admin', function () {
// do stuff
});
Or if you want this to be revolved out of the IoC container:
Route::filter('admin', 'Vendor\Package\Filters\SomeFilter');
Then bind it in your routes file:
Route::get("/admin", ["before" => "admin", "uses" => "SomeController#method"]);
Though you should consider using an event handler instead of this, as it seems like that's actually what you want, rather than "run this code when this route is hit".
Normally you should be saying "I want this code to be ran when this happens" when dealing with a package, which would be an event.
Define your filter like;
Route::filter('filter', function () {
// do stuff
});
or
Route::filter('filter', 'Vendor\Package\Filters\SomeFilter');
And attach to the group, and define your route within it like so;
Route::group(array('before' => 'filter'), function(){
//Define your routes here
});

Resources