Need help fixing a Laravel PageController class error - laravel

Whenever I try to click a button on localhost site such as the manage users
I get the error:
Target class
[App\Http\Controllers\App\Http\Controllers\Admin\PagesController] does
not exist.
I tried a lot of different things to try fix it and I just don't know how to fix it. I asked on forums like this too and I none of the suggestions I was given helped.
Here is the code for my page controller:
<?php
namespace App\Http\Controllers\Admin;
use Auth;
use App\Http\Controllers\Controller;
use App\Http\Requests\WorkWithPage;
use App\Models\Page;
use Illuminate\Http\Request;
class PagesController extends Controller
{
public function __construct() {
$this->middleware('admin');
}
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
if (Auth::user()->isAdminOrUser()) {
$pages = Page::paginate(5);
} else {
$pages = Auth::user()->pages()->paginate(5);
}
return view('admin.pages.index', ['pages' => $pages]);
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create()
{
//
return view('admin.pages.create')->with(['model' => new Page()]);
}
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(WorkWithPage $request)
{
//
Auth::user()->pages()->save(new Page($request->only([
'title','url','content'])));
return redirect()->route('pages.index')->with('status', 'The page has been created.');
}
/**
* Show the form for editing the specified resource.
*
* #param \App\Models\Page $page
* #return \Illuminate\Http\Response
*/
public function edit(Page $page)
{
if(Auth::user()->cant('update', $page)) {
return redirect()->route('pages.index');
}
return view('admin.pages.edit', ['model' => $page]);
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param \App\Models\Page $page
* #return \Illuminate\Http\Response
*/
public function update(WorkWithPage $request, Page $page)
{
if(Auth::user()->cant('update', $page)) {
return redirect()->route('pages.index');
}
$page->fill($request->only([
'title','url','content']));
$page->save();
return redirect()->route('pages.index')->with('status', 'The page has been updated');
}
/**
* Remove the specified resource from storage.
*
* #param \App\Models\Page $page
* #return \Illuminate\Http\Response
*/
public function destroy(Page $page)
{
if(Auth::user()->cant('delete', $page)) {
return redirect()->route('pages.index');
}
}
}
Here is the code for my web.php route:
<?php
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/', function () {
return view('welcome');
});
Auth::routes();
Route::get('/admin', function() {
return view('admin.index');
})->middleware('admin');
Route::resource('/admin/pages', \App\Http\Controllers\Admin\PagesController::class, ['except' => [
'show'
]]);
Route::resource('/admin/users', \App\Http\Controllers\Admin\UsersController::class, ['except' => [
'create','store','show'
]]);
Route::get('/home', 'HomeController#index')->name('home');
Route::get('/home', 'HomeController#index')->name('home');

Add the controllers at the beginning of your web.php routes file
use App\Http\Controllers\Admin\PagesController;
use App\Http\Controllers\Admin\UsersController;
Then define your route as
Route::prefix('admin')->group(function () {
Route::resource('pages', PagesController::class);
Route::resource('users', UsersController::class);
});

Maybe the error is because you forgot to put [] when calling your controller.
Modify this:
Route::resource('/admin/pages', \App\Http\Controllers\Admin\PagesController::class, ['except' => [
'show'
]]);
Route::resource('/admin/users', \App\Http\Controllers\Admin\UsersController::class, ['except' => [
'create','store','show'
]]);
by:
Route::resource('/admin/pages', [\App\Http\Controllers\Admin\PagesController::class], ['except' => [
'show'
]]);
Route::resource('/admin/users', [\App\Http\Controllers\Admin\UsersController::class], ['except' => [
'create','store','show'
]]);

You have to go into your the app/Providers/RouteServiceProvider.php file and comment this line:
protected $namespace = 'App\\Http\\Controllers';
//should be
//protected $namespace = 'App\\Http\\Controllers';
If you do so, you'll be able to use this notation your are using when declaring your routes:
Route::get('something', [\Fully\Qualified\Namespace::class, 'method']);
However, these kind of routes, will not work anymore:
Route::get('/home', 'HomeController#index')->name('home');
// since there are no more default namespace, you must use
// Route::get('/home', '\App\Http\Controllers\HomeController#index');
// or
// Route::get('/home', [\App\Http\Controllers\HomeController::class, 'index']);
You have to choose which route declaration style you use and stick to it for all routes.
Nowadays, Route::get('something', [\Fully\Qualified\Namespace::class, 'method']) is what you should use.

