Laravel 5.4 - How to override route defined in a package? - php

I have created a package in Laravel 5.4 that sets up a basic backoffice. This package contains several routes that are using controllers from within the package. What I want to be able to do is to override the package defined routes in my application in order to plug custom controllers. For example, if I have a route
Route::get('login', [
'as' => 'admin.login',
'uses' => 'Auth\LoginController#showLoginForm'
]);
defined in my package that will use the Vendor\Package\Controllers\Auth\LoginController I want to defined a route for my application that will override that one and use the App\Controllers\Auth\LoginController.
Doing the obvious approach of defining the route in app routes files fails for the app routes files are run before the package routes file, so the package definition will prevail.
Is there any way to accomplish something of this kind?
I also tried to get the particular route in the RouteServiceProvider and use the method uses to set the controller that should be used to resolve it, like this
public function boot()
{
parent::boot();
Route::get('admin.login')->uses('App\Http\Controllers\Admin\Auth\LoginController#showLoginForm');
}
but this also fails to accomplish what is pretended.
Any clues on what I am doing wrong?

In config/app.php in the providers array put the service provider of the package before App\Providers\RouteServiceProvider::class, and then in your web.php routes you'll be able to override it with your custom route.
EDIT
For Laravel package auto discovery you can disable the package being auto discovered in your composer.json like this:
"extra": {
"laravel": {
"dont-discover": [
"barryvdh/laravel-debugbar"
]
}
},
In this example the barryvdh/laravel-debugbar package won't be autodiscovered, which means you would have to manually include its service provider in the config array and then you'll be able to rearrange your custom provider in the desired order.

