Customizing RegisterController.php - Laravel 5.3 - controllers

I want to restrict the access to the route /register to:
if(Auth::user()->admin == 1)
However, I can't seem to find the showRegistrationForm() method in RegisterController.php as shown under Router.php in vendor\laravel\framework\src\Illuminate\Routing
Here's my RegisterController.php
http://pastebin.com/RVARcy0r

You have to make a method showRegistrationForm() in your controller. All these methods are defined in the Illuminate\Foundation\Auth\RegistersUsers.php.
Also, restrict the access in the middleware.

Related

$request-merge() disappears in parent controller

I'm stuck on a weird issue...
I have a simple middleware.
$request->merge([
'user' => $jwt->toArray(),
'app_version' => $request->header('app-version')
]);
When I do a dump right before the $next($request); the it has the user object and the app_version. All good! See image below:
Moving to the controller. When in the function of defined in the route, and doing a dump($request); it has the user Object
The InstallController extends the controller.php which extends the use Illuminate\Routing\Controller as BaseController;
In the controller.php we have a construct function.
For some reason here the $request is empty and lost the object.
Why is this happening? And why is this available in the InstallController but not in the parent?
What turned out is the following. In Laravel lumen, controller constructors are called after the middleware has completed the request. In Laravel the constructors are called before the middleware.
Meaning that adding params to the request in the middleware in Laravel doesn't work.
Thanks for pointing me in the right direction.

Target class [] does not exist - Laravel 8 [duplicate]

