Laravel CRUD, Edit and Delete ID Not Found, But ID Exist - laravel

Here is migration.
Schema::create('ruanganjns', function (Blueprint $table) {
$table->increments('id');
$table->string('kode_jenis_ruangan');
$table->string('jenis_ruangan');
$table->date('tgl_berlaku');
$table->string('status');
$table->timestamps();
});
Here is model.
protected $table = 'ruanganjns';
protected $fillable = ['kode_jenis_ruangan','jenis_ruangan','tgl_berlaku','status'];
public $timestamps = true;
public function Ruangan()
{
return $this->HasMany('App\Ruangan','id_ruangan');
}
here is controller edit code.
public function edit(Ruanganjns $ruanganjns)
{
$ruanganjns = Ruanganjns::findOrFail($ruanganjns->id);
return view('ruanganjns.edit', compact('ruanganjns'));
}
here is the route.
here
The main error always comes from an ID not found. even though all of my code is copied and pasted from the first code source, but the first source code all goes well. and the third source code and so on goes well. the source of the problem is always in this second table even i change it name or make it from beginning it's always the same. are there misspellings or case sensitive or something wrong with my code?
this is the result in the web browser
here

Your are trying to implement Implicit model binding but you have some wrong variable name in controller action. It should match with the route placeholder like this
Your route is like this
Route::get('admin/ruangjns/{ruangjn}/edit', 'RuanganjnsController#edit');
Then your controller action code should be like this
public function edit(Ruanganjns $ruangjn) //here $ruangjn should match with route placeholder
{
return view('ruanganjns.edit', compact('ruangjn'));
}
It automatically fetch model record and if record not found then it will return 404 error. For details check the above link

Related

Route model binding with multiple wildcards

How to explicitly say to route model binding to fetch only related categories? I have my web.php file as follows:
Route::get('/catalog/{category}', [CategoryController::class, 'index'])->name('category.index');
Route::get('/catalog/{category}/{subcategory}', [SubcategoryController::class, 'index'])->name('subcategory.index');
Route::get('/catalog/{category}/{subcategory}/{subsubcategory}', [SubsubcategoryController::class, 'index'])->name('subsubcategory.index');
Subsubcategory controller:
public function index(Category $category, Subcategory $subcategory, Subsubcategory $subsubcategory)
{
$subsubcategory->load('product')->loadCount('product');
$products = Product::where('subsubcategory_id', $subsubcategory->id)->orderByRaw('product_order = 0, product_order')->get();
return view('subsubcategory.index', compact('subsubcategory', 'products'));
}
And model in question:
public function subcategory()
{
return $this->belongsTo(Subcategory::class);
}
public function category()
{
return $this->belongsTo(Category::class);
}
public function getRouteKeyName()
{
return 'slug';
}
It works partially ok. It loads all the slugs, but the problem is, let's say I have Samsung Subsubcategory with it's parent categories like:
catalog/mobile-phones/android/samsung
Whenever I modify url from catalog/mobile-phones/android/samsung to catalog/mobile-phones/ios/samsung it works, where in fact it should not. How to handle this second scenario?
PS: it also applies if I open subcategory and change category slug. But, obviously, if upper level category does not exists, it's going to throw 404.
You may want to explore the docs a bit in regard to explicit route model binding and customizing the resolution logic to get some ideas.
https://laravel.com/docs/8.x/routing#customizing-the-resolution-logic
The following is untested and I'm making some guesses about your table structures, but I think this should give you a basic concept of how you can alter route model binding to fit your needs. The same concept could also be applied to the {subcategory} binding, but with one less relationship check.
App/Providers/RouteServiceProvider.php
public function boot()
{
// ...default code...
// add custom resolution for binding 'subsubcategory'
Route::bind('subsubcategory', function($slug, $route) {
// check to see if category exists
if ($category = Category::where('slug',$route->parameter('category'))->first()) {
// check to see if subcategory exists under category
if ($subcategory = $category->subcategories()->where('slug',$route->parameter('subcategory'))->first()) {
// check to see if subsubcategory exists under subcategory
if ($subsubcategory = $subcategory->subsubcategories()->where('slug',$slug)->first()) {
// success, proper relationship exists
return $subsubcategory;
}
}
}
// fail (404) if we get here
throw new ModelNotFoundException();
});
}
I will note, however, that this makes a number of separate database calls. There may be more efficient ways to achieve the same goal through other methods if optimization is a concern.

Laravel 7 resource model binding, no information in the edit page