Another option -- which doesn't have to muck with the order of service providers -- is to add a binding for the controller.
So e.g. in AppServiceProvider,
$this->app->bind(
\Vendor\Package\Controllers\Auth\LoginController::class,
App\Controllers\Auth\LoginController::class
);
You'll have to match controller method names, but you're doing that already in your example.
(Caveat on this answer: I haven't tested it in Laravel 5.4, but I just did this in Laravel 6.0 using the $bindings property which was added in Laravel 5.6. That said, this should be correct 5.4 syntax for doing the same thing).
Edit: For Laravel 6+ you can instead add the binding to the bindings array in AppServiceProvider:
public $bindings = [
\Vendor\Package\Controllers\Auth\LoginController::class =>
App\Controllers\Auth\LoginController::class,
// other bindings
]

Related

Laravel Spatie Laravel-Navigation Route Error

I'm trying to make the Spatie Laravel-Navitation plugins to work on my project in Laravel 9.1.0
Spatie Laravel Navigation
So far I did :
Install the plugin with composer
add the plugin to the config/app.php provider
App\Providers\NavigationProvider::class,
Add the alias in the config/app.php aliases
'Navigation' => Spatie\Navigation\NavigationServiceProvider::class,
From what I understand I create a new provider
php artisan make:provider NavigationProvider
Inside the provider I add to the top
use Spatie\Navigation\Navigation;
Inside the handle function I add this
app(Navigation::class)
->add('dashboard', route('dashboard'));
I have the following error since:
Route [dashboard] not defined.
In my routes/web.php I have the following route.
Route::get('/', function () {
return view('pages.dashboard');
})->name('dashboard');
Any Idea what I miss.
Any tips also on how I will use this in the blade after making the route portion work.
Thank you for your help.
I maybe found the issue but I'm not sure it's the most elegant way to do this.
In my controller boot function I did this :
$this->app->booted(function () {
app(Navigation::class)
->add('dashboard', route('dashboard'));
});
view()->composer('*',function($view) {
$view->with('navigation', app(Navigation::class)->tree() );
$view->with('breadcrumbs', app(Navigation::class)->breadcrumbs() );
});

How to remove default index action on controller from laravel 5.5

I am using Laravel 5.5 version. I defined my routes in the routes.php file. like this:-
$router->group(['middleware' => 'auth'], function($router) {
$router->resource('/route-name', 'myController#myMethodName');
});
But when I run my application laravel gives error:-
Method [myMethodName#index] does not exist on [App\Http\Controllers\myController].
It is by default put index action after my defined action in the routes.
It is working fine in the laravel 5.3 version. Please solve my problem..
Try this as #devk told in comment:
$router->get('/route-name', 'myController#myMethodName');
By Default resource Request create CRUD requests in routes. For the following methods in Controller.
Index(GET)
Create(GET)
Store(POST)
Show(GET)
edit(GET)
Update(PUT/PATCH)
Delete(DELETE)
You can't pass method name in resource route.
If you want to override any of them. you have to write new one route below the resource Route. Like
Route::get('url','Controller#newMethod');
And Change the method name in Controller with newMethod
For more detail check laravel documents

Laravel named routes not working

Recently I switched to Laravel 5.3.
I have the following route
Route::get('/activate/token', 'AccountActivationController#activate')->name('auth.activate');
But, when I use
dd(route('auth.activate'));
I get the following error:
InvalidArgumentException in UrlGenerator.php line 314: Route [auth.activate] not defined.
It works perfectly fine with
Route::get('/activate/token', [
'as' => 'auth.activate',
'uses' => 'AccountActivationController#activate',
]);
Is this new in Laravel 5.3?? I am fairly new to Laravel itself.
Thank You.
For anyone that comes across this in the future, it is because you aren't refreshing the name lookup on the router.
Laravel 5.2 added the fluent method name($name) as a shortcut replacement for ['as' => $name], but the name($name) method requires $router->getRoutes()->refreshNameLookups(); to be called at some point after your routes are registered in order to actually complete that mapping internally.
In it's current form, the RoutingServiceProvider implemented in the example laravel/laravel package handles this for you behind the scenes, but if you're loading routes in any sort of custom way, you'll need to trigger that refresh yourself at an appropriate time.
See https://github.com/laravel/framework/blob/8.x/src/Illuminate/Foundation/Support/Providers/RouteServiceProvider.php#L47-L50 for how it's handled in Laravel 8.x
Missing a tick mark
Try
dd(route('auth.activate'));
instead.

Laravel 5's route helper doesn't work on fresh install

I am following a tutorial sayings that Laravel has a helper that permits to write the routes like that :
<?php
get('/', function () {
return view('welcome');
});
Instead of :
<?php
Route::get('/', function () {
return view('welcome');
});
(The "Route::" prefix is missing in the first one).
Since what i've looked the documentation (where I've found nothing really related but the providers involved), I correctly have in my providers :
'providers' => [
/*
* Laravel Framework Service Providers...
*/
(...)
Illuminate\Foundation\Providers\FoundationServiceProvider::class,
(...)
/*
* Application Service Providers...
*/
(...)
App\Providers\RouteServiceProvider::class,
(...)
],
And the tutorial says that it has to work in a fresh install.
The router helper functions were removed in December. You can see the changes here:
https://github.com/laravel/framework/commit/62cbae78ba2d40944892c5a16f2d2463087bce23
In the upgrade guide, you can see what is deprecated and removed.
The get, post, and other route helper functions have been removed. You may use the Route facade instead.
Source: https://laravel.com/docs/5.2/upgrade

Laravel: Overriding a Bundle's Service Providers

I have a project that uses the Sentinel bundle for Laravel.
A while ago, I asked a question about extending a model provided in the bundle. The answer I accepted worked, but it required editing the bundle's code in the vendor folder.
Since then, I've run a composer update command and the change I applied was overwritten (no surprise there).
I know a bit more about how laravel works now so I was able to trace back the end point where the bundle's services are referenced by my app. In my config/app.php file I have the service provider reference:
'Sentinel\SentinelServiceProvider',
The SentinelServiceProvider service has a register method that registers the RepoServiceProvider which is the class I need to override.
My plan is to create two new files: ExtendedSentinelServiceProvider.php and ExtendedRepoServiceProvider.php.
In the ExtendedRepoServiceProvider.php file, I could replace the class being used for the User Repository binding with my custom User class:
// Bind the User Repository
$app->bind('Sentinel\Repo\User\UserInterface', function($app)
{
return new ExtendedSentryUser( // This is my custom model that I want the ExtendedRepoServiceProvider to use
$app['sentry']
);
});
In the ExtendedSentinelServiceProvider.php file, I would replace the existing RepoServiceProvider class reference with my newly modified ExtendedRepoServiceProvider class:
public function register()
{
$loader = \Illuminate\Foundation\AliasLoader::getInstance();
$loader->alias('Sentry', 'Cartalyst\Sentry\Facades\Laravel\Sentry');
$repoProvider = new ExtendedRepoServiceProvider($this->app); // This would be my new ExtendedRepoServiceProvider class
$repoProvider->register();
$formServiceProvider = new FormServiceProvider($this->app);
$formServiceProvider->register();
}
And then I would replace the service provider reference in my config/app.php file with the new ExtendedSentinelServiceProvider class:
'providers' => array(
...
'Sentinel\ExtendedSentinelServiceProvider',
...
),
My question is, would this make sense as a way of being able to store my modifications in my app directory rather than modifying the vendor code? Is this going to be a problem when it comes to name spacing? Is there a better way of doing this??
Any help would be greatly appreciated.
You shouldn't run into name spacing issues. However another option - especially if you're adding a feature that might be generally useful for others - would be to fork the project on github and then include a reference to your git project in the "repositories" attribute of your composer.json. For example you could add:
"repositories": [
{
"type": "git",
"url": "git#github.com:{your-user}/Sentinel.git"
}
],
And then composer would look to your fork when ever it does an install/update.

Categories