How to update field when delete a row in laravel - 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.

Related

Update the Record of Related Model in 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]);

laravel 5.6 Eloquent : eloquent relationship model creation issue

in my controller i create an Eloquent Model Instance passign throug a relation. The model is loaded on controller's __construct, that's why is present a $this->store and not a $store.
public function index()
{
if (is_null($this->store->gallery)) {
$this->store->gallery()->create([
'title' => 'gallery_title,
'description' => 'gallery_description',
]);
}
$gallery = $this->store->gallery;
dd($gallery);
return view('modules.galleries.index', compact('gallery'));
}
Simply if a store's gallery is not present yet, let's create it.
The first time i print out my dd() is ALWAYS null, if i reload the page the dd() show correctly my gallery model.
The things is weird for me, seems like the first time the creation is done but not ready... I can work around but why this code doesn't work the first time?
Help is very appreciate.
Relationship codes: on gallery ....
public function store()
{
return $this->belongsTo(Store::class);
}
on store...
public function gallery()
{
return $this->hasOne(Gallery::class);
}
When using the $this->store->gallery()->create() method, the original method is not hydrated with the new value, you can simply do a
$gallery = $this->store->refresh()->gallery;
OR
$gallery = $this->store->load('gallery')->gallery;
if you want to make your code cleanner you can do that in your Store Model:
public function addGallery($gallery){
$this->gallery()->create($gallery);
return $this->load('gallery')->gallery;
}
And that in your controller:
$gallery = $this->store->addGallery([
'title' => 'gallery_title',
'description' => 'gallery_description',
]);
and voila ! You have your gallery ready to be used :)
It's the lazy load part of Eloquent. basicly, when you tested for it with is_null($this->store->gallery) it sets it to that value.
when you tried to recover it again, it did not do the DB query, it just loaded the value already present (null).
after creation you need to force reload the relation:
$this->store->load('gallery');
or
unset($this->store->gallery);
or
$gallery = $this->store->gallery()->get();

Laravel oneToMany accessor usage in eloquent and datatables

On my User model I have the following:
public function isOnline()
{
return $this->hasMany('App\Accounting', 'userid')->select('rtype')->latest('ts');
}
The accounting table has activity records and I'd like this to return the latest value for field 'rtype' for a userid when used.
In my controller I am doing the following:
$builder = App\User::query()
->select(...fields I want...)
->with('isOnline')
->ofType($realm);
return $datatables->eloquent($builder)
->addColumn('info', function ($user) {
return $user->isOnline;
}
})
However I don't get the value of 'rtype' for the users in the table and no errors.
It looks like you're not defining your relationship correctly. Your isOnline method creates a HasMany relation but runs the select method and then the latest method on it, which will end up returning a Builder object.
The correct approach is to only return the HasMany object from your method and it will be treated as a relation.
public function accounts()
{
return $this->hasMany('App\Accounting', 'userid');
}
Then if you want an isOnline helper method in your App\User class you can add one like this:
public function isOnline()
{
// This gives you a collection of \App\Accounting objects
$usersAccounts = $this->accounts;
// Do something with the user's accounts, e.g. grab the last "account"
$lastAccount = $usersAccounts->last();
if ($lastAccount) {
// If we found an account, return the rtype column
return $lastAccount->rtype;
}
// Return something else
return false;
}
Then in your controller you can eager load the relationship:
$users = User::with('accounts')->get(['field_one', 'field_two]);
Then you can do whatever you want with each App\User object, such as calling the isOnline method.
Edit
After some further digging, it seems to be the select on your relationship that is causing the problem. I did a similar thing in one of my own projects and found that no results were returned for my relation. Adding latest seemed to work alright though.
So you should remove the select part at very least in your relation definition. When you only want to retrieve certain fields when eager loading your relation you should be able to specify them when using with like this:
// Should bring back Accounting instances ONLY with rtype field present
User::with('accounts:rtype');
This is the case for Laravel 5.5 at least, I am not sure about previous versions. See here for more information, under the heading labelled Eager Loading Specific Columns
Thanks Jonathon
USER MODEL
public function accounting()
{
return $this->hasMany('App\Accounting', 'userid', 'userid');
}
public function isOnline()
{
$rtype = $this->accounting()
->latest('ts')
->limit(1)
->pluck('rtype')
->first();
if ($rtype == 'Alive') {
return true;
}
return false;
}
CONTROLLER
$builder = App\User::with('accounting:rtype')->ofType($filterRealm);
return $datatables->eloquent($builder)
->addColumn('info', function (App\User $user) {
/*
THIS HAS BEEN SUCCINCTLY TRIMMED TO BE AS RELEVANT AS POSSIBLE.
ARRAY IS USED AS OTHER VALUES ARE ADDED, JUST NOT SHOWN HERE
*/
$info[];
if ($user->isOnline()) {
$info[] = 'Online';
} else {
$info[] = 'Offline';
}
return implode(' ', $info);
})->make();

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

Resources