Laravel. Routes do not match - php

At first it seems that the same routes. But in first route not working middleware that I ordered in the constructor.
How to fix that?
Route::get('/cars.get', function() {
return App::make('App\Http\Controllers\CarsController')->{'get'}();
});
Route::get('/cars.get', 'CarsController#get');
sorry for my English =)

Edit
I was wrong about callAction() it does nothing else than call the method.
Unfortunately there doesn't seem to be a simple API to call middleware manually. A solution to this would just be to define the middleware on the route:
Route::get('/cars.get', ['middleware' => 'auth', function() {
return App::make('App\Http\Controllers\CarsController')->{'get'}();
}]);
original answer:
By directly calling the get() method you skip middleware defined in the controller. You should use callAction() instead:
return App::make('App\Http\Controllers\CarsController')->callAction('get');
Also note that you can use app() as a shortcut for App::make():
return app('App\Http\Controllers\CarsController')->callAction('get');

Related

Declare same route twice but expect different behaviour according to a middleware

I started creating a REST API using the lumen framework and wanted to set up a particular behaviour for my GET /user route. Behaviour is the following:
If the request come from an authenticated user (using auth middleware), the method getAllFields from UserController is called and return all the data from the user
If it's not the case, the method get from UserController is called and return some of the data from the user
It seems logic to me to just write it like that in my web.php using a simple middleware:
<?php
$router->group(['middleware' => 'auth'], function () use ($router) {
$router->get('/user/{id}', [
'uses' => 'UserController#getAllFields'
]);
});
$router->get('/user/{id}', [
'uses' => 'UserController#get'
]);
But for some reason, even if the middleware is correct, I always get the response of the second route declaration (that call get()). I precise that if I remove the second route declaration, the one in the middleware work as expected.
Have someone an idea how I can achieve something similar that work?
Router will check if your request matches to any declared route. Middleware will run AFTER that match, so You cannot just return to router and try to find another match.
To fallow Laravel and Routes pattern - You should have single route that will point to method inside controller. Then inside that You can check if user is logged or not and execute getAllFields() from that controller. It will be not much to rewrite since You are currently using UserController in both routes anyway.
web.php
$router->get('/user/{id}', 'UserController#get');
UserController.php
public function get()
{
return auth()->check() ? YourMethodForLogged() : YourMethodForNotLogged();
}
Or if there is not much logic You can keep this in single method.
Also it is good idea to fallow Laravels REST standards (so use show instead of get, "users" instead of "user" etc - read more https://laravel.com/docs/7.x/controllers)
web.php
$router->get('/users/{user}', 'UserController#show');
UserController.php
public function show(User $user)
{
if (auth()->check()) {
//
} else {
//
}
}
To summary - for your needs use Auth inside controller instead of middleware.
To check if user is logged You can use Facade Auth::check() or helper auth()->check(), or opposite Auth::guest() or auth()->guest().
If you are actually using Lumen instead of full Laravel then there is not auth helper by default (You can make own or use package like lumen-helpers) or just keep it simple and use just Facades instead (if You have then enabled in Lumen).
Read more https://laravel.com/docs/7.x/authentication and https://lumen.laravel.com/docs/7.x/authentication
This pattern is against the idea of Laravel's routing. Each route should be defined once.
You can define your route without auth middleware enabled and then define your logic in the controller.

Laravel: Not picking up __invoke method?

Trying to use invokable controllers, but it seems to fail to find the __invoke method?
Invalid route action: [App\Http\Controllers\App\Http\Controllers\MainController].
It seems to be returning true on:
if (! method_exists($action, '__invoke')) {
throw new UnexpectedValueException("Invalid route action: [{$action}].");
}
Routes:
<?php
Route::get('/', \App\Http\Controllers\MainController::class);
MainController:
<?php
namespace App\Http\Controllers;
class MainController extends Controller
{
public function __invoke()
{
dd('main');
}
}
Laravel by default assumes that your controllers will be located at App\Http\Controllers\. So when you're adding the full path to your controller, Laravel will check it there, at App\Http\Controllers\App\Http\Controllers\MainController.
To solve it simply remove the namespace when you're registering the route, and register it like this:
Route::get('/', MainController::class);
Alternatively, you can stop this behavior by removing ->namespace($this->namespace) from mapWebRoutes() method on RouteServiceProvider class, which is located at App\Providers folder. Then you can register your routes like this:
Route::get('/', \App\Http\Controllers\MainController::class);
Alternatively, you can use:
use App\Http\Controllers\MainController;
Route::get('/', [MainController::class, '__invoke']);
In this case, the namespace provided in RouteServiceProvider won't be taken into account.
The advantage of this is that now your IDE will be able to reference the class usage and you can navigate by clicking on it.
The best answer that works for everyone is laravel documentation.
just use this at the top of your route(web.php) if (websiteController is the name of your controller)
use App\Http\Controllers\WebsiteController;
and define your route like this for your index page
Route::get('/', [WebsiteController::class, 'index']);
take note of the
[ ]
You have to create the crontoller with argument "--invokable"
php artisan make:controller YourController --invokable
Always Declare/Use in Top
use App\Http\Controllers\backend\DashboardController;
Then Use this way
Route::get('/dashboard', [DashboardController::class, 'dashboard'])->name('dashboard');
If have Auth and Use Group
Route::middleware([
'auth:sanctum',
config('jetstream.auth_session'),
'verified'
])->group(function () {
Route::get('/dashboard', [DashboardController::class, 'dashboard'])->name('dashboard');
})
Change your route to:
Route::get('/', "MainController");
In my case I forget to set #action, so change your code from:
Route::get('admin/orders', 'Admin\OrderController')->name('admin.orders');
to:
Route::get('admin/orders', 'Admin\OrderController#index')->name('admin.orders');
you have mentioned get link, but you have not declared which method it should call.
Route::get('/', \App\Http\Controllers\MainController::class);// if you are importing lass like this you have to use resource instead of get.
you can solve this issue by two ways,
first way,
Route::get('/', '\App\Http\Controllers\MainController#index'); // you have to mention your method which you have mentioned in controller
another way is,
Route::resource('/', \App\Http\Controllers\MainController::class);
In, 2nd method laravel will automatically find which request and where should redirect.2nd option is prefered if you are using multiple method for the same route.
Route::resource('/', \App\Http\Controllers\MainController::class);
Use method 'resource'

Laravel routing strange behavior

I have a single domain/subdomain project. In order to see the event by slug, I made this route:
Route::prefix('events')->namespace('Content\Controller')->group(function () {
Route::get('/', 'EventController#getIndex')->name('event.index');
Route::get('{slug}', 'EventController#getView')->name('event.show');
Route::get('{slug}/edit', 'EventController#getEdit')->name('event.edit');
Route::post('load-more-ajax/{region?}', 'EventController#postLoadMoreAjax');
Route::any('sorted-ajax/{region?}', 'EventController#anySortedAjax');
Route::get('category/{category_slug}/{subcategory_slug?}', 'EventController#getCategory');
});
After my page didn't load correctly, I did a dump in the controller:
public function getView($slug)
{
return $slug;
}
To get to the route I am using this URL: https://example.com/events/slug-example.
The problem is that the route is being hit as I see the response when I change it, but I am not getting the slug, instead I am getting Region object back.
If I do this:
public function getView($region, $slug)
{
return $slug;
}
Then I get the slug back. But I have no idea how is this possible, and how could I do it (I came as another dev on the existing project).
I tried commenting out all the middleware and it is still the same. How can I even make something fill the method if I didn't explicitly say it?
EDIT
I noticed there is binding going on in routes file:
Route::bind('region', function ($value) {
...
});
Now if I dd($value) I get the variable back. How is this value filled? From where could it be forwarded?
Looking quickly it should work, but maybe you was verifying other url.
Make sure you put:
Route::get('{slug}', 'EventController#getView')->name('event.show');
Route::get('{slug}/edit', 'EventController#getEdit')->name('event.edit');
routes at the end of routes you showed.
EDIT
If you think that's not the case and you don't have your routes cached you should run:
php artisan route:list
to verify your routes.
EDIT2
After explaining by OPs in comment, domain used for accessing site is:
{region}.example.com
So having $region in controller as 1st parameter is correct behaviour because of route model binding and other route parameters will be 2nd, 3rd and so on.
Instead of
Route::prefix('events')->namespace('Content\Controller')->group(function () {
Route::get('/', 'EventController#getIndex')->name('event.index');
Route::get('{slug}', 'EventController#getView')->name('event.show');
Route::get('{slug}/edit', 'EventController#getEdit')->name('event.edit');
Route::post('load-more-ajax/{region?}', 'EventController#postLoadMoreAjax');
Route::any('sorted-ajax/{region?}', 'EventController#anySortedAjax');
Route::get('category/{category_slug}/{subcategory_slug?}', 'EventController#getCategory');
});
try
Route::prefix('events')->namespace('Content\Controller')->group(function () {
Route::get('/', 'EventController#getIndex')->name('event.index');
Route::post('load-more-ajax/{region?}', 'EventController#postLoadMoreAjax');
Route::any('sorted-ajax/{region?}', 'EventController#anySortedAjax');
Route::get('category/{category_slug}/{subcategory_slug?}', 'EventController#getCategory');
Route::get('{slug}', 'EventController#getView')->name('event.show');
Route::get('{slug}/edit', 'EventController#getEdit')->name('event.edit');
});

How does Routing work in PHP laravel?

I have just started playing with Laravel framework and I have seen this :
Route::get('foo', function () {
return 'Hello World';
});
Can some one please explain what is this ? I mean over all I know what is get . but why do we put 'foo' and then the closure we put ?
Also where am I really getting the information from ?
First we declare the Facade of the Route, think like a shortcut to use the Route class.
After that, we choose the method of the route, it could be:
Route::get($uri, $callback); //get
Route::post($uri, $callback); //post
Route::put($uri, $callback); //put
Route::patch($uri, $callback); //patch
Route::delete($uri, $callback); //delete
Now you choose the url of the page, for example:
If you digit in the browser:
www.foobar.com/user/profile
Laravel will search for the route with the user/profile parameter, like that:
Route::get('user/profile', function () {
return 'Hello World';
});
You can pass variables too,
Route::get('user/{id}', function () {
return 'Hello World';
});
After that, you choose the callback method, in other words, what is gonna happen when the laravel enter in the route.
In your example, you have the function example, just returning a simple "hello world".
The best pratice here is to create a controller
php artisan make:controller FoobarController --resource
And referece to any method of your controller
Route::get('user/profile', 'FoobarController#index');
Now, when the laravel find the route, it's going to redirect to the index method of the Foobar controller, and there, you define your logic
public function index() {
return view('welcome');
}
Firsty, read the documentation, it's super easy, even for the begginers.
Step by step:
get is the HTTP method you use on this particular route. The other most often used is POST, but there are more of them.
foo is the route, in that case will be: www.example.com\foo. You can put any name as you want and need.
As a second parameter to a Route facade you put closure/name of the controller/view you want to handle endpoint, e.g.
Route::get('foo', 'SomeController#method');
Route::get('foo', function(){
return view('some.view');
};
There are lot more options in routing and they are not difficult to understand, just have a look on documentation or some video tutorials.

Controller Method not found in nesting laravel 4

I'm new in laravel and I got an error and don't really know how to fix it.
I got an error "Controller method not found" when i'm asking for this route : /projet/6/note
My routes.php
Route::controller('projet.note', 'NoteController');
Route::resource('/eleves', 'StudentController');
Route::controller('/auth', 'AuthController');
Route::resource('/user', 'UserController');
Route::resource('/projet', 'ProjectController');
Route::post('/eleves/search', 'StudentController#postSearch');
Route::resource('/classe', 'ClasseController');
Route::controller('/', 'HomeController');
I tried to type php artisan routes to see if the routes was working, and she's not.
I tried then to change controller into resource in the line about NoteController, the routes was there but when i go on the link, same error.
Then i guess i can't do 'projet/note' without that my NoteController is a resource?
It's a problem because i need to nest NoteController to ProjetController.
My only action in NoteController
public function getIndex($id)
{
return View::make('note.noter')
->with('project', Project::find($id))
;
}
Thanks
I hope I understood your question right. This is the best solution I could come up with:
Route::any('projet/{id}/note/{action?}', function($id, $action = 'index'){
$controller = App::make('NoteController');
$action = strtolower($_SERVER['REQUEST_METHOD']).studly_case($action);
if(method_exists($controller, $action)){
return $controller->callAction($action, [$id]);
}
});
This basically does some similar things as Route::controller. First we create a controller instance, then build the action name out of the request method and the second parameter in the route and in the end, call the action (if it exists).

Categories