I have User model,
has many morph Notification. The Notification model also belongs to one NotificationType. I want to find data from NotificationType through the User instance. Here is the relationship code:
// User.php
public function notifications()
{
return $this->morphMany(Notification::class, 'notifiable');
}
// Notification.php
public function notification_type()
{
return $this->belongsTo(NotificationType::class, 'notification_type_id');
}
This is the code I have tried:
$notificationType = $user->notifications()->notification_type()->where('name', $this->data->type)->first();
But, it returns
staging.ERROR: Call to undefined method
Illuminate\Database\Eloquent\Relations\MorphMany::notification_type()
{"userId":"996cdaea-c6f3-444a-a430-036e1966ab91","exception":"[object]
(BadMethodCallException(code: 0): Call to undefined method
Illuminate\Database\Eloquent\Relations\MorphMany::notification_type()`
Is it possible to get the notification_type directly from the $user?
Thanks in advance!
Actually, I just found the solution. Since the $user->notifications() is the instance of Illuminate\Database\Eloquent\Relations\MorphMany, there is a function to get the instance of the Notification model, that is getRelated(). I found it here.
Since I got the Notification model class, I finally can retrieve the notification_type() relation method.
Here is my fixed code:
$notificationType = $user->notifications()->getRelated()->notification_type()->getRelated()->where('name', $this->data['type'])->first();
I am open to any suggestions to improve or fix the code above. Thank you.
Related
I am getting a strange error which I cannot work out.
I have a User and also a Partner model. A user can have multiple partners. I am trying to retrieve a list of partners that the user has. I am also using Laravel Sanctum as my auth guard.
My relationship code is as follows;
In my user model
public function partners(): HasMany
{
return $this->hasMany(Partner::class);
}
In my Partner model
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
My route definition looks like so;
Route::middleware(['auth:sanctum'])->group(function () {
Route::apiResource('partners', Api\Partner\PartnerController::class)
->only(['index']);
});
and finally in my controller;
public function index(Request $request)
{
return PartnerResource::collection($request->user()->partners());
}
When I hit the endpoint though, I am getting the following error;
Call to undefined method Illuminate\\Database\\Eloquent\\Relations\\HasMany::mapInto()
I cant figure out the issue. Any insight would be greatly appreciated.
When You are Calling user()->partners() it returns Illuminate\Database\Eloquent\Relations\HasMany Instance.
Resource needs to get Illuminate\Database\Eloquent\Collection Instance.
You have to just call user()->partners ( Remove parenthesis )
Or call get method on Illuminate\Database\Eloquent\Relations\HasMany Instance, to get Collection
user()->partners()->get()
Here is my current situation:
I have a Task model.
Tasks have owners (a belongsTo relationship)
Owners have accounts (yet another belongsTo relationship)
I'd like to set up a "belongsToThrough" relationship from Tasks to Accounts.
My first solution was to define a relationship in the Tasks model, like this:
public function account(): BelongsTo
{
return $this->owner->account();
}
With it I could call $task->account and retrieve a task's account easily. The problem is that this doesn't work with load/with, which in turn causes problems because I can't refresh() a task that has had the account loaded in (because refresh uses load). The error just states Trying to call account() on null which was honestly expected.
My second solution was to change the relationship method to:
public function account(): BelongsTo
{
return $this->owner()->first()->account();
}
With this, I can also simply call $task->account and retrieve the model, and when loading, it doesn't work (returns null), but also doesn't throw any errors. I don't need to load this relationship in, it just happens that sometimes I need to refresh models and having the load method throw an error is not ok.
In summary
What I'm looking for is kind of a BelongsToThrough, as a Task would BelongTo an Account through an Owner (User). Is there a way to do this that works using both $task->account and $task->load('account'). Before you tell me I can load it using owner.account, I know that, but refresh() will do it automatically with load('account') so I need it to work like that, not with the dot notation.
To get it working with load(), you'll need to define an account relationship on the owner model, if you haven't done so already. Like this:
public function account() :BelongsTo
{
return $this->belongsTo(AccountsTable);
}
Then use dot notation when calling load() on your task model like:
$task->load('owner.account');
You can do that using eager loading
public function account()
{
return $this->belongsTo('App\ParentModel', 'foreignkey', 'localkey');
}
After that you can easily fetch relation data with load/with.
Thanks,
I am trying to use wasChanged and wasRecentlyCreated of models in laravel project but both of them are false in the below code
$saved=$project->accessInfo()->updateOrCreate(['type'=>$request->type],['value'=>$data]);
dd($project->accessInfo[0]->wasChanged(),$project->accessInfo[0]->wasRecentlyCreated,$project->wasRecentlyCreated,$project->wasChanged());
//here is my relation in Project model
public function accessInfo()
{
return $this->hasMany('Modules\Project\Models\ProjectAccessInfo', 'project_id');
}
also below code returns error
dd($project->accessInfo->wasChanged(),$project->accessInfo()->wasRecentlyCreated)
//No such method or attribute in both cases
//Call to undefined method Illuminate\\Database\\Eloquent\\Relations\\HasMany::wasChanged()
Thanks in advance for your help.
getChanges - Get the attributes that were changed.
getDirty - Get the attributes that have been changed since last sync.
When you want to know if the model has been edited since it was queried from the database, or isn't saved at all, then you use the ->isDirty() function.
Here is model structure of my Laravel 5.3 project,
User.php (Model)
it has one invitation method that returns the invitation of a user.
public function invitations()
{
return $this->hasMany( 'App\Invitation', 'invitee_id', 'id' );
}
Invitation.php (Model)
This model has another method that would return the inviter detail of an invitation.
public function inviter()
{
return $this->hasOne( 'App\User', 'id', 'invited_by' );
}
If i want to retrieve all invitations of current user it works,
\Auth::user()->invitations;
But if i try to get the information about the inviter it won't work! (Question: How to do it?)
\Auth::user()->invitations->inviter;
Though i can query the inviter from a invitation eloquent object like this,
\App\Invitation::first()->inviter;
But this is not working when i try to access it from the user model -> invitation -> inviter!
Also can i use eager loading here?
\Auth::user()->invitations->inviter;
Looking at this, it appears that you're attempting to retrieve the inviter property from a collection of invitations. The reason Ken's suggestion to use \App\Invitation::first()->inviter; worked is because you are retrieving the inviter of only one invitation (in this instance, the first). To resolve this, loop through your invites before attempting to retrieve the properties for each one:
$invitations = \Auth::user()->invitations;
foreach ($invitations as $invitation) {
$inviter = $invitation->inviter;
}
There is also an each() method specific to Laravel Collections that will allow you to loop through your object.
I'm not quite sure if I understand the associate method in Laravel. I understand the idea, but I can't seem to get it to work.
With this (distilled) code:
class User
{
public function customer()
{
return $this->hasOne('Customer');
}
}
class Customer
{
public function user()
{
return $this->belongsTo('User');
}
}
$user = new User($data);
$customer = new Customer($customerData);
$user->customer()->associate($customer);
I get a Call to undefined method Illuminate\Database\Query\Builder::associate() when I try to run this.
From what I can read, I do it exactly as is stated in the docs.
What am I doing wrong?
I have to admit that when I first started using Laravel the relationships where the part that I had to consistently refer back to the docs for and even then in some cases I didn't quite get it right.
To help you along, associate() is used to update a belongsTo() relationship. Looking at your code, the returned class from $user->customer() is a hasOne relationship class and will not have the associate method on it.
If you were to do it the other way round.
$user = new User($data);
$customer = new Customer($customerData);
$customer->user()->associate($user);
$customer->save();
It would work as $customer->user() is a belongsTo relationship.
To do this the other way round you would first save the user model and then save the customer model to it like:
$user = new User($data);
$user->save();
$customer = new Customer($customerData);
$user->customer()->save($customer);
Edit: It may not be necessary to save the user model first but I've just always done that, not sure why.
As I understand it, ->associate() can onyl be called on a BelongsTo relationship. So, in your example, you could do $customer->user()->associate($user). However, in order to 'associate' a Has* relationship you use ->save(), so your code should be $user->customer()->save($customer)
just add ->save() to the end.
$user->customer()->associate($customer)->save();