Laravel Routing to Wrong View - php

I'm working with Laravel 4.2. I have an app that's routing to the wrong view, although the URL is correct. On a button click, it's supposed to route to users.create (UsersController#create), but is instead routing to UsersController#show. The resolved URL is correct, though, and the DOM element has the correct URL listed. Can anyone help me out?
Here is my Routes file:
// Home page
Route::get('/', 'BaseController#index');
// Define User model to pass through routes
Route::model('user', 'User');
// Create custom route for editing a user
Route::get('users/edit/{user}',
array('as' => 'users.edit', 'uses' => 'UsersController#edit'));
// Create custom route for showing a user
Route::get('users/{user}',
['as' => 'users.show', 'uses' => 'UsersController#show']);
// Remaining routes
Route::resource('users', 'UsersController',
array('except' => array('edit', 'show')));
Here is my UsersController with the two functions in question:
class UsersController extends \BaseController {
protected $user;
public function create()
{
return View::make('users/create');
}
public function show($user)
{
return View::make('users/show', ['user' => $user]);
}}
And here are the relevant results from php artisan routes:
GET:HEAD users/{user} users.show UsersController#show
GET:HEAD users/create users.create UsersController#create
Thanks for your help!
Edit:
The answer to the problem was to simply re-order the routes so that the resource is defined first. I was aware that Laravel grabs the first route that matches a URI, but I still don't understand why a route that isn't passed a user object would select a route defined as users/{user}. Furthermore, I was accessing the route via link_to_route(), that is to say, by name. Why would Laravel pick a different route from the one I explicitly named?
I suppose these questions are beyond the scope of the initial question, but I would greatly appreciate further explanation from someone. Problem solved!

The first thing that jumps out at me is there is no route for "create". There is the "restful" controller, but maybe you want to just try putting the route in. I'm slightly uncomfortable using restful routes when serving html. In the project i'm working on i've been trying to preserve those for data/json transmission, in order to support outside api action.

I think your routes setup recognizes create as {user} in user/{user}, thus redirect to user/show/create as your "custom route for showing a user" setup.
You may have to avoid getting string variable right after users/ route.

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 5.3 - flash data removed after redirect

I am using Laravel 5.3
I have two models, Parent and Student with a many-to-many relationship between them and I want to add a Parent for a Student and vice versa.
My approach was:
Create a link from Student profile to add Parent, like so:
Add Parent
Add the route students.parents.add with a controller method to flash the id to the session and redirect.
// in web.php:
Route::get('/students/{id}/parents/add', ['as' => 'students.parents.add', 'uses' => 'StudentController#addParent']);
Route::resource('students', 'StudentController');
// and in StudentsController:
public function addParent($id)
{
return redirect()->route('parents.create')->with('associated_id', $id);
}
After that, clicking the button redirects to the ParentsController create() but the session data is not there when I try return session()->all().
Am I missing something?
Make sure you are not adding web middleware in your routes.php file as it is already added in the file RouteServiceProvider.php file.
If you now apply it again in your routes.php, you will see that web appears twice on the route list php artisan route:list. This exactly makes the flash data discard.

Laravel 5 redirect to path with parameters (not route name)

