Laravel: Use the method updateOrCreate on polymorphic relation - laravel

I am trying to use the method updateOrCreate on my polymorphic relation, which is called Taggable. This is the method I use to create a new tag.
public function attachTag($attributes)
{
return $this->tags()->create($attributes);
}
If I change the create method to the update, it also works fine when it comes to updating the model. But I want to use updateOrCreate method, which is problem because I don't pass the ID in the $attributes and therefore it just doesn't know, if there's some record in the DB or not.
I made some googling and found very little about this particular case, only something like I should pass second parameter. But I'm confused which parameter should I pass as second to make it working.
Thanks in advance for any help.

2 possible solutions
1- https://laracasts.com/discuss/channels/eloquent/updateorcreate-on-polymorph-relation
in this link, you should detect which one you want by selecting the second parameter.
2- Laravel: UpdateOrCreate on Relation?
I think it is also addressing your problem.
I used to use solution #1.
Hope it helps

Related

How to use Has One Of Many on a Many To Many relationship in Laravel

I have many to many relationship But I want to get only one record not a collection of records. I know it's possible to get only one record for a one to many relationship using the latestOfMany() function but it doesn't exist for a many to many one.
I ended up implementing it like this and I was wondering if there is a better way to have an actual relation function and not a getter function.
public function animal(): Attribute
{
return Attribute::make(
fn () => $this->morphToMany(
Animal::class,
'follow_up',
'animal_follow_ups',
'follow_up_id',
'animal_id'
)->first()
);
}
i think the purpose itself doesn't make any sense even when we use raw query to get a single result from many to many relationship, we should apply where condition to get it, or programatically we could apply iteration do get what we need... at least that what the documentation said here
https://laravel.com/docs/9.x/eloquent-relationships#many-to-many
hope it helps

How to get modified relationship laravel

We have the models: Question and Answer.
In the answers table, we have a boolean column with the name accepted and we have just one accepted Answer. We want to get question with its answers and accept answer separately.
I use two approaches, but I don't know which is better:
1). check if the relation is loaded if loaded filter relations and get an accepted answer like this:
if(!$this->relationLoaded('answers')){
$this->load('answers');
}
return $this->answers->firstWhere('accepted',true);
2). We can use this approach too:
function accepted_answer(){
return $this->answer()->where('accepted',true);
}
The problem of the second approach is we get an array, but we expect a single response or null.
Is there any better approach to this or we can use neither 1 or 2?
Create an Accessor on Question model.
class Question extends Model
{
public function getSelectedAnswerAttribute()
{
return $this->answers->where('accepted', true)->first();
}
}
now in every Answer instance has an attribute called selected_answer.
You can access it like,
$answer->selected_answer;
Note
this 'selected_answer' is not fetching from database, it filters from already fetched answers list. so its more efficient than your 2nd approach.
and, If you want this attribute automatically bind to the Question model always. add this accessor to appends array.
Model
protected $appends = ['selected_answer'];
create accepted scope at your answer model.
public function scopeAccepted($query){
return $query->where("accepted",true)->first();
}
then you can easly retreive first accepted answer.
$question->answer()->accepted();
for more further check out query scopes;
You should go with the second approach as you will have a single source to change later on if something changes (instead of digging through a lot of controllers)
To get the result, use ->get(); at the end of builder query.
P.S: Scopes are generally always better than writing queries manually inside the controller

What is the difference between attributesToArray() and toArray() in Laravel?

Can someone explain the difference between $model->attributesToArray() and $model->toArray() on a model?
I have an issue where a seeder is throwing an error about getCreatedAtAttribute method is not defined and it's complaining due to a toArray() method call. This is what prompted me to try and find out the difference between the two.
After switching to attributesToArray() the seeder runs fine.
attributesToArray will only fetch the attributes for the current model.
toArray calls the attributesToArray function, but also adds loaded relations to the array.

Customizable model file for a Laravel 5 package

I'm developing a Laravel 5 package where I have a "Member" model which currently extends App\User model. I would like to know the best practice to let any developer use a custom "Member" model instead of the one from the package. This is for example to allow a developer use another table.
One approach that seems to work without having done a deep test with it is to make an alias in my package service provider in the register() method:
$MemberModel = 'MyVendor\MyPackage\Member';
$loader = \Illuminate\Foundation\AliasLoader::getInstance();
$loader->alias('MyMember', $MemberModel);
In this case I have to:
Replace all entries in the code from the original class to the alias
Delete all php "use" entries related to it
Get the value of $MemberModel from a config file or the database
But I don't know if it is a good way to solve it or It may cause any conflict.
Is there any other and better approach for this goal? Thanks in advance!
I finally had to test by myself this approach without haven't read the solution anywhere else, but anyway everything seems to work fine in my source code.
If anyone is looking for doing anything similar, the code example in my question works because the $MemberModel is defined with a value. If you want to get that value from a Model instance, as me, you have to add that code in the boot() method of the service provider.

How to check if model's attached items have changed?

Suppose we have Class and Student models with many-to-many relationship defined between them.
I want to perform some action, if $students, that are attached to a $class, change. For example:
$class->attach($newSetOfStudents); // notify a teacher about the change behind the scenes
$class->save(); // by overriden save() or attach() methods
How can this be accomplished? I tried to use ..->isDirty() when overriding the save() method, but it does not seem to work with attached models.
Update
Checking the pivots for ..->isDirty() doesn't seem to work either:
// ..
foreach($class->students as $student){
if($student->pivot->isDirty()) return true;
}
// ..
the best thing to do, is using beforeSave() method by extending Ardent, there you can handle the case you want, do the changes, let it go to the save method by its own.
take a look at this nice package
You can use Model Event - created on Pivot like this:
use Illuminate\Database\Eloquent\Relations\Pivot;
Pivot::created(function($pivot) {
// Do something here
});
This solutions fires for each pivot & only works in case of attach().
See more about this - here
Hope this helps!

Resources