Laravel Resource Routing not showing anything when directly call method - laravel

I am stuck in resource routing
when I enter url netbilling.test/customer it goes to customer index file but when I enter url netbilling.test/customer/index nothing is returned. Also guide me if I have to route different method than in resource what is the method for that.
here is my web.php,
Route::get('/dashboard', function () {
return view('dashboard/index');
});
Route::resource('/customer','CustomerController');
here is my customer controller :
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Customer;
use App\Package;
use Redirect,Response;
class CustomerController extends Controller
{
public function index()
{
$packages = Package::get();
$customers = Customer::orderBy('id', 'DESC')->get();
return view('customer/index', compact('customers','packages'));
}
public function create()
{
//
}
public function store(Request $request)
{
//
}
public function show($id)
{
//
}
public function edit($id)
{
//
}
public function update(Request $request, $id)
{
//
}
public function destroy($id)
{
}
}

Without custom route specification, this is how the index route maps to a Resource Controller, taken from Actions Handled By Resource Controller:
Verb
URI
Action
Route Name
GET
/photos
index
photos.index
So if you want URI /customer/index to work, then you need to specify this explicitly in your Controller:
use App\Http\Controllers\CustomerController;
Route::resource('customer', CustomerController::class);
Route::get('customer/index', [CustomerController::class, 'index'])->name(customer.index);

Related

How to read data from Controller action redirect?

The docs show how to redirect to a controller action:
return redirect()->action(
[HomeController::class, 'index'], ['id' => 1]
);
but how do I read the id parameter inside HomeController?
These don't seem to work:
1
class HomeController extends Controller
{
public function index(Request $request)
{
dd($request);
}
}
2
class HomeController extends Controller
{
public function index($id)
{
dd($id);
}
}
3
class HomeController extends Controller
{
public function index(Action $id)
{
dd($id);
}
}
class HomeController extends Controller
{
public function index(Request $request, $id)
{
dd($id);
}
public function update(Request $request, $id)
{
//Do something
return redirect()->action(
[HomeController::class, 'index'], ['id' => 1]
);
}
}
In web.php
use App\Http\Controllers\HomeController;
Route::get('/{id}', [HomeController::class, 'index']);
If your route doesn't take a route parameter then calling action will append id as a query string parameter. This would be an input on the request which you can access via the Request object as an input:
$request->input('id')

Laravel route model binding without global scope

