Display list and details using separate controllers in Laravel - laravel

I'm using the following two routes in my app, but they are failing. (only one works when I switch the positions). Notice that I'm using two separate controllers. What's the correct way of specifying routes for a scenario like this?
Route::controller('schedulers', 'SchedulersController', [
'getIndex' => 'schedulers.index',
'getUpdate' => 'schedulers.edit'
]);
Route::controller('schedulers/{schedulerId}', 'ReportsController', [
'getIndex' => 'schedulers.reports',
]);

You can add route prefix
Example :
Route::group(['prefix' => 'schedulers'], function() {
Route::controller('/{schedulerId}', 'ReportersController', [
'getIndex' => 'schedulers.reports',
]);
Route::controller('/', 'SchedulersController', [
'getIndex' => 'schedulers.index',
'getUpdate' => 'schedulers.edit'
]);
});

Try to user resource (routes.php):
Route::resource('schedulers', SchedulersController::class);
After this create SchedulersController with two methods: show, index:
<?php
namespace App\Http\Controllers;
class SchedulersController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
//
}
/**
* Display the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function show($id)
{
//
}
}
schedulers => SchedulersController::index
schedulers/1 => SchedulersController::show

Related

Laravel validation "Present" does not work

I have created a FormRequest for updating a BlogPost as UpdateBlogRequest.
I set thumbnail as a "present" for validation. but when this input is empty I get "The thumbnail field must be present."
Also I added input file with thumbnail name in HTML form.
UpdateBlogRequest:
<?php
namespace App\Http\Requests\Blog;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class UpdateBlogRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array<string, mixed>
*/
public function rules()
{
return [
'name' => [
'required',
Rule::unique('blogs', 'name')->ignore($this->blog),
],
'body' => ['required'],
'excerpt' => ['present'],
'thumbnail' => ['present'],
];
}
}
I expected does not show error message for thumbnail when is empty

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

Validating Nest JSON with Parameters

I am trying to validate a nested JSON object in Laravel. I have created a custom rule to do this however I have an issue currently, I want to be able to pass the object at the current array index to my custom validator:
<?php
namespace App\Http\Requests\App;
use App\Rules\CheckoutDepatureCheck;
use App\Rules\SeatIsAvailable;
use Illuminate\Foundation\Http\FormRequest;
class CheckoutRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
"company" => "required",
"seats" => "required|array",
"seats.*.seat_no" => ['required', new SeatIsAvailable()], // would like to pass seat.* to the constructor of my custom validator here
"seats.*.schedule_id" => "required|numeric",
"seats.*.date" => "required|date"
];
}
}
The point for this is my custom validator needs schedule_id and data as well as the seat_no to successfully validate the request.
How do I do this in Laravel?
You can dynamically add rules depending on the length of the seats' array input
<?php
namespace App\Http\Requests\App;
use App\Rules\CheckoutDepatureCheck;
use App\Rules\SeatIsAvailable;
use Illuminate\Foundation\Http\FormRequest;
class CheckoutRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
$rules = [
'company' => 'required',
'seats' => 'required|array',
];
return array_merge($rules, $this->seatsRules());
}
private function seatsRules(): array
{
$rules = [];
foreach ((array) $this->request->get('seats') as $key => $seat) {
$rules["seats.$key.seat_no"] = ['required', new SeatIsAvailable($seat)];
$rules["seats.$key.schedule_id"] = 'required|numeric';
$rules["seats.$key.date"] = 'required|date';
}
return $rules;
}
}

Need help fixing a Laravel PageController class error

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.

How can i solve this error "Too few arguments to function App\Http\Controllers\CtnController::show(), 0 passed and exactly 1 expected"

I have reviewed similar questions but none of the solutions worked for me. I have show view that fetches data from the db which I want to display. I believe I have the right code for my show function on my CtnController but I keep getting this frustrating error. Ctn in this case is a type of form I'm trying to create.
This is my controller.
<?php
namespace App\Http\Controllers;
use App\Ctn;
use Illuminate\Http\Request;
class CtnController extends Controller
{
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
$ctns = Ctn::orderBy('created_at', 'desc')->paginate(5);
return view('/ctn.index')->with('ctns', $ctns);
}
public function create(){
return view('/ctn.create');
}
public function store(Request $request){
$validatedData = $request -> validate([
'bol' => 'required',
'carrier' => 'required',
'address' => 'required',
'etd' => 'required',
'eta' => 'required',
'portload' => 'required',
'portdischarge' => 'required',
]);
$ctn = new Ctn;
$ctn->bill_landing = request('bol');
$ctn->carrier = request('carrier');
$ctn->address = request('address');
$ctn->eta = request('eta');
$ctn->etd = request('etd');
$ctn->incoterm = request('incoterm');
$ctn->forwarder = request('forwarder');
$ctn->ctnref = request('ctnref');
$ctn->portloading = request('portload');
$ctn->portdischarge = request('portdischarge');
$ctn->quantity = request('quantity');
$ctn->origin_goods = request('origin');
$ctn->cost_goods = request('cost');
$ctn->currency = request('currency');
$ctn->package_type = request('package');
$ctn->save();
return redirect('/ctn')->with('success', 'CTN created');
}
/**
* Display the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function show($id)
{
$ctn = Ctn::find($id);
return view('/ctn.show', compact('ctn'));
}
}
Below is my show route on web.php file
Route::get('/ctn/show', 'CtnController#show')->name('show');
The show form is just a HTML form.
Your show() method excepts an $id, however, you've not specified the value in your route. Change your route definition so that is can accept the id:
Route::get('/ctn/show/{id}', 'CtnController#show')->name('show');
This will assume that you're using a url like:
http://example.com/ctn/show/1
For more information you can view the Route Parameters documentation
The $id argument of your show method expects an implicit binding from the route parameters, but your routes does not know any id parameter, therefore it can't be bound to your method.

Resources