How to add data to additional column in pivot table in laravel - 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

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 firstOrCreate without Eloquent

Eloquent has a firstOrCreate method which gets a model based on a condition, or creates it if it doesn't exist.
Is there any equivalent method in Laravel's query builder (i.e. NOT in Eloquent)? For example:
$row = DB::table('users')->where('user_id', 5)->firstOrCreate('name' => 'Peter', 'last_name' => 'Pan');
That would try to get a row from users with 'user_id'==5. If it doesn't exist, it would insert a row with that id number, plus the other mentioned fields.
EDIT: I'm not trying to apply my question with users. I used users as an example to make as clear as possible what I'm looking for.
updateOrInsert function with empty values give me the result like firstOrCreate
Nope, Laravel firstOrCreate is function, that says next:
public function firstOrCreate(array $attributes, array $values = [])
{
if (! is_null($instance = $this->where($attributes)->first())) {
return $instance;
}
return tap($this->newModelInstance($attributes + $values), function ($instance) {
$instance->save();
});
}
But you can add it with query micro:
DB::query()->macro('firstOrCreate', function (array $attributes, array $values = [])
{
if ($record = $this->first()) {
// return model instance
}
// create model instance
});
So than you will be able to call it same way you do with Eloquent.
$record= DB::table('records')->where('alias', $alias)->firstOrFail();
Yeah of course! Just use normal SQL and ->selectRaw( your conditions ) and look for if there is a entry where your specifications are.
https://laravel.com/docs/5.7/queries#raw-expressions

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: How to update pivot tables withou using first

Im new in Laravel. I want to update my leaves pivot table. I am trying with below code but it only updates the single row i have multiple rows in db with same leave_id and i want to update all this where leave_id = xyz
I have following function in my model Leave:
public function relLeave(){
return $this->belongsToMany(User::class)->withPivot('days');
}
LeaveController:
public function saveUpdate(Request $request)
{
$leave = Leave::find($request->id);
$msg = $leave->relLeave()->Where('leave_id', $request->id)->get()->first();
$msg->pivot->days = $request->days;
$msg->pivot->save();
}
I followed #option's instruction and it works for me i removed the first();
below is my updated code.
$msg = $leave->relLeave()->Where('leave_id', $request->id)->get();
foreach($msg as $msgs)
{
$msgs->pivot->days = $request->days;
$msgs->pivot->save();
}
you can update extra fields in pivot table when updating relationship
$leave->relLeave()->sync([$request['id'] => ['days' => $request['days']]]);
You can use Query Builder for that if it's an option:
DB::table('leave_user')->where('leave_id', $request->id)->update(['days' => $request->days]);
This is just one DB query and it's pretty simple one.
If you want Eloquent solution, use updateExistingPivot() in a loop:
$leave = Leave::find($request->id);
$usersIds = $leave->relLeave()->pluck('id')->toArray();
foreach ($usersIds as $userId) {
$leave->relLeave()->updateExistingPivot($userId, ['days' => $request->days]);
}

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