I have following route group in my laravel 8.0 app:
Route::prefix('offline_transaction')->name('offline_transaction.')->group(function () {
Route::post('/approve/{transaction:uuid}', [OfflineTransactionController::class, 'approve'])
->name('approve');
Route::post('/reject/{transaction:uuid}', [OfflineTransactionController::class, 'reject'])
->name('reject');
});
And Transaction model is:
class Transaction extends Model implements CreditBlocker
{
//....
protected static function boot()
{
parent::boot();
static::addGlobalScope(new AuthUserScope());
}
//....
}
And this is my AuthUserScope:
class AuthUserScope implements Scope
{
private string $fieldName;
public function __construct($fieldName = 'user_id')
{
$this->fieldName = $fieldName;
}
public function apply(Builder $builder, Model $model)
{
$user = Auth::user();
if ($user) {
$builder->where($this->fieldName, $user->id);
}
}
}
Now the problem is when an admin wants to approve or reject a transaction, 404 Not found error will throws. How can I pass this?
Customizing The Resolution Logic
If you wish to define your own model binding resolution logic, you may
use the Route::bind method. The closure you pass to the bind
method will receive the value of the URI segment and should return the
instance of the class that should be injected into the route. Again,
this customization should take place in the boot method of your
application's RouteServiceProvider:
Solution
What you can do is change the parameter name(s) in your routes/web.php file for the specific route(s).
Route::prefix('offline_transaction')->name('offline_transaction.')->group(function () {
Route::post('/approve/{any_transaction}', [OfflineTransactionController::class, 'approve'])
->name('approve');
Route::post('/reject/{any_transaction}', [OfflineTransactionController::class, 'reject'])
->name('reject');
Note the any_transaction. Change that to whatever naming convention you find most convenient.
Then, in your app/Providers/RouteServiceProvider.php file, change your boot(...) method to something like this:
use App\Models\Transaction;
use Illuminate\Support\Facades\Route;
// ...
public function boot()
{
// ...
Route::bind('any_transaction', function($uuid) {
return Transaction::withoutGlobalScopes()->where('uuid', $uuid)->firstOrFail();
});
// ...
}
// ...
Then in your controller app/Http/Controllers/OfflineTransactionController.php file, access the injected model:
use App\Models\Transaction;
// ...
public function approve(Transaction $any_transaction) {
// ...
}
// ...
Credits: Using Route Model Binding without Global Scope #thomaskim
Addendum
If you would like to remove a specific global scope from the route model bound query, you may use
withoutGlobalScope(AuthUserScope::class) in the boot(...) method of the app/Providers/RouteServiceProvider.php file.
Another approach is that I can use Route::currentRouteNamed in AuthUserScope class as following, which I prefer to use instead of Route::bind:
<?php
namespace App\Scopes;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Route;
class AuthUserScope implements Scope
{
private string $fieldName;
public function __construct($fieldName = 'user_id')
{
$this->fieldName = $fieldName;
}
public function apply(Builder $builder, Model $model)
{
$user = Auth::user();
if ($user && !Route::currentRouteNamed('admin.*')) {
$builder->where($this->fieldName, $user->id);
}
}
}

Laravel authorization policy not working on Show page

I have a laravel app using Policies to assign roles and permissions, i cant seem to access the show page and im not sure what im doing wrong?
If i set return true it still shows a 403 error as well, so im unsure where im going wrong here. The index page is accessable but the show page is not?
UserPolicy
public function viewAny(User $user)
{
if ($user->isSuperAdmin() || $user->hasPermissionTo(44, 'web')) {
return true;
}
return false;
}
public function view(User $user, User $model)
{
if ($user->isSuperAdmin() || $user->hasPermissionTo(44, 'web')) {
return true;
}
return false;
}
UserController
public function __construct()
{
$this->authorizeResource(User::class, 'user');
}
public function index()
{
$page_title = 'Users';
$page_description = 'User Profiles';
$users = User::all();
return view('pages.users.users.index', compact('page_title', 'page_description', 'users'));
}
public function create()
{
//
}
public function store(Request $request)
{
//
}
public function show($id)
{
$user = User::findOrFail($id);
$user_roles = $user->getRoleNames()->toArray();
return view('pages.users.users.show', compact('user', 'user_roles'));
}
Base on Authorize Resource and Resource Controller documentation.
You should run php artisan make:policy UserPolicy --model=User. This allows the policy to navigate within the model.
When you use the authorizeResource() function you should implement your condition in the middleware like:
// For Index
Route::get('/users', [UserController::class, 'index'])->middleware('can:viewAny,user');
// For View
Route::get('/users/{user}', [UserController::class, 'view'])->middleware('can:view,user');
or you can also use one policy for both view and index on your controller.
I had an issue with authorizeResource function.
I stuck on failed auth policy error:
This action is unauthorized.
The problem was that I named controller resource/request param with different name than its model class name.
F. ex. my model class name is Acknowledge , but I named param as timelineAcknowledge
Laravel writes in its documentation that
The authorizeResource method accepts the model's class name as its first argument, and the name of the route / request parameter that will contain the model's ID as its second argument
So the second argument had to be request parameter name.
// Here request param name is timelineAcknowledge
public function show(Acknowledge $timelineAcknowledge)
{
return $timelineAcknowledge->toArray();
}
// So I used this naming here also
public function __construct()
{
$this->authorizeResource(Acknowledge::class, 'timelineAcknowledge');
}
Solution was to name request param to the same name as its model class name.
Fixed code example
// I changed param name to the same as its model name
public function show(Acknowledge $acknowledge)
{
return $acknowledge->toArray();
}
// Changed here also
public function __construct()
{
$this->authorizeResource(Acknowledge::class, 'acknowledge');
}
I looked over Laravel policy auth code and I saw that the code actually expects the name to be as the model class name, but I couldn't find it anywhere mentioned in Laravel docs.
Of course in most of the cases request param name is the same as model class name, but I had a different case.
Hope it might help for someone.

Passing Data in Login and Register Page Laravel 6

I create login and register function in Laravel 6 with scaffold function, and i got this LoginController:
<?php
...
...
class LoginController extends Controller
{
use AuthenticatesUsers;
protected $redirectTo = RouteServiceProvider::HOME;
public function __construct()
{
$this->middleware('guest')->except('logout');
}
}
I want to pass a data DB::table('terms_condition')->get() to login view, how should i do?
Put this method in LoginController
public function showLoginForm()
{
$terms_condition = DB::table('terms_condition')->get();
return view('auth.login',compact('terms_condition'));
}
showLoginForm() is from AuthenticatesUsers trait which is used by your LoginController. You have to put this method in LoginController.
Inside your login controller rewrite the function showLoginform
public function showLoginForm()
{
` $data = DB::table('terms_condition')->get();
return view('frontend.auth.login',compact('data'));
}
Or From your LoginController you can see that AuthenticateUsers
go to the Authenticate Users file and edit the showLoginForm as like this
public function showLoginForm()
{
` $data = DB::table('terms_condition')->get();
return view('frontend.auth.login',compact('data'));
}
And dont forget to use DB in the top
You can override the built-in showLoginForm() method in the LoginController
LoginController.php
use Illuminate\Support\Facades\DB;
class LoginController extends Controller
{
use AuthenticatesUsers;
protected $redirectTo = RouteServiceProvider::HOME;
public function __construct()
{
$this->middleware('guest')->except('logout');
}
public function showLoginForm()
{
return view('admin.login',['terms'=>DB::table('terms_condition')->get()]); //pass your data here as a second argument
}
}
You can then access this in your blade view as $terms
A different way to go about it: use a View Composer. This will run when the view is rendered so you can pass data to it this way:
view()->composer('auth.login', function ($view) {
$view->with('something', DB::table(...)->get());
});
// or View::composer(...) if you prefer
You can add that at a Service Provider's boot method. No overriding anything.
Laravel 6.x Docs - Views - View Composers View::composer()

Laravel middleware redirection

when i use laravel middleware its routes is not work properly
<?php
namespace App\Http\Controllers;
use Auth;
use App\Article;
use App\Http\Requests;
use Illuminate\Http\Request;
use App\Http\Requests\ArticleRequest;
use App\Http\Controllers\Controller;
use Carbon\Carbon;
//use Illuminate\Http\Request;
class ArticlesController extends Controller
{
public function __construct(){
$this->middleware('auth',['only'=>'create']);
}
//
public function index(){
//return \Auth::user();
$articles = Article::latest('published_at')->published()->get();
return view('articles.index',compact('articles'));
}
public function show($id){
$article = Article::findorFail($id);
//dd($article->published_at->addDays(8)->diffForHumans());
return view('articles.show',compact('article'));
}
public function create(){
if(Auth::guest()){
return redirect('articles');
}
return view('articles.create');
}
public function store(ArticleRequest $request){
/*
$input = Request::all();
$input['published_at'] = Carbon::now();
*/
$article = new Article($request->all());
Auth::user()->articles()->save($article);
//Article::create($request->all());
return redirect('articles');
}
public function edit($id){
$article = Article::findorFail($id);
return view('articles.edit', compact('article'));
}
public function update($id, ArticleRequest $request){
$article = Article::findorFail($id);
$article->update($request->all());
return redirect('articles');
}
}
when i go to http://localhost/lernlaravel/public/articles/create it works fine
but when i go to http://localhost/learnlaravel/public/articles it redirect to http://localhost/articles.
index() method is used for listing articles how i can fix it?
The redirect () accepts a URL path so if you want ensure your redirect will work on both testing and production environments, I would pass either action () or route () to all of your applications redirect calls. In your this case I would go with
return redirect(action ('ArticlesController#show', $articles->id));
This way Laravel will automatically generate the proper URL path to the controller you want to handle the request.
If you choose to go with route() you are required to have named the route in your routes file, but I find that with resourceful controllers it's less complicated to go with action.

Resources