Related

Laravel: How do I raise a 404 error instead of a 50X error when ID for resource is non-integer

I created a simple crud in Laravel, but I'm having a problem:
I am using Illuminate\Support\Facades\Route::resource method, this is my routes/web.php:
<?php
use Illuminate\Foundation\Application;
use Illuminate\Support\Facades\Route;
use Inertia\Inertia;
Route::get('/', function () {
return Inertia::render('Welcome', [
'canLogin' => Route::has('login'),
'canRegister' => Route::has('register'),
'laravelVersion' => Application::VERSION,
'phpVersion' => PHP_VERSION,
]);
});
Route::get('dashboard', [App\Http\Controllers\PageController::class, 'dashboard'])
->middleware('auth:sanctum')
->name('dashboard');
Route::resource('notes', App\Http\Controllers\NoteController::class)
->middleware('auth:sanctum');
app/Http/Controllers/NoteController.php:
<?php
namespace App\Http\Controllers;
use App\Models\Note;
use Illuminate\Http\Request;
use Inertia\Inertia;
class NoteController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index(Request $request)
{
if ($request->q) {
return Inertia::render('Notes/Index', [
'notes' => Note::where('title', 'ilike', "%$request->q%")->get(),
]);
}
return Inertia::render('Notes/Index', [
'notes' => Note::all()
]);
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create()
{
return Inertia::render('Notes/Create', [
'note' => new Note()
]);
}
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$note = Note::create($request->validate([
'title' => 'required',
'content' => 'required',
]));
return redirect()->route('notes.show', $note)->with('success', 'Nota creada');
}
/**
* Display the specified resource.
*
* #param \App\Models\Note $note
* #return \Illuminate\Http\Response
*/
public function show(Note $note)
{
return Inertia::render('Notes/Show', compact('note'));
}
/**
* Show the form for editing the specified resource.
*
* #param \App\Models\Note $note
* #return \Illuminate\Http\Response
*/
public function edit(Note $note)
{
return Inertia::render('Notes/Edit', compact('note'));
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param \App\Models\Note $note
* #return \Illuminate\Http\Response
*/
public function update(Request $request, Note $note)
{
$request->validate([
'title' => 'required',
'content' => 'required',
]);
$note->update($request->all());
return redirect()->route('notes.show', $note)->with('success', 'Nota actualizada');
}
/**
* Remove the specified resource from storage.
*
* #param \App\Models\Note $note
* #return \Illuminate\Http\Response
*/
public function destroy(Note $note)
{
$note->delete();
return redirect()->route('notes.index')->with('success', 'Nota eliminada');
}
}
When I go to /notes/a where 'a' is supposed to be the index of the note I want to see, I get a 500 error:
SQLSTATE[22P02]: Invalid text representation: 7 ERROR: invalid input syntax for type bigint: "a"
select * from "notes" where "id" = a limit 1
At this point, none of my code has yet run. How can I catch this error to raise a 404 error instead?
you can use firstOrFail() or findOrFail example code below
public function find(Request $request){
return Note::findOrFail($request->id);
}
You can use abort(404) which abort your code if no data found.
public function findNote($id)
{
$note = Note::find($id)
if($note == null)
{
abort(404);
}
}
you can use try catch block to modify the response
public function whatEverMyMethodIs( Request $request ) {
try {
return ModeL::find( $request->input('id') );
} catch (\Throwable $th) {
return response()->json(['message' => $th->getMessage()], 404 );
}
}
Since you're using the built-in resource controller, the following URIs, among others, will have been created and model binding happens. If the parameter doesn't fit the id's type it will error out.
GET /notes/{note}
GET /notes/{note}/edit
I have not found a way to modify the request validation when model binding happens. If you wish to customise the behaviour, you can do so by leaving the show and edit functions out of the route resource declaration and writing custom endpoints listed above.
routes/web.php
Route::resource('notes', NoteController::class)->except([
'show', 'edit'
]);
Route::get('/notes/{note}', [
'as' => 'notes.show',
'uses' => '\App\Http\Controllers\NoteController#show',
]);
app/Http/Controllers/NoteController.php
use Illuminate\Http\Request;
...
public function show(Request $request)
{
$noteId = $request->note;
...
}
You can perform the validation by switching Request to a custom request which inherits FormRequest.
More information can be found here:
https://laravel.com/docs/9.x/validation#form-request-validation