In Laravel 7 I did the following:
php artisan make:controller ClientGroupController --resource --model=ClientGroup
I modified the edit function in ClientGroupController to look as follows:
public function edit(ClientGroup $clientGroup)
{
return view('extranet.groups.create_modal_form', compact('clientGroup'));
}
I also added this route resource: Route::resource('groups', 'ClientGroupController');
A dd($clientGroup) in the view (when visiting the page http://127.0.0.1:8000/groups/2/edit) yields none of the data for the current record (a blank ClientGroup object).
Did I miss a step? Why does $clientGroup->id return null in my view (id is the primary key of the client_group table).
public function edit($id)
{
$clientGroup = ClientGroup::find($id);
return view('extranet.groups.create_modal_form', compact('clientGroup'));
}
I had a similar problem with resource routes defined like this:
Route::resource('others', OtherServiceController::class);
But my model name was OtherService
This was my edit and update function
public function edit(OtherService $otherService)
{
return view('others.master-edit', compact('otherService'));
}
public function update(OtherServiceRequest $request, OtherService $otherService)
{
$otherService->update($request->validated());
return redirect()->route('others.index')->withToastSuccess('Success Update Data');
}
But this code threw errors about a missing required parameter, because resource name and model name are not the same. So, my solution was to change the resource routes to match the model.
Route::resource('otherService', OtherServiceController::class);
Maybe you can read this question, marked answer tells about overriding

The update nor the destroy methods won't work in laravel eloquent model?

I have a strange situation where eloquent model won't let me update nor destroy while index and create is working fine!
I'm using Vue.js and Laravel API Resource for form control, and while it worked with me before, it won't work here:
Here's my Vue.js Code:
updateFinish(finish) {
axios.patch(`/api/finishes/${finish.id}`, finish).then(response => {
this.fetchFinishes();
}).catch(error => {
// Get laravel validation error
this.errors = error.response.data.errors;
});
},
laravel update code (not working)
public function update(FinishType $finishType)
{
// Don't know why not working
$finishType->update($this->validateRequest());
return new FinishTypeResource($finishType);
}
the response is null:
{"id":null,"name":null}
While this code works:
public function update($id)
{
$finishType = FinishType::find($id);
$validates = $this->validateRequest();
$finishType->name = $validates['name'];
$finishType->save();
return new FinishTypeResource($finishType);
}
public function validateRequest()
{
return request()->validate([
'name' => 'required | unique:finish_types',
]);
}
Note the Model name is FinishType and database table name is finish_types, I even tried to define the table name in the model like so protected $table = 'finish_types' – still not working and I already have defined the $fillable array!!!
Your route model binding is not working correctly, for the implicit binding to work your injected variable should match the route parameter name.
Assuming that your parameter name could be finish (reading the url from your javascript) you have to write the update function using $finish as injected variable, like this:
public function update(FinishType $finish)
{
$finish->update($this->validateRequest());
return new FinishTypeResource($finish);
}
Do the same for destroy():
public function destroy(FinishType $finish)
{
// your destroy code here
}
In any case you can run php artisan route:list to find your parameter name (the part of the URI in braces) and give the same name to the injected variable.
If the two do not match, parameter and injected variable name, laravel injects a void, not loaded, FinishType model so it does not make sense doing an update or a delete on it.
I can't post comments so I'm going to post what I assume is the answer.
Laravel does route model binding automagically when the route url name corresponds to the name of the table I think... or model.
So users/{id} would auto bind the User object when you type it as a param in the controller. Example (User $user)
However, since your URL seems to be "different" from the name of your Model/Table, go to the RouteServiceProvider, and manually do the binding.
So in your case you'd do something like this in the boot function of the RouteServiceProvider class:
public function boot()
{
parent::boot();
Route::model('finishes', FinishType::class);
}
Don't forget your imports :)
You can read more about Explicit Model Binding here: https://laravel.com/docs/5.8/routing#explicit-binding

Returning other entry in the url includes the first entry as well

public function show(Criminal $criminal){
$profile = Criminal::with(['profile','crimes'])->findOrFail($criminal);
dd($profile);
}
I have this method and it should return like this when I type localhost:8000/criminal/1
But when I say like criminal/3
it also returns the criminal/1 json output like this :
the first entry looks like this :
try this
public function show(Criminal $criminal, $id){
$profile = Criminal::with(['profile','crimes'])->findOrFail($id);
dd($profile);
}
There is no need to query the database again, the model passed to your function is already an eloquent model.
public function show(Criminal $criminal) {
dd($criminal);
}
If you really want to lazy load the relations, this can be done as follows:
public function show(Criminal $criminal) {
$criminal->load('profile', 'crimes')
dd($criminal);
}
This should not be necessary however as Laravel loads relations when needed.

Laravel Backpack - getting current record from crud controller

In my crud controller I am trying to get the name of the person who is currently being edited.
so
http://192.168.10.10/admin/people/93/edit
In the people crud controller
public function setup() {
dd(\App\Models\People::get()->first()->name)
}
This returns the first person not the person currently being edited.
How do I return the current person (with an id of 93 in this example)
Ok, So since you use backpack look into CrudController to see how the method looks:
public function edit($id)
{
$this->crud->hasAccessOrFail('update');
$this->data['entry'] = $this->crud->getEntry($id);
$this->data['crud'] = $this->crud;
$this->data['fields'] = $this->crud->getUpdateFields($id);
$this->data['id'] = $id;
return view('crud::edit', $this->data);
}
So now you can overwrite the edit function and change whatever you want. You can even create a custom edit page if you so wish.
Setup on the other hand is usually used to add things like
$this->crud->addClause(...);
Or you can even get the entire constructor and put it in the setup method because setup call looks like this:
public function __construct()
{
// call the setup function inside this closure to also have the request there
// this way, developers can use things stored in session (auth variables, etc)
$this->middleware(function ($request, $next) {
$this->setup();
return $next($request);
});
}
So you could do something like \Auth::user()->id;
Also it's normal to work like this. If you only use pure laravel you will only have access to the current id in the routes that you set accordingly.
Rahman said about find($id) method. If you want to abort 404 exception just use method findOrFail($id). In my opinion it's better way, because find($id)->name can throw
"Trying to get property of non-object error ..."
findOrFail($id) first fetch user with specified ID. If doesn't exists just throw 404, not 500.
The best answer is:
public function edit($id)
{
return \App\Models\People::findOrFail($id);
}
Good luck.
you need person against id, try below
public function setup($id) {
dd(\App\Models\People::find($id)->name);
}

Resources