Framework PHP Route - Error 404 Not found - php

In Laravel, I need to edit user created by Auth/RegisterController, but using the controller that I created, example ProfileController. But when I try access by a a:href button, show 404 Error.
Code:
web.php
Route::group(['middleware' => ['auth']], function(){
Route::resource('profile', 'ProfileController')->except(['edit']);
Route::get('profile/{profile}/edit', ['as' => 'profile.edit', 'uses' => 'ProfileController#edit']);
});
Auth::routes();
app.blade.php
<a href="{{route('profile.edit',['profile'=>auth()->user()->id])}}" class="btn btn-primary">
{{auth()->user()->email}}
</a>
ProfileController
public function edit($profile)
{
$user = \App\User::findOrFail($profile);
return view('profile.edit', compact('user'));
}
List Routes
| | POST | profile | profile.store | App\Http\Controllers\ProfileController#store | web,auth,guest |
| | GET|HEAD | profile | profile.index | App\Http\Controllers\ProfileController#index | web,auth,guest |
| | GET|HEAD | profile/create | profile.create | App\Http\Controllers\ProfileController#create | web,auth,guest |
| | DELETE | profile/{profile} | profile.destroy | App\Http\Controllers\ProfileController#destroy | web,auth,guest |
| | PUT|PATCH | profile/{profile} | profile.update | App\Http\Controllers\ProfileController#update | web,auth,guest |
| | GET|HEAD | profile/{profile} | profile.show | App\Http\Controllers\ProfileController#show | web,auth,guest |
| | GET|HEAD | profile/{profile}/edit | profile.edit | App\Http\Controllers\ProfileController#edit | web,auth,guest |
Someone can help me?
Tks,
Aguiar, Adson M.

Welcome to SO!
Like #lagbox mentioned, you can just keep the
Route::resource('profile', 'ProfileController');
without the ->except() to have the exact same edit route automatically generated for you.
Furthermore, you can simplify your controller action to:
public function edit(User $profile)
{
return view('profile.edit', compact('profile'));
}
This uses type hinting to automatically have the dependency injection resolve a User instance for you, identified by the key passed in with the {profile} parameter.
You would then have to go with $profile in your profile/edit.blade.php, unless you want to do something like return view('profile.edit', ['user' => $profile]);.
It might be a good idea to name the parameters like your Models. Resource routes usually base completely on the Model's names, so profile is not a good choice for User routes. You might either use Route::resource('user', 'ProfileController') (or even UserController for that matter), or if you want to stick with profile, but want $user as a parameter, you would have to create all routes by yourself like Route::get('profile/{user}/edit', 'ProfileController').
Also, writing route('profile.edit',['profile'=>auth()->user()]) works too, and has the advantage that it would not break when the user is not authenticated.
All that said, your code should still work. Try to use a find() instead of a findOrFail() and dd($user); in the following line to make sure your route is working. If you see the dump, it is probably null, meaning the id passed is not valid, which would be really odd.
If you can post the full generated link of the anchor tag and the outcome of the dd, I'll be happy to help.

Related

Laravel Controller Dependency Injection