How do I fix the Laravel page not found error?

After registering, it redirects to / home. But I get a 404 error. When I set the route to / home, I get 302 continuous routing errors.
RegisterController.php
use RegistersUsers;
protected $redirectTo = '/';
public function __construct()
{
$this->middleware('guest');
}
Route.php
Auth::routes(['verify' => true]);
Route::get('/', 'HomeController#index')->name('home');
HomeController
class HomeController extends Controller
{
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('guest');
}
/**
* Show the application dashboard.
*
* #return \Illuminate\Contracts\Support\Renderable
*/
public function index()
{
return view('home');
}
}
if you have in your HomeController's construct a middleware that requires the user to be logged in then what you are getting is normal.
You should have a login page wich use the "guest" middleware.
or
login the user automatically once he registers before redirecting him to your home route.
Auth::login($user)
//or
Auth::loginUsingId($userId);
Remove guest middleware.
public function __construct()
{
$this->middleware('guest');
}
Your HomeController should look like
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class HomeController extends Controller
{
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Show the application dashboard.
*
* #return \Illuminate\Contracts\Support\Renderable
*/
public function index()
{
return view('home');
}
}
your route.php Look like
Route::get('/', function () {
return view('welcome');
});
Auth::routes();
Route::get('/home', 'HomeController#index')->name('home');
RegisterController should look like
namespace App\Http\Controllers\Auth;
use App\User;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Foundation\Auth\RegistersUsers;
class RegisterController extends Controller
{
/*
|--------------------------------------------------------------------------
| Register Controller
|--------------------------------------------------------------------------
|
| This controller handles the registration of new users as well as their
| validation and creation. By default this controller uses a trait to
| provide this functionality without requiring any additional code.
|
*/
use RegistersUsers;
/**
* Where to redirect users after registration.
*
* #var string
*/
protected $redirectTo = '/home';
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('guest');
}
/**
* Get a validator for an incoming registration request.
*
* #param array $data
* #return \Illuminate\Contracts\Validation\Validator
*/
protected function validator(array $data)
{
return Validator::make($data, [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
'password' => ['required', 'string', 'min:8', 'confirmed'],
]);
}
/**
* Create a new user instance after a valid registration.
*
* #param array $data
* #return \App\User
*/
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => Hash::make($data['password']),
]);
}
}
make sure you're following laravel authentication.

Pass parameter to Laravel Middleware

How can I passed a parameter in my middleware? I'm always getting this error
Here are the structure of my middlware
<?php
namespace App\Http\Middleware;
use Closure;
class SubDomainAccess
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next, $subdomain)
{
dd($subdomain); // Just trying to output the result here
return $next($request);
}
}
And on the Kernel.php under the $routeMiddleware I added this
'subdomain.access' => \App\Http\Middleware\SubDomainAccess::class,
Now on my web.php route file I added this
Route::group(['domain' => '{subdomain}.' . config('site.domain')], function () {
Route::get('/', ['as' => 'site.home', 'uses' => 'Site\Listing\ListingController#showListing'])->middleware('subdomain.access');
});
Also I tried this
Route::group(['domain' => '{subdomain}.' . config('site.domain')], function () {
Route::group(['middleware' => 'subdomain.access'], function () {
Route::get('/', ['as' => 'site.home', 'uses' => 'Site\Listing\ListingController#showListing']);
});
});
I tried this but nothings working. The only thing I haven't tried is placing the middleware in my controller constructor. But I don't wan't it that way as I think this is messy and it's more elegant if its within the route file.
Hope you can help me on this. Thanks
Ok so I managed to find a way to get the parameters without passing a third parameter on the middleware handle function thanks to this link
So what I did to retrieve the subdomain parameter is this
$request->route()->parameter('subdomain')
or if all parameter
$request->route()->parameters()
['middleware' => 'subdomain.access'] is wrong, try to use ['middleware' => 'subdomain:access'] with a : instead.
https://mattstauffer.co/blog/passing-parameters-to-middleware-in-laravel-5.1
Get URI from $request object and then return domain. No need to pass subdomain as params to middleware.
namespace App\Http\Middleware;
use Closure;
class SubDomainAccess
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next, $subdomain)
{
$sudomain = $this->getSubDomain($_SERVER['HTTP_HOST']);
return $next($request);
}
/**
* Get Subdomain name
* #param $uri
* #return bool
*/
private function getSubDomain($uri)
{
if(!empty($uri))
{
$host = explode('.', $uri);
if(sizeof($host) > 2)
return $host[0];
}
return false;
}
}

