I have a problem on the update treatment processed into my functional tests on Codeception : I systematically have a 404 error. Here are the details.
Everything is going well for every other simulated http requests but when codeception tries to execute the update method on a put HTTP request (POST request with a "_method" param having the value "PUT") is never executed by my controller, which lead codeception on the update url without the redirection that should happen after the treatment in this update method. I tried to redirect to my home page on top of my update method to test that fact and the redirection never happens.
For information, I use the Laravel5 module. Here is my functional.suite.yml file content :
class_name: FunctionalTester
modules:
enabled:
- Asserts
- \Helper\Functional
- MailCatcher
- Laravel5:
environment_file: .env.testing
config:
MailCatcher:
url: 'http://192.168.10.10'
port: '1080'
I tried to replace the "PUT" value of the "_method" param by "PATCH" to see if any change could be seen but the problem persists and the behaviour is still the same.
Codeception includes the Laravel5 app to test it. The only clue I have is that the testing environment has a problem to interpret the PUT or PATCH request. There is no problem for a simple POST request (creation doesn't cause any problem).
I precise that the HTML form is correct, the update happens correctly in my local environment and the http request contains correct params. Here is what I have when I execute it the with the --debug option :
[Uri] http://project/en/permissions/update
[Method] POST
[Parameters] {"_token":"RUx7DjU3b6GEjodnpwXvJJYJIcmQJGbabj23q0yK","_method":"PATCH","_id":"1","name_en":"Administrator","name_fr":"Administrateur","slug":"admin"}
[Page] http://project/en/permissions/update
[Response] 200
[Request Cookies] {"XSRF-TOKEN":"eyJpdiI6InZQV2NVcTRoZHVONXYzZzNLTnBWU1E9PSIsInZhbHVlIjoiWWhWa0kyUGxJNkJRTXIyaEhVcDdHR0tRcklHZStpVWdlTjlDdmRKVmEyVDFPWkxBVmhLc1lra05zeWh1ZWtKMENCc29lWFZTN2lSd3dIbjZyNEo5eWc9PSIsIm1hYyI6ImEzMDNmOWM5OGQzNzE4ZWI5MDg0MTI0ZmQwMTI1ZTk0OTM1OTY4NjA5ZTZjMGFhYTI0MTdlMzMzM2QyMWQ4MzUifQ==","laravel_session":"eyJpdiI6ImF4cVFYYVNUU3J0WUd2VzNRZlhSc3c9PSIsInZhbHVlIjoibDdPd3ZEZVZOdDJwRlBjMVZtc2dNM0I3WUw0REEzK25NVFVWT1FIRjEzR05tRGZLXC9SYUZkRmhEdXlyQVdybURHTWVQVUtucnBkZEwwaTN4NWF6XC9YQT09IiwibWFjIjoiMzliODY4ZWUwYmZjODI1OTVkMTBiYjA4ODY2OWNiODc3ZTI1NzAzZmJhMjg4OTY4Y2MzM2VkMjYyYTkwOTQ2MyJ9"}
[Response Headers] {"cache-control":["no-cache"],"Set-Cookie":[{},{}]}
As you can see, the process end on a 200 response and that is all.. I tested it with a few pages and the problem is the same everywhere.
I'm blocked on this problem for weeks now without finding any solution. If someone has a clue, I am listening !.
EDIT 1 : 26/01/2015
As it has been asked to me, here is my routes file.
As you can see, I use LaravelLocalization, this is a multilingual app.
I only show you the permissions routes but they are all managed this way.
Route::group([
'prefix' => LaravelLocalization::setLocale(),
'middleware' => [
'auth',
'localize',
'localeSessionRedirect',
'localizationRedirect',
]], function () {
// permissions
Route::get(LaravelLocalization::transRoute('routes.permissions.index'), ['as' => 'permissions.index', 'uses' => 'User\PermissionsController#index']);
Route::get(LaravelLocalization::transRoute('routes.permissions.create'), ['as' => 'permissions.create', 'uses' => 'User\PermissionsController#create']);
Route::post(LaravelLocalization::transRoute('routes.permissions.store'), ['as' => 'permissions.store', 'uses' => 'User\PermissionsController#store']);
Route::get(LaravelLocalization::transRoute('routes.permissions.edit'), ['as' => 'permissions.edit', 'uses' => 'User\PermissionsController#edit']);
Route::put(LaravelLocalization::transRoute('routes.permissions.update'), ['as' => 'permissions.update', 'uses' => 'User\PermissionsController#update']);
Route::delete(LaravelLocalization::transRoute('routes.permissions.destroy'), ['as' => 'permissions.destroy', 'uses' => 'User\PermissionsController#destroy']);
});
EDIT 2 : 29/01/2015
Following the Lerzenit solution explained here, I tried to place the following code into the file tests/_bootstrap.php :
Request::enableHttpMethodParameterOverride();
It had no effect, I still have a 200 response and the update method from my controller is never reached.
I checked if the $httpMethodParameterOverride param was passed to true just after the method execution and could verify that is has been successful set to true.
I am still looking for a solution.
EDIT 3 : 05/02/2015
I have a clue on an investigation way : I succeeded to execute an update on a entity named 'District' and this is the only one on my project to have the same route in english and in french. As I specified earlier, I use the LaravelLocalization plugin and the routes translation may be the cause of the bad interpretation of the _method param with the PUTvalue that should redirect toward the update method of my controller.
I would be grateful if someone could help me on this.
I finally found the solution !
The update method was never reached because, on my POST requests, I sometimes passed the id of the resource into the request by using hidden variables as _id for example.
Laravel expect an id to be given on the post UPDATEor DELETErequests after a slash, that is why the UPDATE / DELETE methods were never reached. In fact, this is a bad practice to pass params in the request on PUT / PATCH / DELETE requests because the targeted resource must be explicitly shown in the url.
So, if you encounter the same problem, be sure you precise a correct POST route in your form as route('users.update', ['id' => $user->id])for example.
Pfiuuu, I now can write my tests in order to have a 100% tested app. That was a painful investigation ;)
Related
In my routes.php I have:
Route::patch('/preferences/{id}', 'UserController#update');
And in the view file (account/preferences.blade.php) I have:
{!! Form::model(Auth::user(), ['method' => 'PATCH', 'route' => '/preferences/' . Auth::user()->id]) !!}
But I'm getting this error:
Route [/preferences/1] not defined
A similar error occurs when calling the route() helper directly:
route('/preferences/' . Auth::user()->id');
I think I'm misunderstanding the docs on this topic but I've defined a route for PATCH requests with a given parameter, and set this in the view correctly. What am I overlooking here?
The route() method, which is called when you do ['route' => 'someroute'] in a form opening, wants what's called a named route. You give a route a name like this:
Route::patch('/preferences/{id}',[
'as' => 'user.preferences.update',
'uses' => 'UserController#update'
]);
That is, you make the second argument of the route into an array, where you specify both the route name (the as), and also what to do when the route is hit (the uses).
Then, when you open the form, you call the route:
{!! Form::model(Auth::user(), [
'method' => 'PATCH',
'route' => ['user.preferences.update', Auth::user()->id]
]) !!}
Now, for a route without parameters, you could just do 'route' => 'routename', but since you have a parameter, you make an array instead and supply the parameters in order.
All that said, since you appear to be updating the current user's preferences, I would advise you to let the handling controller check the id of the currently logged-in user, and base the updating on that - there's no need to send in the id in the url and the route unless your users should need to update the preferences of other users as well. :)
This thread is old but was the first one to come up so I thought id share my solution too. Apart from having named routes in your routes.php file. This error can also occur when you have duplicate URLs in your routes file, but with different names, the error can be misleading in this scenario. Example:
Route::any('official/form/reject-form', 'FormStatus#rejectForm')
->name('reject-form');
Route::any('official/form/accept-form', 'FormStatus#acceptForm')
->name('accept-form');
Changing one of the names solves the problem. Copy, pasting, & fatigue can lead you to this problem :).
If route is not defined, then check web.php routing file.
Route::get('/map', 'NavigationController#map')->name('map'); // note the name() method.
Then you can use this method in the views:
<a class="nav-link" href="{{ route('map') }}">{{ __('Map') }}</a>
PS: the __('Map') is to translate "Map" to the current language.
And the list of names for routes you can see with artisan command:
php artisan route:list
I'm using Laravel 5.7 and tried all of the above answers but nothing seemed to be hitting the spot.
For me, it was a rather simple fix by removing the cache files created by Laravel.
It seemed that my changes were not being reflected, and therefore my application wasn't seeing the routes.
A bit overkill, but I decided to reset all my cache at the same time using the following commands:
php artisan route:clear
php artisan view:clear
php artisan cache:clear
The main one here is the first command which will delete the bootstrap/cache/routes.php file.
The second command will remove the cached files for the views that are stored in the storage/framework/cache folder.
Finally, the last command will clear the application cache.
when you execute the command
php artisan route:list
You will see all your registered routes in there in table format .
Well there you see many columns like Method , URI , Name , Action .. etc.
So basically if you are using route() method that means it will accept only name column values and if you want to use URI column values you should go with url() method of laravel.
One more cause for this:
If the routes are overridden with the same URI (Unknowingly), it causes this error:
Eg:
Route::get('dashboard', ['uses' => 'SomeController#index', 'as' => 'my.dashboard']);
Route::get('dashboard/', ['uses' => 'SomeController#dashboard', 'as' => 'my.home_dashboard']);
In this case route 'my.dashboard' is invalidate as the both routes has same URI ('dashboard', 'dashboard/')
Solution: You should change the URI for either one
Eg:
Route::get('dashboard', ['uses' => 'SomeController#index', 'as' => 'my.dashboard']);
Route::get('home-dashboard', ['uses' => 'SomeController#dashboard', 'as' => 'my.home_dashboard']);
// See the URI changed for this 'home-dashboard'
Hope it helps some once.
My case is a bit different, since it is not a form but to return a view. Add method ->name('route').
MyView.blade.php looks like this:
CATEGORIES
And web.php routes file is defined like this:
Route::view('admin', 'admin.index')->name('admin');
i had the same issue and find the solution lately.
you should check if your route is rather inside a route::group
like here:
Route::group(['prefix' => 'Auth', 'as' => 'Auth.', 'namespace' => 'Auth', 'middleware' => 'Auth']
if so you should use it in the view file. like here:
!! Form::model(Auth::user(), ['method' => 'PATCH', 'route' => 'Auth.preferences/' . Auth::user()->id]) !!}
In my case the solution was simple:
I have defined the route at the very start of the route.php file.
After moving the named route to the bottom, my app finally saw it.
It means that somehow the route was defined too early.
On a side note:
I had the similar issues where many times I get the error Action method not found, but clearly it is define in controller.
The issue is not in controller, but rather how routes.php file is setup
Lets say you have Controller class set as a resource in route.php file
Route::resource('example', 'ExampleController');
then '/example' will have all RESTful Resource listed here:
http://laravel.com/docs/5.0/controllers#restful-resource-controllers
but now you want to have some definition in form e.g: 'action'=>'ExampleController#postStore' then you have to change this route (in route.php file) to:
Route::controller('example', 'ExampleController');
Please note that the command
php artisan route:list
Or to get more filter down list
php artisan route:list | grep your_route|your_controller
the forth column tells you the names of routes that are registered (usually generated by Route::resource)
In route.php I defined a route to a controller with 2 tokens on it.
Route::get('/{category}/{slug}', 'projectController#detail');
Everything is working fine till when there is a call to a URL that have the same structure but has nothing to do with the one that has to be caught by that route shown below.
So when I have for example "/admin/tags", the controller below is triggered because it has the same structure of "/{category}/{slug}" and of course it gives me an error, because it doesn't find a variable.
So now I fixed the problem moving that route on the bottom, but I believe I have to do something to prevent this behavior in advance, cause if I have multiple routes with different tokens everything would be triggered every time and there would be a mess.
So, what is it supposed to do in these cases?
P.S. I'm super beginner with Laravel
use some constraint to the route, reference parameters-regular-expression-constraints. For example:
Route::get('user/{name}', function ($name) {
//
})
->where('name', '[A-Za-z]+');
Or you can make the most specific before unspecific one. For example, in this sequence:
Route::get("/admin/tags", '......');
Route::get('/{category}/{slug}', 'projectController#detail');
if route need two token like that, i'm usually add prefix so my routes looks like this
Route::get('/categories/{category}/slug/{slug}', 'ProjectController#detail');
or
Route::get('/categories/{category}/{slug}', 'ProjectController#detail');
I was having the same issue.
I have constraints on every path parameter (as you always should) and unfortunately the conflict occurs between the following:
Route::get('{userId}/{path}', [
'as' => 'products',
'uses' => 'HomeController#click'
])->where(['id' => '[0-9]+', 'path' => '[0-9a-fA-F]+']);
Route::get('link/{link_path}', [
'as' => 'product-link',
'uses' => 'UserController#productLink'
])->where(['link_path' => '[0-9a-fA-F]+']);
Where even though the one path has the prepended 'link/' in the path it still tried to hit the other. By placing the route with the prepended 'link/' above the other route it took priority and works.
Personally I think if you have a condition that isn't met on the route where clause it should skip the route and move on to the next. It doesn't really make sense to me to put a conditional that doesn't actually get passed up if the conditions aren't met.
Hopefully this helps anyone else having this issue.
I have a homegrown, Laravel 5.1 base application on top of which I build specific applications. The base application uses a named route for login, naturally called "login", which listens for GET /login.
In one of my specific applications, I attempted to overload that route to send the requests to a different controller. It seemed to work for a while, but then it started going to the base application's controller again. I'm sure I changed something to break it, but the problem is that I can't figure out how to fix it again.
My base application routes are all defined in app/Http/Routes/core.php. The relevant route:
Route::get('login', [
'as' => 'login',
'uses' => '\MyVendor\Core\Http\Controllers\AuthController#getLogin'
]);
My specific application routes are defined in app/Http/Routes/app1.php. The relevant route:
Route::get('login', [
'as' => 'login',
'uses' => 'App1\AuthController#getLogin'
]);
App2 and App3 are defined similarly. My app/Http/routes.php adds these routes like this:
require 'Routes/core.php';
Route::group(['domain' => 'app1.com'], function() {
require 'Routes/app1.php';
});
Route::group(['domain' => 'app2.com', function() {
require 'Routes/app2.php';
});
Route::group(['domain' => 'app3.com', function() {
require 'Routes/app3.php';
});
The problem I am seeing is that visiting app1.com/login, app2.com/login, and app3.com/login all result in the execution of \MyVendor\Core\Http\Controllers\AuthController#getLogin rather than App1\AuthController#getLogin.
EDIT: I have changed the problem description since I was describing it incorrectly as a problem with calls to route('login').
The index of the routes in Laravel follows a "$domain$uri" format, therefore routes with a domain won't overwrite those without. A fallback route without a domain should be declared after the domain group, so it is later in the route collection and won't match before a route with a matching domain.
"the most recent definition for a route is the effective route"
This is not a bug, this is the expected behaviour, a simple example would be setting a variable to value 1 then setting it to value 2, of course the (most) recent value takes place.
In my routes.php I have:
Route::patch('/preferences/{id}', 'UserController#update');
And in the view file (account/preferences.blade.php) I have:
{!! Form::model(Auth::user(), ['method' => 'PATCH', 'route' => '/preferences/' . Auth::user()->id]) !!}
But I'm getting this error:
Route [/preferences/1] not defined
A similar error occurs when calling the route() helper directly:
route('/preferences/' . Auth::user()->id');
I think I'm misunderstanding the docs on this topic but I've defined a route for PATCH requests with a given parameter, and set this in the view correctly. What am I overlooking here?
The route() method, which is called when you do ['route' => 'someroute'] in a form opening, wants what's called a named route. You give a route a name like this:
Route::patch('/preferences/{id}',[
'as' => 'user.preferences.update',
'uses' => 'UserController#update'
]);
That is, you make the second argument of the route into an array, where you specify both the route name (the as), and also what to do when the route is hit (the uses).
Then, when you open the form, you call the route:
{!! Form::model(Auth::user(), [
'method' => 'PATCH',
'route' => ['user.preferences.update', Auth::user()->id]
]) !!}
Now, for a route without parameters, you could just do 'route' => 'routename', but since you have a parameter, you make an array instead and supply the parameters in order.
All that said, since you appear to be updating the current user's preferences, I would advise you to let the handling controller check the id of the currently logged-in user, and base the updating on that - there's no need to send in the id in the url and the route unless your users should need to update the preferences of other users as well. :)
This thread is old but was the first one to come up so I thought id share my solution too. Apart from having named routes in your routes.php file. This error can also occur when you have duplicate URLs in your routes file, but with different names, the error can be misleading in this scenario. Example:
Route::any('official/form/reject-form', 'FormStatus#rejectForm')
->name('reject-form');
Route::any('official/form/accept-form', 'FormStatus#acceptForm')
->name('accept-form');
Changing one of the names solves the problem. Copy, pasting, & fatigue can lead you to this problem :).
If route is not defined, then check web.php routing file.
Route::get('/map', 'NavigationController#map')->name('map'); // note the name() method.
Then you can use this method in the views:
<a class="nav-link" href="{{ route('map') }}">{{ __('Map') }}</a>
PS: the __('Map') is to translate "Map" to the current language.
And the list of names for routes you can see with artisan command:
php artisan route:list
I'm using Laravel 5.7 and tried all of the above answers but nothing seemed to be hitting the spot.
For me, it was a rather simple fix by removing the cache files created by Laravel.
It seemed that my changes were not being reflected, and therefore my application wasn't seeing the routes.
A bit overkill, but I decided to reset all my cache at the same time using the following commands:
php artisan route:clear
php artisan view:clear
php artisan cache:clear
The main one here is the first command which will delete the bootstrap/cache/routes.php file.
The second command will remove the cached files for the views that are stored in the storage/framework/cache folder.
Finally, the last command will clear the application cache.
when you execute the command
php artisan route:list
You will see all your registered routes in there in table format .
Well there you see many columns like Method , URI , Name , Action .. etc.
So basically if you are using route() method that means it will accept only name column values and if you want to use URI column values you should go with url() method of laravel.
One more cause for this:
If the routes are overridden with the same URI (Unknowingly), it causes this error:
Eg:
Route::get('dashboard', ['uses' => 'SomeController#index', 'as' => 'my.dashboard']);
Route::get('dashboard/', ['uses' => 'SomeController#dashboard', 'as' => 'my.home_dashboard']);
In this case route 'my.dashboard' is invalidate as the both routes has same URI ('dashboard', 'dashboard/')
Solution: You should change the URI for either one
Eg:
Route::get('dashboard', ['uses' => 'SomeController#index', 'as' => 'my.dashboard']);
Route::get('home-dashboard', ['uses' => 'SomeController#dashboard', 'as' => 'my.home_dashboard']);
// See the URI changed for this 'home-dashboard'
Hope it helps some once.
My case is a bit different, since it is not a form but to return a view. Add method ->name('route').
MyView.blade.php looks like this:
CATEGORIES
And web.php routes file is defined like this:
Route::view('admin', 'admin.index')->name('admin');
i had the same issue and find the solution lately.
you should check if your route is rather inside a route::group
like here:
Route::group(['prefix' => 'Auth', 'as' => 'Auth.', 'namespace' => 'Auth', 'middleware' => 'Auth']
if so you should use it in the view file. like here:
!! Form::model(Auth::user(), ['method' => 'PATCH', 'route' => 'Auth.preferences/' . Auth::user()->id]) !!}
In my case the solution was simple:
I have defined the route at the very start of the route.php file.
After moving the named route to the bottom, my app finally saw it.
It means that somehow the route was defined too early.
On a side note:
I had the similar issues where many times I get the error Action method not found, but clearly it is define in controller.
The issue is not in controller, but rather how routes.php file is setup
Lets say you have Controller class set as a resource in route.php file
Route::resource('example', 'ExampleController');
then '/example' will have all RESTful Resource listed here:
http://laravel.com/docs/5.0/controllers#restful-resource-controllers
but now you want to have some definition in form e.g: 'action'=>'ExampleController#postStore' then you have to change this route (in route.php file) to:
Route::controller('example', 'ExampleController');
Please note that the command
php artisan route:list
Or to get more filter down list
php artisan route:list | grep your_route|your_controller
the forth column tells you the names of routes that are registered (usually generated by Route::resource)
In my case, I was using a duplicate method. I was trying to update like this:
Route::get('/preferences/{id}', 'UserController#edit');
Route::get('/preferences/{id}', 'UserController#update');
When what I meant to do was something similar to this:
Route::get('/preferences/{id}', 'UserController#edit');
Route::post('/preferences/{id}', 'UserController#update');
Notice the get and post methods are different but the URLs are the same.
I got an annoying problem with a route, for a section of a CMS that I'm developing.
I got routes for all the sections, "products", for example:
Route::get('admin/products', array('as' => 'admin/products', 'uses'=> 'admin.products#index'));
Route::get('admin/products/create', array('as' => 'admin/products/create', 'uses'=> 'admin.products#create'));
Route::get('admin/products/edit/(:num)', array('as' => 'admin/products/edit', 'uses'=> 'admin.products#edit'));
Route::get('admin/products/delete/(:num)', array('as' => 'admin/products/delete', 'uses'=> 'admin.products#delete'));
.. and the related files, like the products controller, the product model and the views.
Everything was doing well until I decided to create a new section, "users". I used the same approach as "products", creating the routes and the other files. In fact I just copied and paste the files, making the changes when needed -- pretty straightforward. By accessing "admin/users" and "admin/users/create", it works as expected. But I can't access "/users/edit/1" and "/users/delete/1". I thought it would be a route problem, but when I tested the route file, I got a 404 even before reaching the route. Here's an example:
Route::get('admin/users/edit/(:num)', function()
{
return "Holy Hell.";
});
"Holy Hell" is never printed into the screen.
Here's the config for "users":
Route::get('admin/users', array('as' => 'admin/users', 'uses'=> 'admin.users#index'));
Route::get('admin/users/edit/(:num)', array('as' => 'admin/users/edit/', 'uses'=> 'admin.users#edit'));
Route::get('admin/users/create', array('as' => 'admin/users/create', 'uses'=> 'admin.users#create'));
Route::get('admin/users/delete/(:num)', array('as' => 'admin/users/delete', 'uses'=> 'admin.users#delete'));
Things that I noticed / Checked:
The index view, where is the users list, got a "URL::to_route('admin/users/edit')" function. I have no errors on the screen, so Laravel understands that the route 'admin/users/edit' is set correctly.
I know that this is not a general problem, because the "edit" and "delete" methods for the other CMS sections have no issues.
The views for these methods are there. So this is not a "file not found" issue.
I wonder if I'm missing something really obvious here. Any ideas? If not, would anyone please tell me how to debug this?
Thank you very much.
EDIT: Heads up
Your routes are in a bad order. Reverse them. Routes are evaluated top down, so anything with admin/products in the route will route to admin.products#index and nothing else.
In your edit method, you need to have the id parameter defined.
Since you didn't post your controller, I'm assuming this is why, since the closure does not have the $id passed to it. Example:
// Required user id:
Route::get('admin/users/edit/(:num)', function($id)
{
return "Holy Hell.";
});
// Optional user id:
Route::get('admin/users/edit/(:num?)', function($id = null)
{
return "Holy Hell.";
});
In your case, you probably don't want the optional part unless you plan on spewing out an error (or redirecting on error).