Update the Record of Related Model in Laravel - laravel

How to update a record in the related table model by chain expression?
This is what I currently do (and it works)
$user = User::find(1);
$token = Token::where('user_id', $user->id)->first();
$token->token = $request->token;
$token->save();
But can I do the above in a more elegant way, such as?
$user = User::find(1);
$user->token()->token = $new_token;
$user->token()->save();
My User Model
public function token()
{
return $this->hasOne('App\Token');
}

In one line:
User::find(1)->token()->update(['token' => $new_token]);
Just know these things before using it:
User find could return null if the user id is not found.
The saved and updated model events will not be fired for the updated models.
The update method execution does not go through the Eloquent model methods.
However in your particular case I think it's valid, specially if you know that the user id will always be valid.

Yo can do it like this :
User::find(1)->token()->update(['token' => $new_token]);
Or do it in youApp\Token class like this :
User::find(1)->token()->update_token($new_token);
And create update_token function in App\Token class:
public function update_token(string $new_token)
{
$this->update(['token'=>$new_token]);
}

$user = User::with('token')->findOrFail(1);
$user->token->update(['token' => $request->token]);

Related

How can fill the user id field with auth user on creation of resource?

I'm sure there must be a very simple way to do this - I would like to fill the user_id field on my resource with the authenticated user's id whenever a new instance of the resource is created.
In the store() method of my Resource model I have:
public function store(Request $request)
{
$input = $request->all();
$resource = Resource::create($input);
$resource->user_id = Auth::user()->id;
return $resource;
return 'Resource added.';
}
This works through a post API route, however whenever I add a new resource instance through Nova dashboard, it does not add the Auth user id. I'm guessing this because Nova doesn't use that Resource controller that I have set out?
I would appreciate suggestions!
Working on the assumption that you have relationship method User::resources() the following should work:
return $request->user()->resources()->create($request->all());
The way you have it doesn't work because you didn't save the resource after associating user with it.
I haven't used Nova yet, but since its also laravel and most likely Eloquent ORM I can tell the following.
In these two lines you've set the user_id but you haven't persisted the change:
$resource->user_id = Auth::user()->id;
return $resource;
You should add this line to save the changes you've done:
$resource->save();
As an alternative you could add the value already into your $input array:
$input = $request->all();
$input["user_id"] = Auth::user()->id;
$resource = Resource::create($input);
I just created an ResourceObserver. Saved the Auth()->user->id with the created method.
Registered the ResourceObserver to AppServiceProvider and NovaServiceProvider.
https://laravel.com/docs/5.7/eloquent#observers
https://nova.laravel.com/docs/1.0/resources/#resource-events
In the model class, add function like this:
public function save(array $options = array())
{
$this->user_id = auth()->id();
parent::save($options);
}
Just be carefull if you tend to use save in any other scenario so you don't overwrite existing user_id.

Doing ->save to multiple relations

I am using Laravel 5.5.13.
I have a model called Thumb. This thumb is related to two things in a many-to-one relationship: Player and Comment.
I currently do things like this:
public function store(Request $request, Entity $entity, Player $player)
{
$thumb = new Thumb($request->all());
$thumb->player_id = $player->id;
$entity->thumbs()->save($thumb);
return response()->json($thumb, 201);
}
We see how I have to set $thumb->player_id AND I don't have to set the entity_id because I am doing $entity->thumbs()->save
Is there a way to do $entityAndPlayer->thumbs()->save? Or is the way I did it above the recommend way?
You cannot use relationships to set 2 foreign columns so they way you showed is the correct one. However you can make it a bit cleaner in my opinion.
Into Thumb model you could add:
public function setPlayer(Player $player)
{
$this->player_id = $player->id;
}
and then instead of:
$thumb->player_id = $player->id;
you could use:
$thumb->setPlayer($player);
Or you could add create setPlayerAttribute method and finally instead of:
$thumb = new Thumb($request->all());
$thumb->player_id = $player->id;
use just:
$thumb = new Thumb($request->all() + ['player' => $player]);
You can't save multiple relationships at once but, for many to one associations you can use the method associate() (Laravel docs) to save using the belongs to part of the relationship, for example:
public function store(Request $request, Entity $entity, Player $player)
{
$thumb = new Thumb($request->all());
$thumb = $thumb->save();
$thumb->player()->associate($player);
$thumb->entity()->associate($entity);
return response()->json($thumb, 201);
}