Session in middleware don't working

I'm storing a value in session in my middleware:
but when I refresh or go to new page the sessions is null.
what I do wrong?
class WorkflowContextMiddleware
{
/**
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|mixed
*/
public function handle(Request $request, Closure $next)
{
$types = $request->input('types', []);
foreach ($types as $type => $context) {
$request->session()->put("somekey.contexts.{$type}", $context);
$request->session()->save();
}
return $next($request);
}
}
route:
Route::group([
'prefix' => LaravelLocalisation::setLocale(),
'middleware' => ['web','localise','localeSessionRedirect']
], function () {
Route::get('/', function() {
(new \Illuminate\Support\Debug\Dumper)->dump(\Session::get('somekey'));
});
});
route provider:
class RouteServiceProvider extends ServiceProvider
{
/**
* This namespace is applied to the controller routes in your routes file.
*
* In addition, it is set as the URL generator's root namespace.
*
* #var string
*/
protected $namespace = 'Arcanine\Http\Controllers';
/**
* Define your route model bindings, pattern filters, etc.
*
* #param \Illuminate\Routing\Router $router
* #return void
*/
public function boot(Router $router)
{
//
parent::boot($router);
}
/**
* Define the routes for the application.
*
* #param \Illuminate\Routing\Router $router
* #return void
*/
public function map(Router $router)
{
$router->group(['namespace' => $this->namespace], function ($router) {
require app_path('Http/routes.php');
});
}
}
Kernel.php
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\App\Workflow\Http\Middleware\WorkflowContextMiddleware::class,
],
In order for your session to work, wrap all your routes within:
Route::group(['middleware' => 'web'], function () {
...
});
Remove web middleware from route group if you're using 5.2.27 and higher.
The thing is all routes in web.php are already using web middleware and adding it manually will cause problems with sessions.

Laravel middleware 'except' rule not working