I've been reading everywhere but couldn't find a way to redirect and include parameters in the redirection.
This method is for flash messages only so I can't use this.
return redirect('user/login')->with('message', 'Login Failed');
This method is only for routes with aliases my routes.php doesn't currently use an alias.
return redirect()->route('profile', [1]);
Question 1
Is there a way to use the path without defining the route aliases?
return redirect('schools/edit', compact($id));
When I use this approach I get this error
InvalidArgumentException with message 'The HTTP status code "0" is not valid.'
I have this under my routes:
Route::get('schools/edit/{id}', 'SchoolController#edit');
Edit
Based on the documentation the 2nd parameter is used for http status code which is why I'm getting the error above. I thought it worked like the URL facade wherein URL::to('schools/edit', [$school->id]) works fine.
Question 2
What is the best way to approach this (without using route aliases)? Should I redirect to Controller action instead? Personally I don't like this approach seems too long for me.
I also don't like using aliases because I've already used paths in my entire application and I'm concerned it might affect the existing paths if I add an alias? No?
redirect("schools/edit/$id");
or (if you prefer)
redirect("schools/edit/{$id}");
Just build the path needed.
'Naming' routes isn't going to change any URI's. It will allow you to internally reference a route via its name as opposed to having to use paths everywhere.
Did you watch the class Illuminate\Routing\Redirector?
You can use:
public function route($route, $parameters = [], $status = 302, $headers = [])
It depends on the route you created. If you create in your app\Http\Routes.php like this:
get('schools/edit/{id}', 'SchoolController#edit');
then you can create the route by:
redirect()->action('SchoolController#edit', compact('id'));
If you want to use the route() method you need to name your route:
get('schools/edit/{id}', ['as' => 'schools.edit', 'uses' => 'SchoolController#edit']);
// based on CRUD it would be:
get('schools/{id}/edit', ['as' => 'schools.edit', 'uses' => 'SchoolController#edit']);
This is pretty basic.
PS. If your schools controller is a resource (CRUD) based you can create a resource() and it will create the basic routes:
Route::resource('schools', 'SchoolController');
// or
$router->resource('schools', 'SchoolController');
PS. Don't forget to watch in artisan the routes you created

Route definition not working in Laravel

I have 2 routes in my routes file.
Route::get('/deals/{merchant_name}?c={deal_id}', ['uses' => 'dealsvisibleController#index']);
Route::get('/deals/{merchant_name}', ['uses' =>'dealsController#index']);
Both routes are calling on a different controller function. The first route is however not working.
I am trying this in a 3rd controller.
return redirect('deals/'.$merchant_name.'?c='.$deal_id);
However, when the page redirects, it is calling dealsController#index and not dealsvisibleController#index
Can someone help me with why this is happening.
Laravel's router considers only path when matching URLs to your routes. Therefore, if you redirect to deals/someMerchant?c=someDealId then it uses deals/someMerchant to match the URL.
You'll need to define the first route as deals/{merchant_name}/{deal_id} in order for this routing to work as you want it to.

Change Laravel's default (root) controller

In Laravel the default controller is the Home_Controller. However I have a controller called frontend. I want to use this instead of the home controller.
When I register a route like this:
Route::controller(Controller::detect());
then a request to /offer will be handled from within the home controller like home#offer. I want to use frontend#offer and access it from the site's root - not like /frontend/offer.
What should I do?
Thanks in advance.
Home_Controller is one of the hard-coded convention which exist in Laravel 3, however there are still ways to define routing to point the Frontend_Controller methods, my preference would be.
Route::any('/(index|offer|something)', function ($action)
{
return Controller::call("frontend#{$action}");
});
Limitation with this is that you need to define all supported "actions" method in Frontend_Controller.
My guess is that the only reason you think the Home_Controller is some sort of default is because you are using Controller::detect(); I really haven't seen anything in the documentation to make me think that the Home_Controller is anything special at all. In fact, it doesn't even look like it is routed to in the example documentation. Given that, my first suggestion would be to get rid of Controller::detect() and see if that fixes your problem.
Barring that, have you tried registering frontend as route named home? It appears that all URL::home() does is search for the 'Home' route, and then redirect to it. When using controller routing this can be done with something to the effect of.
Route::get('/',
array(
'as' => 'home',
'uses' => 'frontend#index'
)
);
Or is that not your desired effect? Do you want all routes which aren't otherwise found to be redirected to your frontend controller?
If you are concerned about your urls looking pretty, you can probably use some rewrite rules in your .htaccess file to make the whole process of routing to /frontend/index transparent you your users.
Add this to your routes.php :
Route::get('/', array('as' => 'any.route.name', 'uses' => 'frontend#offer'));
If you have any other / route, just remove it.

Categories