How to add data to additional column in pivot table in laravel

I'm trying to build an app in Laravel 5.3, I want to add additional column data in the pivot table. Following is my code:
My Users model:
public function relations()
{
return $this->belongsToMany('App\Plan')->withPivot('child');
}
My Plan model:
public function relations()
{
return $this->belongsToMany('App\User')->withPivot('child');
}
In my controller I'm fetching the user data from Auth::user(); and for plans and child element I'm getting through request. I want to store this to my pivot table. Following is the code which I tried in my controller:
$user = \Auth::user();
$plan_id = $request->plan_id;
$childid = $request->child_id;
$plan = App\Plan::find($plan_id);
$user->relations()->attach($plan, ['child' => $childid]);
Help me out in this.
You should use attach() like this:
$user->relations()->attach($plan_id, ['child' => $childid]);
Try the save method as:
$user->relations()->save($plan, ['child' => $childid]);
Docs
Both save and attach work. Just that attach will return null while save will return $user object when I try with tinker

When to refresh an instance using Eloquent

Why do we have to refresh an instance after adding new relations?
Example, theres a pivot table 'favourites' which stores all the favourite relation N:N between items and users:
$item = factory(App\Item::class)->create();
$user = factory(App\User::class)->create();
$user->setFavourite($item->id);
dd($user->favourites);//is Empty!!
//whereas refreshing the instance...
$user = $user->fresh();
dd($user->favourites);//is the corresponding collection within the item
The setFavourite method is simply an attach/detach of the relationship:
public function setFavorito($id)
{
if(Auth::check())
{
$user = Auth::user();
if($user->esAnuncioFavorito($id)) {
$user->favoritos()->detach($id);
}else{
$user->favoritos()->attach($id);
}
}
return Redirect::back();
}
I though that when eloquent calls for the related instances of an instance it was done at the moment, therefore a call to the DB shall be done and would end retrieving an updated collection including the added one.
Could someone explain it to me? When should I use the fresh() method?

How to update field when delete a row in laravel

Let I have a table named customer where customer table has a field named deleted_by.
I implement softDelete in customer model. Now I want to update deleted_by when row delete. So that I can trace who delete this row.
I do search on google about it But I don't found anything.
I use laravel 4.2.8 & Eloquent
You may update the field using something like this:
$customer = Customer::find(1); // Assume 1 is the customer id
if($customer->delete()) { // If softdeleted
DB::table('customer')->where('id', $customer->id)
->update(array('deleted_by' => 'SomeNameOrUserID'));
}
Also, you may do it in one query:
// Assumed you have passed the id to the method in $id
$ts = Carbon\Carbon::now()->toDateTimeString();
$data = array('deleted_at' => $ts, 'deleted_by' => Auth::user()->id);
DB::table('customer')->where('id', $id)->update($data);
Both is done within one query, softDelete and recorded deleted_by as well.
Something like this is the way to go:
// override soft deleting trait method on the model, base model
// or new trait - whatever suits you
protected function runSoftDelete()
{
$query = $this->newQuery()->where($this->getKeyName(), $this->getKey());
$this->{$this->getDeletedAtColumn()} = $time = $this->freshTimestamp();
$deleted_by = (Auth::id()) ?: null;
$query->update(array(
$this->getDeletedAtColumn() => $this->fromDateTime($time),
'deleted_by' => $deleted_by
));
}
Then all you need is:
$someModel->delete();
and it's done.
I would rather use a Model Event for this.
<?php
class Customer extends \Eloquent {
...
public static function boot() {
parent::boot();
// We set the deleted_by attribute before deleted event so we doesn't get an error if Customer was deleted by force (without soft delete).
static::deleting(function($model){
$model->deleted_by = Auth::user()->id;
$model->save();
});
}
...
}
Then you just delete it like you would normally do.
Customer::find(1)->delete();
I know this is an old question, but what you could do (in the customer model) is the following....
public function delete()
{
$this->deleted_by = auth()->user()->getKey();
$this->save();
return parent::delete();
}
That would still allow the soft delete while setting another value just before it deletes.

Resources