Laravel Custom Morph Relationship with custom table structure - laravel

I have the following table structure:
Tokens
- type ( Flag Indicating that if its a Users token or company's token )
- user_company_id (User or Company Id )
Users
- id
- username
- password
Companies
- id
- username
- password
Im trying to create the relationship from the token to get the user or the company based on the type flag.
I know that I should have a different modeling, but this database is up and running and I cant change their structure.
How can I do this?
Im trying to figure it out but no success until now =(

You may try something like this (make sure the namespace and model names are correct):
Token Model:
class Token extends Model
{
public function tokenable()
{
return $this->morphTo();
}
}
User Model:
class User extends Model
{
public function tokens()
{
return $this->morphMany('App\Token', 'tokenable', 'type', 'user_company_id');
}
}
Company Model:
class Company extends Model
{
public function tokens()
{
return $this->morphMany('App\Token', 'tokenable', 'type', 'user_company_id');
}
}
Notice the third (type) and fourth (user_company_id) argument in the morphMany method call, those are optional but in your case, these are required because you've custom field names in your database. Check the documentation to learn how to retrieve relations.

Related

Laravel Multiple Foreign Keys on Intermediate Table

I have the following table structure:
default_tasks
id
...
locations
id
...
users
id
...
default_task_location
id
location_id
default_task_id
default_assignee_id (FK to users.id)
In my blade file I'm looping through the default tasks for the location, and trying to output the default assigned user. I can get the ID by doing $task->pivot->default_assignee_id, but I want to get the actual user model so I can output the user's name in my blade file
I've gathered from searching that the way to accomplish this is to create a pivot table model. So I've done this:
class DefaultTaskLocationPivot extends Pivot
{
public function user()
{
return $this->belongsTo(User::class, 'default_assignee_id');
}
public function defaultTask()
{
return $this->belongsTo(DefaultTask::class);
}
public function location()
{
return $this->belongsTo(Location::class);
}
}
and in my location model I've done this:
public function taskDefaultAssignee()
{
return $this->belongsToMany(User::class)
->using(DefaultTaskLocationPivot::class)->withPivot(['default_task_id', 'frequency_type_override', 'create_on_day_override', 'due_on_day_override', 'default_assignee_id']);
}
However, I'm still unable to access the user associated with the default_assignee_id. I've tried things like $task->location->taskDefaultAssignee, but it doesn't seem like the relationship is even available if I dump the object.

Laravel eager loading a BelongsTo relation doesn't work

This seems extremely simple and yet it doesn't work:
// Reservations
class Reservation extends Model
{
public function service()
{
return $this->belongsTo('App\Landing');
}
}
// Service
class Landing extends Model
{
public function reservation()
{
return $this->hasMany('App\Reservation');
}
}
And then in my controller I have:
$x = Reservation::with('service')->get();
$y = Reservation::all()->load('service');
None of these work. I've tried several ways of loading it and none of them work. It always returns an empty result for the service.
Any other result works fine with eager loading (even with nesting) except te BelongsTo - this one.
The eager loading works.
The problem is your relationship
When you define a BelongsTo relationship you need to specify a foreign key if the name of your property does not correspond to the entity being referenced
For example: if you call the relationship "landing", you will be fine, because under-the-hood, Laravel passes the foreign key landing_id based on the name of the property
class Reservation extends Model
{ //landing correspond to the lowercase (singular) name of the Landing class
//in that case Laravel knows how to set the relationship by assuming
//that you want to match landing_id to the id of the landings table
public function landing()
{
return $this->belongsTo(Landing::class);
}
}
If you chose to name the relationship differently, such as "service", then you need to specify the foreign key ex: landing_id since service and landing are two different words, and landing correspond to the lowercase version of the actual class Landing. Otherwise Laravel would think your foreign key is "service_id" instead of landing_id
class Reservation extends Model
{
//service is a custom name to refer to landing
//in that case Laravel needs you to specify the foreign key
public function service()
{
return $this->belongsTo(Landing::class, 'landing_id');
}
}
Read more here: https://laravel.com/docs/5.8/eloquent-relationships#updating-belongs-to-relationships

How to eloquent relationship with multiple results

Problem
I have two classes, Users & Posts. A user "hasMany" posts and a post "belongTo" a user. But when I call "User::all()" it doesn't automatically pull the users posts for obvious reasons, because if my user had relations to 100 different tables pulling all users would start to become pretty chunky.
Question
Is there a way to pull all users and all user->posts in one or few lines of code without going through a foreach loop?
I know i can use a mutator but the problem I have is my field is called user_id and i have tested it with this code:
public function getUserIdAttribute($id)
{
return User::find($id);
}
But it will replace "user_id" field value with a user object, Id rather have it set to its own "temporary user" field within the result. I'm trying to find best practice!
Thank you in advance.
What you're looking for is called Eager Loading
Inside your post model :
class Post extends Model
{
protected $table='posts';
public $primaryKey='id';
public function user(){
return $this->belongsTo('App\User','user_id');
}
}
now you want to get post with user use below code :
$posts=Post::with('user')->get();
inside your user model :
class User extends Model
{
public function posts(){
return $this->hasMany('App\Model\Post');
}
}
now you want to get a user with all posts :
$user=User::where('id',$id)->first();
$user_posts=$user->posts;

How to setup conditional relationship on Eloquent

I have this (simplified) table structure:
users
- id
- type (institutions or agents)
institutions_profile
- id
- user_id
- name
agents_profile
- id
- user_id
- name
And I need to create a profile relationship on the Users model, but the following doesn't work:
class User extends Model
{
public function profile()
{
if ($this->$type === 'agents')
return $this->hasOne('AgentProfile');
else
return $this->hasOne('InstitutionProfile');
}
}
How could I achieve something like that?
Lets take a different approach in solving your problem. First lets setup relationship for the various models respectively.
class User extends Model
{
public function agentProfile()
{
return $this->hasOne(AgentProfile::class);
}
public function institutionProfile()
{
return $this->hasOne(InstitutionProfile::class);
}
public function schoolProfile()
{
return $this->hasOne(SchoolProfile::class);
}
public function academyProfile()
{
return $this->hasOne(AcademyProfile::class);
}
// create scope to select the profile that you want
// you can even pass the type as a second argument to the
// scope if you want
public function scopeProfile($query)
{
return $query
->when($this->type === 'agents',function($q){
return $q->with('agentProfile');
})
->when($this->type === 'school',function($q){
return $q->with('schoolProfile');
})
->when($this->type === 'academy',function($q){
return $q->with('academyProfile');
},function($q){
return $q->with('institutionProfile');
});
}
}
Now you can access your profile like this
User::profile()->first();
This should give you the right profile. Hope it helps.
you can do this by use another method please check this:
a blog Post and Video model could share a polymorphic relation to a
Tag model. Using a many-to-many polymorphic relation allows you to
have a single list of unique tags that are shared across blog posts
and videos. First, let's examine the table structure:
https://laravel.com/docs/5.4/eloquent-relationships#many-to-many-polymorphic-relations
Looks like that should be $this->type rather than $this->$type - since type is a property, not a variable.

Laravel & Eloquent - Query 'Friends' Relationship

Lets say you have User and Friend Schemas
user:
- id
- username
friends:
- id
- user_id
- friend_id
A 'friendship' is determined by having two reciprocal records. And lets says if it's just a one way relationship, this is a pending request. So in the friends table:
user_id: 5 | friend_id: 6
user_id: 6 | friend_id 5
In the User Model, you would then have:
public function friends()
{
return $this->belongsToMany(self::class,'friends','user_id','friend_id')->withTimestamps();
}
However, this isn't the whole story because this doesn't check for the presence of the mutual relationship.
How would you set this up? Should the friends() method be responsible for for querying the data further? Or is this method appropriate, and instances where you want to get a mutual friendship, you should append a query scope? For example
$this->user->friends->mutual()
OR
$this->user->friends->pending()
Ended up figuring this out based on this answer. However, i changed the merge() functionality to intersect() because I'm not use the approved flag to determine weather the friendship is mutual. I'm only using the presence of the two relationships.
So in my case. the relations are:
public function myFriends()
{
return $this->belongsToMany(self::class,'friends','user_id','friend_id')->withTimestamps();
}
public function friendsOf()
{
return $this->belongsToMany(self::class,'friends','friend_id','user_id')->withTimestamps();
}
And the other logic is:
public function getFriendsAttribute()
{
if ( ! array_key_exists('friends', $this->relations)) $this->loadFriends();
return $this->getRelation('friends');
}
protected function loadFriends()
{
if ( ! array_key_exists('friends', $this->relations)) $this->setRelation('friends', $this->mergeFriends());
}
protected function mergeFriends()
{
return $this->myFriends->intersect($this->friendsOf);
}

Resources