Laravel 9 Cannot UPDATE Data - laravel

CONTROLLER
public function update(Request $request)
{
DB::table('bahanbaku')->where('id', $request->id)->update([
'id_bb' => $request->id_bb,
'nama_bb' => $request->nama_bb,
'stok' => $request->stok
]);
dd($request);
return redirect('/bahanbaku');
}
Sorry for my bad english, but in my case,
After Submit, Data still same, not change
Can you help me? T.T

Id does not exist, this is quite basic, but i feel like there is some misunderstandings with Laravel. Just to get the basics down, in Laravel i would expect you to do the following.
Use models for database operations
Instead of passing the id on the request, pass it on URL parameters
Use model binding for getting your model.
Create your model, since it has a non standard table name define that. Add the properties you want to be filled when updating it as fillables.
use Illuminate\Database\Eloquent\Model;
class Bahanbaku extends Model {
protected $table = 'bahanbaku';
protected $fillables = [
'id_bb',
'nama_bb',
'stok',
];
}
In your route, define the model as a parameter.
Route::put('bahanbaku/{bahanbaku}', [BahanbakuController::class, 'update']);
Now the logic can be simplified to this, which will automatically handle if the model is not found and give you a 404 error.
public function update(Request $request, Bahanbaku $bahanbaku)
{
$bahanbaku->fill(
[
'id_bb' => $request->id_bb,
'nama_bb' => $request->nama_bb,
'stok' => $request->stok
],
);
$bahanbaku->save();
return redirect('/bahanbaku');
}
To improve even more, i would look into utilizing form requests.

Related

Laravel Slugable Route Model Binding weird behaviour