I have a controller with the following in the constructor:
$this->middleware('guest', ['except' =>
[
'logout',
'auth/facebook',
'auth/facebook/callback',
'auth/facebook/unlink'
]
]);
The 'logout' rule (which is there by default) works perfectly but the other 3 rules I have added are ignored. The routes in routes.php look like this:
Route::group(['middleware' => ['web']],function(){
Route::auth();
// Facebook auth
Route::get('/auth/facebook', 'Auth\AuthController#redirectToFacebook')->name('facebook_auth');
Route::get('/auth/facebook/callback', 'Auth\AuthController#handleFacebookCallback')->name('facebook_callback');
Route::get('/auth/facebook/unlink', 'Auth\AuthController#handleFacebookUnlink')->name('facebook_unlink');
}
If I visit auth/facebook, auth/facebook/callback or auth/facebook/unlink whilst logged in I get denied by the middleware and thrown back to the homepage.
I've tried specifying the 'except' rules with proceeding /'s so they match the routes in routes.php exactly but it makes no difference. Any ideas why these rules are being ignored, whilst the default 'logout' rule is respected?
Cheers!
You need to pass the method's name instead of the URI.
<?php
namespace App\Http\Controllers;
class MyController extends Controller {
public function __construct() {
$this->middleware('guest', ['except' => [
'redirectToFacebook', 'handleFacebookCallback', 'handleFacebookUnlink'
]]);
}
}
Since Laravel 5.3, you can use fluent interface to define middlewares on controllers, which seems cleaner than using multidimensional arrays.
<?php
$this->middleware('guest')->except('redirectToFacebook', 'handleFacebookCallback', 'handleFacebookUnlink');
I solved this issue in my Middleware by adding this inExceptArray function. It's the same way VerifyCsrfToken handles the except array.
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class MyMiddleware
{
/**
* Routes that should skip handle.
*
* #var array
*/
protected $except = [
'/some/route',
];
/**
* Determine if the request has a URI that should pass through.
*
* #param Request $request
* #return bool
*/
protected function inExceptArray($request)
{
foreach ($this->except as $except) {
if ($except !== '/') {
$except = trim($except, '/');
}
if ($request->is($except)) {
return true;
}
}
return false;
}
/**
* Handle an incoming request.
*
* #param Request $request
* #param Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
// check user authed or API Key
if (!$this->inExceptArray($request)) {
// Process middleware checks and return if failed...
if (true) {
// Middleware failed, send back response
return response()->json([
'error' => true,
'Message' => 'Failed Middleware check'
]);
}
}
// Middleware passed or in Except array
return $next($request);
}
}
If you are trying to follow the Laravel Documentation, an alternative solution to this is suggested by adding routes to the $except variable in the /Http/Middleware/VerifyCsrfToken.php file. The documentation says to add them like this:
'route/*'
But I found the only way to get it to work is by putting the routes to ignore like this:
'/route'
When assigning middleware to a group of routes, you may occasionally need to prevent the middleware from being applied to an individual route within the group. You may accomplish this using the withoutMiddleware method:
use App\Http\Middleware\CheckAge;
Route::middleware([CheckAge::class])->group(function () {
Route::get('/', function () {
//
});
Route::get('admin/profile', function () {
//
})->withoutMiddleware([CheckAge::class]);
});
for more information read documentation laravel middleware
Use this function in your Controller:
public function __construct()
{
$this->middleware(['auth' => 'verified'])->except("page_name_1", "page_name_2", "page_name_3");
}
*replace page_name_1/2/3 with yours.
For me it's working fine.
I have this solved, and here's what I am doing. Aso, I just realized this is very similar to what cmac did in his answer.
api.php
Route::group(['middleware' => 'auth'], function () {
Route::get('/user', 'Auth\UserController#me')->name('me');
Route::post('logout', 'Auth\LoginController#logout')->name('logout');
});
LoginController.php
class LoginController extends Controller
{
use AuthenticatesUsers, ThrottlesLogins;
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('guest')->except('logout');
}
// ...
/**
* If the user's session is expired, the auth token is already invalidated,
* so we just return success to the client.
*
* This solves the edge case where the user clicks the Logout button as their first
* interaction in a stale session, and allows a clean redirect to the login page.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function logout(Request $request)
{
$user = $this->guard()->user();
if ($user) {
$this->guard()->logout();
JWTAuth::invalidate();
}
return response()->json(['success' => 'Logged out.'], 200);
}
}
Authenticate.php
class Authenticate extends Middleware
{
/**
* Exclude these routes from authentication check.
*
* Note: `$request->is('api/fragment*')` https://laravel.com/docs/7.x/requests
*
* #var array
*/
protected $except = [
'api/logout',
];
/**
* Ensure the user is authenticated.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
try {
foreach ($this->except as $excluded_route) {
if ($request->path() === $excluded_route) {
\Log::debug("Skipping $excluded_route from auth check...");
return $next($request);
}
}
// code below here requires 'auth'
{ catch ($e) {
// ...
}
}
I over-engineered it slightly. Today I only need an exemption on /api/logout, but I set the logic up to quickly add more routes. If you research the VerifyCsrfToken middleware, you'll see it takes a form like this:
protected $except = [
'api/logout',
'api/foobars*',
'stripe/poop',
'https://www.external.com/yolo',
];
That's why I put that "note" in my doc above there. $request->path() === $excluded_route will probably not match api/foobars*, but $request->is('api/foobars*') should. Additionally, a person might be able to use something like $request->url() === $excluded_route to match http://www.external.com/yolo.
You should pass the function name to 'except'.
Here's an example from one of my projects:
$this->middleware('IsAdminOrSupport', ['except' => [
'ProductsByShopPage'
]
]);
This means the middleware 'IsAdminOrSupport' is applied to all methods of this controller except for the method 'ProductByShopPage'.

Resources