Here is my controller:
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class RegisterController extends Controller
{
public function register(Request $request)
{
dd('aa');
}
}
As seen in the screenshot, the class exists and is in the correct place:
My api.php route:
Route::get('register', 'Api\RegisterController#register');
When I hit my register route using Postman, it gave me the following error:
Target class [Api\RegisterController] does not exist.
How can I fix it?
Thanks to the answers, I was able to fix it. I decided to use the fully qualified class name for this route, but there are other options as described in the answers.
Route::get('register', 'App\Http\Controllers\Api\RegisterController#register');
You are using Laravel 8. In a fresh install of Laravel 8, there is no namespace prefix being applied to your route groups that your routes are loaded into.
"In previous releases of Laravel, the RouteServiceProvider contained a $namespace property. This property's value would automatically be prefixed onto controller route definitions and calls to the action helper / URL::action method. In Laravel 8.x, this property is null by default. This means that no automatic namespace prefixing will be done by Laravel." Laravel 8.x Docs - Release Notes
You would have to use the Fully Qualified Class Name for your Controllers when referring to them in your routes when not using the namespace prefixing.
use App\Http\Controllers\UserController;
Route::get('/users', [UserController::class, 'index']);
// or
Route::get('/users', 'App\Http\Controllers\UserController#index');
If you prefer the old way:
App\Providers\RouteServiceProvider:
public function boot()
{
...
Route::prefix('api')
->middleware('api')
->namespace('App\Http\Controllers') // <---------
->group(base_path('routes/api.php'));
...
}
Do this for any route groups you want a declared namespace for.
The $namespace property:
Though there is a mention of a $namespace property to be set on your RouteServiceProvider in the Release notes and commented in your RouteServiceProvider this does not have any effect on your routes. It is currently only for adding a namespace prefix for generating URLs to actions. So you can set this variable, but it by itself won't add these namespace prefixes, you would still have to make sure you would be using this variable when adding the namespace to the route groups.
This information is now in the Upgrade Guide
Laravel 8.x Docs - Upgrade Guide - Routing
With what the Upgrade Guide is showing the important part is that you are defining a namespace on your routes groups. Setting the $namespace variable by itself only helps in generating URLs to actions.
Again, and I can't stress this enough, the important part is setting the namespace for the route groups, which they just happen to be doing by referencing the member variable $namespace directly in the example.
Update:
If you have installed a fresh copy of Laravel 8 since version 8.0.2 of laravel/laravel you can uncomment the protected $namespace member variable in the RouteServiceProvider to go back to the old way, as the route groups are setup to use this member variable for the namespace for the groups.
// protected $namespace = 'App\\Http\\Controllers';
The only reason uncommenting that would add the namespace prefix to the Controllers assigned to the routes is because the route groups are setup to use this variable as the namespace:
...
->namespace($this->namespace)
...
Yes, in Laravel 8 this error does occur.
After trying many solutions I got this perfect solution.
Just follow the steps...
Case 1
We can change in api.php and in web.php files like below.
The current way we write syntax is
Route::get('login', 'LoginController#login');
That should be changed to:
Route::get('login', [LoginController::class, 'login']);
Case 2
First go to the file: app > Providers > RouteServiceProvider.php
In that file replace the line
protected $namespace = null; with protected $namespace = 'App\Http\Controllers';
Then add line ->namespace($this->namespace) as shown in image...
In Laravel 8 you just add your controller namespace in routes\web.php
use App\Http\Controllers\InvoiceController; // InvoiceController is controller name
Route::get('invoice',[InvoiceController::class, 'index']);
Or go to: app\Providers\RouteServiceProvider.php path and remove the comment:
protected $namespace = 'App\\Http\\Controllers';
In Laravel 8 the default is to remove the namespace prefix, so you can set the old way in Laravel 7 like:
In RouteServiceProvider.php, add this variable:
protected $namespace = 'App\Http\Controllers';
And update the boot method:
public function boot()
{
$this->configureRateLimiting();
$this->routes(function () {
Route::middleware('web')
->namespace($this->namespace)
->group(base_path('routes/web.php'));
Route::prefix('api')
->middleware('api')
->namespace($this->namespace)
->group(base_path('routes/api.php'));
});
}
The way to define your routes in Laravel 8 is either
// Using PHP callable syntax...
use App\Http\Controllers\HomeController;
Route::get('/', [HomeController::class, 'index']);
Or
// Using string syntax...
Route::get('/', 'App\Http\Controllers\HomeController#index');
A resource route becomes
// Using PHP callable syntax...
use App\Http\Controllers\HomeController;
Route::resource('/', HomeController::class);
This means that in Laravel 8, there isn't any automatic controller declaration prefixing by default.
If you want to stick to the old way, then you need to add a namespace property in the
app\Providers\RouteServiceProvider.php and activate in the routes method.
Laravel 8 updated RouteServiceProvider and it affects routes with the string syntax. You can change it like in previous answers, but the recommended way is using action syntax, not using route with string syntax:
Route::get('register', 'Api\RegisterController#register');
It should be changed to:
Route::get('register', [RegisterController::class, 'register']);
I got the same error when I installed Laravel version 8.27.0:
The error is as follows:
But when I saw my app/Providers/RouteServiceProvider.php file, I had namespaces inside my boot method. Then I just uncommented this => protected $namespace = 'App\\Http\\Controllers';.
Now my project is working.
If you are using Laravel 8, just copy and paste my code:
use App\Http\Controllers\UserController;
Route::get('/user', [UserController::class, 'index']);
The Laravel 8 documentation actually answers this issue more succinctly and clearly than any of the answers here:
Routing Namespace Updates
In previous releases of Laravel, the RouteServiceProvider contained a $namespace property. This property's value would automatically be prefixed onto controller route definitions and calls to the action helper / URL::action method. In Laravel 8.x, this property is null by default. This means that no automatic namespace prefixing will be done by Laravel. Therefore, in new Laravel 8.x applications, controller route definitions should be defined using standard PHP callable syntax:
use App\Http\Controllers\UserController;
Route::get('/users', [UserController::class, 'index']);
Calls to the action related methods should use the same callable syntax:
action([UserController::class, 'index']);
return Redirect::action([UserController::class, 'index']);
If you prefer Laravel 7.x style controller route prefixing, you may simply add the $namespace property into your application's RouteServiceProvider.
Also check your route web.php file if your RegisterController is properly in place..
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Auth\RegisterController;
Route::get('/register',[RegisterController::class,'index'])->name('register');
Route::post('/register',[RegisterController::class,'store']);
Route::get('/', function () {
return view('test.index');
});
For the solution, just uncomment line 29:
protected $namespace = 'App\\Http\\Controllers';
in the app\Providers\RouteServiceProvider.php file.
Just uncomment line 29
If you would like to continue using the original auto-prefixed controller routing, you can simply set the value of the $namespace property within your RouteServiceProvider and update the route registrations within the boot method to use the $namespace property:
class RouteServiceProvider extends ServiceProvider
{
/**
* This namespace is applied to your controller routes.
*
* In addition, it is set as the URL generator's root namespace.
*
* #var string
*/
protected $namespace = 'App\Http\Controllers';
/**
* Define your route model bindings, pattern filters, etc.
*
* #return void
*/
public function boot()
{
$this->configureRateLimiting();
$this->routes(function () {
Route::middleware('web')
->namespace($this->namespace)
->group(base_path('routes/web.php'));
Route::prefix('api')
->middleware('api')
->namespace($this->namespace)
->group(base_path('routes/api.php'));
});
}
Yes, check if your web.php in the routes folder has the Controller class used.
use App\Http\Controllers\<name of controlelr class>
Just uncomment the below line from RouteServiceProvider (if does not exists then add it):
protected $namespace = 'App\\Http\\Controllers';
One important thing to make sure you do after each change on the routes is clearing the cache (using Laravel 9):
php artisan route:clear
In my case, I had the same error, because I forgot to capitalize the first letter of controllers in the path.
So I changed
use App\Http\controllers\HomeController;
to this:
use App\Http\Controllers\HomeController;
In Laravel 8 you can use it like this:
Route::group(['namespace'=>'App\Http\Controllers', 'prefix'=>'admin',
'as'=>'admin.', 'middleware' => ['auth:sanctum', 'verified']], function()
{
Route::resource('/dashboard', 'DashboardController')->only([
'index'
]);
});
On a freshly installed Laravel 8, in the App/Providers/RouteServices.php file:
/*
* The path to the "home" route for your application.
*
* This is used by Laravel authentication to redirect users after login.
*
* #var string
*/
public const HOME = '/home';
/**
* The controller namespace for the application.
*
* When present, controller route declarations will automatically be prefixed with this namespace.
*
* #var string|null
*/
// protected $namespace = 'App\\Http\\Controllers';
Uncomment line
protected $namespace = 'App\\Http\\Controllers';
That should help you run Laravel the old-fashioned way.
In case you are upgrading from lower versions of Laravel to 8 then you might have to implicitly add line
protected $namespace = 'App\\Http\\Controllers';
in the RouteServices.php file for it to function the old way.
Ensure you're using the correct name of the file in your route.
For example:
If your controller file was named User.php, make that you're referencing it with User and not UserController.
In Laravel 9, there isn't any need to add a namespace in RouteServiceProvider.
Instead of
Route::resource('tickets', 'TicketController');
use
Route::resource('tickets', TicketController::class);
I tried everything, didn't work, until I tried this 2nd time
restart server
php artisan cache:clear
php artisan optimize
php artisan route:list
In case if you prefer grouping of these routes, you can do it as:
Route::group(['namespace' => 'App\Http\Controllers\Api'], function () {
Route::resource('user', 'UserController');
Route::resource('book', 'BookController');
});
I faced the same error when running php artisan route:list. In my case I had deleted the recourse controller yet the route was still defined. I had to make sure the class in question was commented off in my routes/web.php.
In Laravel 8 the way routes are specified has changed:
Route::resource('homes', HomeController::class)->names('home.index');
I had this error:
(Illuminate\Contracts\Container\BindingResolutionException
Target class [App\Http\Controllers\ControllerFileName] does not exist.
Solution:
Just check your class name. It should be the exact same of your file name.
It happened to me when I was passing null to the middleware function:
Route::middleware(null)->group(function () {
Route::get('/some-path', [SomeController::class, 'search']);
});
Passing [] for no middleware works. Or probably just remove the middleware call if not using middleware :D
In the app/Providers folder, file RouteServiceProvider.php, change the protected $namespace variable to
protected $namespace = 'App\\Http\\Controllers';
This will auto-comment the variable on save.

Use Auth facade in API routes (Laravel 8)

I am looking to use Auth::user() in the CompanyController sitting in the api.php route file in Laravel 8. Like
Route::get('team', [CompanyController::class, 'index']);
But if I do so, I won't be able to access Auth in the following code in the CompanyController file.
use Illuminate\Support\Facades\Auth;
public function index(Request $request)
{
/**
* Role 1 => admin, 2 => hr, 3=> member
*/
if (Auth::user()->role <= 2) {
return ['company' => Auth::user()->company, 'team' => Auth::user()->company->users];
}
}
So what I have done now to achieve what I need is prefix api to the routes sitting in the web.php route file instead.
Route::prefix('api')->group(function () {
Route::get('team', [CompanyController::class, 'index']);
}
After googling around, I am more or less aware that Laravel Sanctum may solve the issue, and it's happened because of the Token driver used in the Api routes. But I'm wondering if there is any easy alternative solution for this. It looks like it would take a while to customise the login page with Sanctum.
What I want is still to take advantage of the initial login page set up with the Breeze starter kit. At the same time, after the user logs in, they can get access to Auth.
if (Auth::user()->role <= 2) {
Here you assume that the user is authenticated and you need to put this route with the authentication middleware. For example:
Route::get('team', [CompanyController::class, 'index'])->middleware('auth');
If you will use Laravel Sanctum, you need to protect routes (only if really needed)
Route::get('team', [CompanyController::class, 'index'])->middleware('auth:sanctum');
Documentation:
Laravel Middleware
Laravel Sanctum

Change LogIn route

I am working in Laravel auth application and when my user is log out I want to redirect it to custom static page and from there I want to redirect to login page again by clicking button on that page.
For example when user is trying to access some particular route, and he is unauthorized then I want to redirect with satatic.blade.php and from there I want to redirect it to log in page, How can I make it happen?
As you didn't mention which Laravel version you are using and which scaffolding you are using, I am assuming you are using Laravel 5.5/6 with LaravelUI/default auth scaffolding.
You should have App\\Http\\Controllers\\Auth namespace where you kept all auth related controller.
You should have one LoginController.php which contains all default login behavior inside AuthenticatesUsers trait. We should override the login method inside our controller.
Copy this code to your LoginController class to do so.
public function login(Request $request)
{
$this->validateLogin($request);
if (method_exists($this, 'hasTooManyLoginAttempts') &&
$this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
// Here is our custom logic check occurs before login
if ($this->userIsnotAuthorized()) { // All your logic checks are inside 'userIsnotAuthorized()' method. Use any function or static check here
return redirect()->to('/static/page'); // Also can use route name / url
}
if ($this->attemptLogin($request)) {
return $this->sendLoginResponse($request);
}
$this->incrementLoginAttempts($request);
return $this->sendFailedLoginResponse($request);
}
EDIT #1
If you want to have the same check for all protected routes, you should generate a middleware with php artisan make:middleware CheckResourceAccessMiddleware and use the same in your route.
In CheckResourceAccessMiddleware's handle method
// Here is our custom logic check occurs before login
if ($this->userIsnotAuthorized()) { // All your logic checks are inside 'userIsnotAuthorized()' method. Use any function or static check here
return redirect()->to('/static/page'); // redirect to static page which indicates unauthorized user note
}
return $next($request); // proceed to your page as user is authorized
to register the middleware edit your app/Http/Kernel.php and add this line to $routeMiddleware array
protected $routeMiddleware = [
...
'resource_access' => \App\Http\Middleware\CheckResourceAccessMiddleware::class,
];
After this step., you can use the middleware in any routes you want to protect
Route::get('/protected', [Controller::class, 'method'])->middleware('resource_access');
OR
// Middleware will be applied to all routes inside it
Route::middleware('resource_access')->group(function () {
Route::get('/protected', [Controller::class, 'method']);
// all other protected routes will be here
});
I found different approaches for this problem, Later I Found the best solution, as mention below,
In App\Middlewear\Authenticate.php, I have to change from return route('login');
to return route('my_custom_page_route');
From my custom page I can redirect it to auth login page easily.
Thank you everyone who suggest the best solutions.

Passing two models to the Authorize middleware (also called can)

I am trying to pass two models to the Authorize middleware, used under the name can.
routes/api.php
Route::middleware('can:reach,profile,photo')->resource('users/{user}/profiles/{profile}/photos', 'PhotoController');
Then I try to retrieve arguments like so:
app/Policies/PhotoPolicy.php
public function reach(User $user, Profile $profile, Photo $photo)
{
return $profile->id === $photo->profile->id;
}
But the middleware is totally ignored. I checked the definition of the middleware and I cannot see why this would not work.
Thanks in advance.
I think you have to add the middleware to the resource, not the opposite. Or, you can create a group.
Example:
Route::group(['middleware' => 'can:reach,profile,photo'], function($router){
$router->resource('users/{user}/profiles/{profile}/photos', 'PhotoController');
});

Resources