I'm trying to do dependency injection in Laravel to keep my controllers and models as slim as possible. The goal is to have repositories to handle the fetching of data attributed to certain models.
To this end I'm trying to follow the example from the documentation here and a popular Laravel boilerplate here
But I don't understand where the $user is coming from.
So looking at the boilerplate we have two files:
The ProfileController here
Excerpt below:
use App\Repositories\Frontend\Access\User\UserRepository;
/**
* Class ProfileController.
*/
class ProfileController extends Controller
{
/**
* #var UserRepository
*/
protected $user;
/**
* ProfileController constructor.
*
* #param UserRepository $user
*/
public function __construct(UserRepository $user)
{
$this->user = $user;
}
This looks a lot like the dependency injection mentioned in the docs, which is this:
class UserController extends Controller {
/**
* The user repository instance.
*/
protected $users;
/**
* Create a new controller instance.
*
* #param UserRepository $users
* #return void
*/
public function __construct(UserRepository $users)
{
$this->users = $users;
}
My problem is I don't understand where the $user is coming from.
In the UserRepository there is no $user defined as a parameter of the class itself. No where in the code is there any Auth::user() so I'm confused as to where the user instance is coming from.
In Laravel dependency injection is handled by the Container. I'm simplifying, but you can think of the container as a source of objects. If there is a singleton, its stored in the container. Otherwise the container knows how to instantiate objects for you. Whenever Laravel calls a method (like in a controller) or instantiates an object for you it will inspect the constructor and look for type hinted dependencies. If it sees a dependency it knows how to retrieve or create it will do so and pass it in for you.
So when Laravel instantiates the controller it looks at the constructor
public function __construct(UserRepository $user)
{
$this->user = $user;
}
The container uses Type Hinting to see that it requires a UserRepository so it will instantiate a new one for you. It also does this recursively. So when it creates a new UserRepository it looks at that constructor and sees that it requires a RoleRepository so it will instantiate that as well.
TLDR: The service container inspects your dependencies and will instantiate them for you.
Welcome to the dubious magic of Laravel. The basic idea with these dependency injections is that, depending on how you define your routes & controllers, Laravel can perform some automagical parsing of urls, identification of ids in those urls, and database fetching of objects.
My problem is I don't understand where the $user is coming from.
You should probably read the docs on the service container. You can also get a better idea of how your route definitions translate into parameter-laden urls with this command:
php artisan route:list
On one of my projects, this results in this output:
+--------+-----------+----------------------------+--------------------+-------------------------------------------------+--------------+
| Domain | Method | URI | Name | Action | Middleware |
+--------+-----------+----------------------------+--------------------+-------------------------------------------------+--------------+
| | GET|HEAD | / | | Closure | web |
| | GET|HEAD | api/user | | Closure | api,auth:api |
| | GET|HEAD | categories | categories.index | App\Http\Controllers\CategoryController#index | web |
| | POST | categories | categories.store | App\Http\Controllers\CategoryController#store | web |
| | GET|HEAD | categories/create | categories.create | App\Http\Controllers\CategoryController#create | web |
| | GET|HEAD | categories/{category} | categories.show | App\Http\Controllers\CategoryController#show | web |
| | PUT|PATCH | categories/{category} | categories.update | App\Http\Controllers\CategoryController#update | web |
| | DELETE | categories/{category} | categories.destroy | App\Http\Controllers\CategoryController#destroy | web |
| | GET|HEAD | categories/{category}/edit | categories.edit | App\Http\Controllers\CategoryController#edit | web |
| | GET|HEAD | products | products.index | App\Http\Controllers\ProductController#index | web |
| | POST | products | products.store | App\Http\Controllers\ProductController#store | web |
| | GET|HEAD | products/create | products.create | App\Http\Controllers\ProductController#create | web |
| | GET|HEAD | products/{product} | products.show | App\Http\Controllers\ProductController#show | web |
| | PUT|PATCH | products/{product} | products.update | App\Http\Controllers\ProductController#update | web |
| | DELETE | products/{product} | products.destroy | App\Http\Controllers\ProductController#destroy | web |
| | GET|HEAD | products/{product}/edit | products.edit | App\Http\Controllers\ProductController#edit | web |
+--------+-----------+----------------------------+--------------------+-------------------------------------------------+--------------+
And all those routes and their uris and parameters are generated from only a couple of very simple routes definitions. Here's my routes file:
$ cat routes/web.php
<?php
Route::get('/', function () {
return view('master');
});
Route::resource('products', 'ProductController');
Route::resource('categories', 'CategoryController');
If you look at the list of URIs in the routes output above, you'll see parameters named in the URIs like {category} and {product}. These correspond to ids/keys in the URI which Laravel identifies. Laravel is "smart" enough to look at my Controller files, see the type-hinting in the various functions and detect that my function is expecting a depedency to be injected.
For instance, the Category controller's show method looks like this:
public function show(Tree $category)
{
var_dump($category);
}
My controller might seem a little unusual because I'm type hinting that I want an object of type Tree, but Laravel is smart enough to recognize that I do in fact want a Model of type Tree, so it parses out the url and finds the id in it and automatically fetches the record in my db table trees with id matching the {category} fragment of my url and injects that into my function.
Note that I had some trouble when I tried to name the input parameter $tree instead of $category. That other thread may help answer your question a bit too.
The bottom line is that Laravel does a lot of "magic" to hopefully free you up from the tedious of manually defining your own code and queries to retrieve the objects you want.

Laravel 5.1 adding middleware to resource route

so I have been trying to use middleware with my route resource and having trouble making it work.
Here is my routes setup:
Route::group(['prefix' => 'api','middleware' => 'locationRouteValidator'], function()
{
Route::resource('location', 'LocationController');
});
and route seems to be setup properly:
php artisan route:list
+--------+----------+------------------------------+----------------------+-------------------------------------------------+------------------------+
| Domain | Method | URI | Name | Action | Middleware |
+--------+----------+------------------------------+----------------------+-------------------------------------------------+------------------------+
| | GET|HEAD | / | | Closure | |
| | GET|HEAD | api/location | api.location.index | App\Http\Controllers\LocationController#index | locationRouteValidator |
| | POST | api/location | api.location.store | App\Http\Controllers\LocationController#store | locationRouteValidator |
| | GET|HEAD | api/location/create | api.location.create | App\Http\Controllers\LocationController#create | locationRouteValidator |
| | DELETE | api/location/{location} | api.location.destroy | App\Http\Controllers\LocationController#destroy | locationRouteValidator |
| | PATCH | api/location/{location} | | App\Http\Controllers\LocationController#update | locationRouteValidator |
| | GET|HEAD | api/location/{location} | api.location.show | App\Http\Controllers\LocationController#show | locationRouteValidator |
| | PUT | api/location/{location} | api.location.update | App\Http\Controllers\LocationController#update | locationRouteValidator |
| | GET|HEAD | api/location/{location}/edit | api.location.edit | App\Http\Controllers\LocationController#edit | locationRouteValidator |
+--------+----------+------------------------------+----------------------+-------------------------------------------------+------------------------+
so now I create the middleware :
php artisan make:middleware locationRouteValidator
and leave the default code, which is :
public function handle($request, Closure $next)
{
return $next($request);
}
and just for testing, in my controllers show method, I echo out the passed id like so:
public function show($id)
{
//
echo "show ".$id;
}
so now I expect that when I visit /public/api/location/abcd it should display:
show abcd or when I visit /public/api/location/1234 it should display show 1234 after which I intended to modify the middleware to allow only numeric values to be passed into {location}.
But If I just run with the default middleware code, the page returns white without displaying anything. I remove the middleware from the route, and it displays the text as expected.
I know I could attach the middleware to the controller instead, but I thought of attaching it in the route instead so that I could write and apply some common middleware by using the route's group feature, which should be possible, right?
Where do you guys think I am going wrong? Thanks in advance for looking!
Check your \app\http\kernel.php file to see if you have registered the middleware as a route middleware.

First time Laravel facing NotFoundHttpException

I'm following flynsarmys' laravel tutorial. Everything went well until the second part where I put the index for ProjectsController, when I tested to navigate to 15todo.app:8000/projects in browser the app throws NotFoundHttpException.
routes.php
Route::get('/', function () {
return view('welcome');
});
Route::resource('projects', 'ProjectsController');
// Route::resource('tasks', 'TasksController');
Route::resource('projects.tasks', 'TasksController');
Route::bind('tasks', function($value, $route) {
return App\Task::whereSlug($value)->first();
});
Route::bind('projects', function($value, $route) {
return App\Project::whereSlug($value)->first();
});
ProjectsController.php
public function index()
{
return view('projects.index');
}
I have googled and searched, but I still haven't find a clue of why this is happening. If I checked php artisan route:list it showed like this
$ php artisan route:list
+--------+----------+----------------------------------------+------------------------+-------------------------------------------------+------------+
| Domain | Method | URI | Name | Action | Middleware |
+--------+----------+----------------------------------------+------------------------+-------------------------------------------------+------------+
| | GET|HEAD | / | | Closure | |
| | GET|HEAD | projects | projects.index | App\Http\Controllers\ProjectsController#index | |
| | GET|HEAD | projects/create | projects.create | App\Http\Controllers\ProjectsController#create | |
What am I doing wrong? Help...
My dev env is homestead on windows. For the console I'm using Git Bash (MinGW). My 15todo.app:8000 is up and showing "Laravel 5" and random quotes about simplicity.
You need to actually create the view. Save it in the /app/resources/views/projects/ directory as index.blade.php. Reference the views documentation here.
You can either create a new PHP/HTML file, but the best practice is to use the Blade template engine. For example:
#extends('app')
#section('content')
<!-- your content here -->
{{ 'escaped string' }}
{!! 'non escaped <strong>string</strong>' !!}
#endsection
#stop
Read up a little bit more on the docs for the view, and check out this video on Laracasts.

Laravel controller action returns error 404

I'm getting a 404 error when trying to access a route linked to a controller action.
I have the route defined like this in my routes.php file.
Route::controller('error', 'ErrorsController');
The ErrorsController class looks as follows.
class ErrorsController extends BaseController {
public function __construct()
{
// vacio
}
public function getIndex()
{
return View::make('error.accessdenied');
}
public function getAccessDenied()
{
return View::make('error.accessdenied');
}
}
I have a view with a link to chek if it is working properly. The link is created as follows
{{ HTML::linkAction('ErrorsController#getAccessDenied', 'Error') }}
When I click on the link the page moves to the URL 'mytestdomain.com/error/access-denied' returning an 404 error, but when I access the URL 'mytestdomain.com/error' it works perfectly.
Any idea on what I'm doing wrong?
EDIT:
Running the command php artisan routes these are the routes pointing to ErrorsController:
+--------+------------------------------------------------------------------------------------------------+------+--------------------------------------+----------------+---------------+
| Domain | URI | Name | Action | Before Filters | After Filters |
+--------+------------------------------------------------------------------------------------------------+------+--------------------------------------+----------------+---------------+
| | GET|HEAD error/index/{one?}/{two?}/{three?}/{four?}/{five?} | | ErrorsController#getIndex | | |
| | GET|HEAD error | | ErrorsController#getIndex | | |
| | GET|HEAD error/access-denied/{one?}/{two?}/{three?}/{four?}/{five?} | | ErrorsController#getAccessDenied | | |
| | GET|HEAD|POST|PUT|PATCH|DELETE error/{_missing} | | ErrorsController#missingMethod | | |
+--------+------------------------------------------------------------------------------------------------+------+--------------------------------------+----------------+---------------+
Only the sencond and the fourth ones are working.
It looks as though specifying the route in the way you have won't work. This type of routing only works for RESTful requests. See >http://laravel.com/docs/4.2/controllers#restful-resource-controllers>.
You might have to explicitly specify the route using Route::get/post.
Somehow I found the problem.
For some reason, my apache server doesn't rewrite mytestdomain.com/error/ * route. Probably is something related with the word error and the apache module mod_rewrite.
Anyway, defining the route as follows solves the problem.
Route::controller('fail', 'ErrorsController');

Laravel Using controller Route

i have resource in route and that work correctly and i want to change that to Route::controller.
but after define that i get error in php artisan route :
+--------+------------------------------------+-----------+---------------------------------+----------------+---------------+
| Domain | URI | Name | Action | Before Filters | After Filters |
+--------+------------------------------------+-----------+---------------------------------+----------------+---------------+
| | GET index | index | Closure | | |
| | GET admin/index | dashboard | Closure | | |
| | GET logout | logout | Closure | | |
| | POST auth | auth | Closure | csrf | |
| | GET login | login | Closure | | |
| | GET admin/admin/profile/{_missing} | | ProfileController#missingMethod | | |
+--------+------------------------------------+-----------+---------------------------------+----------------+---------------+
my Current route is:
Route::resource('profile' , 'ProfileController', array('as'=>'profile') );
and i want to change that to :
Route::controller('admin/profile', 'ProfileController', array('index'=>'profile.index') );
how to resolve this problem?
This is not an error, Resource and Controller routes are completely different things.
Resource routes have a predefined list of routes (index, create, store, delete, update). If you don't have the method set in your controller it will still work, unless someone hit that route.
Controller routes relies on your controller methods:
public function getIndex() {}
public function getCreate() {}
public function postStore() {}
Methods names are predefined as
<http method><your action name>()
If those methods are not present in your controller, Laravel will not show them in your routes list.
So, just create a
public function getIndex() {}
In your controller and run
php artisan route
Again.
Use :
Route::resource('profile, 'ProfileController', array('as' => 'profile', 'names' => array('index' => 'profile.index')));
Instead of either the routes above.

Categories