I have a section in my project with the latest news articles. For this I have a:
Post model
Post resource controller and a
Resource Post Route.
Post Model
class Post extends Model
{
use HasFactory, Sluggable;
protected $fillable = [...,...];
public function getRouteKeyName()
{
return 'slug';
}
public function sluggable(): array
{
return [
'slug' => [
'source' => 'title'
]
];
}
}
PostController.php
public function show(Post $post)
{
dd($post);
}
web.php
Route::resource('/posts', App\Http\Controllers\PostController::class)->only(['index','show']);
Index (http://localhost/news) and show (http://localhost/news/{slug}) work as expected!
Now the problem/bug I noticed:
When I change the route from posts to news, the show method no longer works.
Index still works.
the modified route from posts to news
Route::resource('/news', App\Http\Controllers\PostController::class)->only(['index','show']);
http://localhost/news works but http://localhost/news/{slug} shows me only the PostModel Structure.
Do you know the problem and what do I have to do to make it work? I use Laravel 8 and "cviebrock/eloquent-sluggable": "^8.0" packagefor the slugs. Thanks for your time!
Ok. I've figured it out. I'm writing the answer here for anyone who might have the same problem as me. First of all. It is not a bug. If you adjust the route so that the model name is no longer included in the route, then you have to bind the route explicitly. https://laravel.com/docs/8.x/routing#explicit-binding
All you have to do. In the boot() method of RouteServiceProvider.php, add the desired route and bind it with the desired classes. In my case it was news instead of post.
public function boot()
{
....
Route::model('news', \App\Models\Post::class);
}

Show function not working. Can't retrieve element by id. Laravel 5.8

I have created resource controllers, one per model in my laravel 5.8 project. I want the show function to return the DB element i want based on the id inserted on the URL, as it is supposed to do. For now i do tests directly on my controller, i'm not using the "thisCircuit" function of my model. Calling the index, returns a json with all circuits. Calling the show returns nothing. How can i fix it?
Show function
public function show(circuits $circuits)
{
$circuits = circuits::findOrFail($circuits);
dd($circuits);
}
Model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;
class circuits extends Model
{
protected $fillable = [
'circuitId', 'circuitRef', 'name',
'location', 'country', 'lat',
'lng', 'alt', 'url',
];
protected $primaryKey = 'circuitId';
public function races()
{
return $this->hasMany('App\races', 'circuitId');
}
public function allCircuits(){
$data = Circuits::all();
return response()->json($data);
}
public function thisCircuit($id){
$id = circuits::findOrFail($id);
}
}
Web.php File
Route::get('/test', 'CircuitsController#index');
Route::get('/test/{circuit}', 'CircuitsController#show');
URL on browser
http://localhost:8000/test/1
Result on browser
Illuminate\Database\Eloquent\Collection {#947 ▼
#items: []
}
Ok, let's clean up this solution. A lot of smaller stylistic problems, that will hurt you going forward if not adjusted.
Firstly
Class names are starting with capitols letter in most standard naming conventions and in singular form.
circuits.php
Should be.
Circuit.php
Secondly
You are already using model binding. If you are doing this approach you can actually just return the circuit directly. As a bonus Laravel does not have to return response if the returned data is a model, unless you want to change the response code from 200 to something else.
public function show(Circuit $circuit) {
return $circuit;
}
Also you are misunderstanding firstOrFail(). This code you have written can never return multiple Circuits, this will return a singular model.
$circuits = circuits::findOrFail($circuits);

Laravel getAttribute() on eloquent?

so i just wondered, if something like this is possible, since my code does not work.
protected $appends = ['position_name'];
public function getPositionNameAttribute()
{
return $this->belongsTo('App\EmployeePosition', 'employee_position_id')->name;
}
Can I append the name of Eloquen relationship model?
edit: so far, i am using this:
foreach ($employees as $e) {
$e->position_name = $e->position->name;
}
So, I needed to use the relation defined before.
protected $appends = ['position_name'];
public function position()
{
return $this->belongsTo('App\EmployeePosition', 'employee_position_id');
}
public function getPositionNameAttribute()
{
return $this->position->name;
}
Based on your comments i'd suggest to use the laravel default solution for your problems API resrouces
eg
class EmployeeResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
'position_name' => $this->position->name,
];
}
}
note: using the with as other people suggested to preload information can increase performance by reducing the amount of queries, if you are returning a collection of employees.
Creating an accessor that looks up a value in another model and appending this field by using $appends is bad practice and will lead to n+1 queries whenever you fetch your Employee model. You should avoid doing this and just use $employee->position->name.
You should also make sure to use Employee::with('position') when you need to show the position name, so that the position model is fetched in a single query.
If the position name is something that you need in all your Employee queries, then you can set the Employee to always eager load the position by defining the following inside your Employee model:
/**
* The relationships that should always be loaded.
*
* #var array
*/
protected $with = ['position'];
I think you can just create a model with position names and reference it to the position id in the other mode by using eloquent relationships.

Laravel nova resource extending/overriding the create method

I am developing a web admin panel using Laravel Nova.
I am having an issue since Nova is quite a new technology.
What I would like to do now is I would like to add a hidden field or extend or override the create method.
This is my scenario. Let's say I have a vacancy nova resource with the following field.
public function fields(Request $request)
{
return [
ID::make()->sortable(),
Text::make('Title')->sortable(),
Text::make('Salary')->sortable()
// I will have another field, called created_by
];
}
Very simple. What I like to do is I want to add a new field called created_by into the database. Then that field will be auto filled with the current logged user id ($request->user()->id).
How can I override or extend the create function of Nova? How can I achieve it?
I can use resource event, but how can I retrieve the logged in user in
the event?
What you're looking for is Resource Events.
From the docs:
All Nova operations use the typical save, delete, forceDelete, restore Eloquent methods you are familiar with. Therefore, it is easy to listen for model events triggered by Nova and react to them.
The easiest approach is to simply attach a model observer to a model:
If you don't feel like creating a new observable you could also create a boot method in your eloquent model as so:
public static function boot()
{
parent::boot();
static::creating(function ($vacancy) {
$vacancy->created_by = auth()->user()->id;
});
}
But please do note that these are a bit harder to track than observables, and you or a next developer in the future might be scratching their head, wondering how's the "created_at" property set.
In my opinion you should go for Observers. Observers will make you code more readable and trackable.
Here is how you can achieve the same with Laravel Observers.
AppServiceProvider.php
public function boot()
{
Nova::serving(function () {
Post::observe(PostObserver::class);
});
}
PostObserver.php
public function creating(Post $post)
{
$post->created_by = Auth::user()->id;
}
OR
You can simply hack a Nova field using withMeta.
Text::make('created_by')->withMeta([
'type' => 'hidden',
'value' => Auth::user()->id
])
You could also do that directly within your Nova resource. Every Nova resource has newModel() method which is called when resource loads fresh instance of your model from db. You can override it and put there your logic for setting any default values (you should always check if values already exist, and only set if they are null, which will only be the case when the model is being created for the first time, which is what you actually need):
public static function newModel()
{
$model = static::$model;
$instance = new $model;
if ($instance->created_by == null) {
$instance->created_by = auth()->user()->id;
}
return $instance;
}
a) Create an Observer class with following command:
php artisan make:observer -m "Post" PostObserver
b) Add following code in the PostObserver:
$post->created_by = Auth::user()->id;
c) Register PostObserver in AppServiceProvider.php
For detailed explanation: https://medium.com/vineeth-vijayan/how-to-add-a-new-field-in-laravel-nova-resource-87f79427d38c
Since Nova v3.0, there is a native Hidden field.
Usage:
Hidden::make('Created By', 'created_by')
->default(
function ($request) {
return $request->user()->id;
}),
Docs: https://nova.laravel.com/docs/3.0/resources/fields.html#hidden-field

Laravel 5 Form request validation with parameters

I am using form request validation and there are some rules that needs external values as a parameters.
Here are my validation rules for editing a business profile inside a form request class,
public function rules()
{
return [
'name' => 'required|unique:businesses,name,'.$business->id,
'url' => 'required|url|unique:businesses'
];
}
I can use this on the controller by type hinting it.
public function postBusinessEdit(BusinessEditRequest $request, Business $business)
{
//
}
But how to pass the $business object as a parameter to the rules method?
Lets say this is your model binding:
$router->model('business', 'App\Business');
Then you can reference the Business class from within the FormRequest object like this:
public function rules()
{
$business = $this->route()->getParameter('business');
// rest of the code
}
Note that if you use your form request both for create and update validation, while creating the record, the business variable will be null because your object does not exists yet. So take care to make the needed checks before referencing the object properties or methods.
There can be many ways to achieve this. I do it as below.
You can have a hidden field 'id' in your business form like bellow,
{!! Form::hidden('id', $business->id) !!}
and you can retrieve this id in FormRequest as below,
public function rules()
{
$businessId = $this->input('id');
return [
'name' => 'required|unique:businesses,name,'.$businessId,
'url' => 'required|url|unique:businesses'
];
}
For those who switched to laravel 5 :
public function rules()
{
$business = $this->route('business');
// rest of the code
}
Let say if we have a scenario like we want to change our validation rules depends on the type that we pass in with the route. For example:
app.dev/business/{type}
For different type of business, we have different validation rules. All we need to do is type-hint the request on your controller method.
public function store(StoreBusiness $request)
{
// The incoming request is valid...
}
For the custom form request
class StoreBussiness extends FormRequest
{
public function rules()
{
$type = $this->route()->parameter('type');
$rules = [];
if ($type === 'a') {
}
return rules;
}
}
In Laravel 5.5 at least (haven't checked older versions), once you did your explicit binding (https://laravel.com/docs/5.5/routing#route-model-binding), you can get your model directly through $this:
class StoreBussiness extends FormRequest
{
public function rules()
{
$rules = [];
if ($this->type === 'a') {
}
return rules;
}
}
Since Laravel 5.6 you may type hint it in the rules method:
public function rules(Business $business)
{
return [
'name' => 'required|unique:businesses,name,'.$business->id,
'url' => 'required|url|unique:businesses'
];
}
See the docs for more:
You may type-hint any dependencies you need within the rules method's signature. They will automatically be resolved via the Laravel service container.

Resources