I have a problem with Laravel relationships.
I need to make relationship based on this table:
issuer and friend need to be united. Relationship will return all rows where user id in issuer or in friend. At the moment code looks like this:
return DB::table('contacts')->select()->where('friend', $this->id)->orWhere('issuer', $this->id)->where('status', 'approved');
Previously I used that method, but there are no relationship, 'cause attach() is undefined.
private function contactsIssued() {
return $this->belongsToMany(User::class, 'contacts','issuer', 'friend');
}
private function contactsFriended() {
return $this->belongsToMany(User::class, 'contacts','friend', 'issuer');
}
public function contacts() {
return $this->contactsIssued()->union($this->contactsFriended()->toBase());
}
So, I need to make one relationship that has two foreign columns.
Sorry, my English can be broken, 'cause it's not my native language.
That's look like a one to many relationship but you are using belongsToMany which is many to many relationship and required a pivot table.
if you have user model that has many contact model then in your contact model you should use the one to many relationship by using belongsTo.
but if you have 3 table you didn't say that in you question then please edit you question and provide your models and the relations between them.
Related
In my app, you can create lists of roles that are attached to contacts. So you can assign the contact "Bob" the roles of "Gardener" and "Pet Sitter". Then you can create the list "People" and add "Gardener (Bob)" and "Pet Sitter (Bob)" to it.
I have the following tables:
contacts
id
name
roles
id
name
contact_role (pivot)
id
contact_id
role_id
lists
id
name
contact_role_list (pivot)
id
contact_role_id
list_id
Everything was working smoothly until the second pivot table linked to the first pivot table. My pivot tables are (currently) not having any models so I'm not sure if there is a built-in feature to tackle this in Laravel or if I need to think differently.
I currently have this in my List model:
public function list_roles(): BelongsToMany
{
return $this->belongsToMany(XYZ::class, 'contact_role_list', 'list_id', 'contact_role_id');
}
Is this even close? What do I put where it says XYZ::class?
Ok, so the below is doing what I want, but is there an even better way to do it? The key to solving my problem was to create a Model for ContactRole and changing extends Model to extends Pivot.
I placed this in my List Model:
public function list_roles(): BelongsToMany
{
return $this->belongsToMany(ContactRole::class, 'contact_role_list', 'list_id', 'contact_role_id');
}
And this in my ContactRole Model:
public function contact(): BelongsTo
{
return $this->belongsTo(Contact::class);
}
Now I could reach the contact data by using something like this: List::first()->contact_roles->first()->contact
Any way to use with, pivot or similar to tidy this up even more? Thanks!
I like to approach these issues in terms of Models rather than pivots. I think many new Developers in Laravel get over obsessed with what's going on in the Database which is fine, but theres a lot of Magic going on so you can write very simple code that does a lot of Heavy lifting, so that being said if I fully understand your problem
You have a Contacts Model
This model can have many roles
so in your contacts Model you need a role relationship
public function roles()
{
return $this->belongsToMany(Roles::class);
}
next of course you have a role Model (pun intended)
your each role can have many list
public function lists()
{
return $this->hasMany(List::class)
}
then the idea is now that you have roles on contacts and lists on roles you should be able to have many lists through contact
public function lists()
{
return $this->hasManyThrough(List::class, Role::class);
}
I've done similar things before and for your description it seems like that's the approach you might need to take.
I have a Laravel model called "Area" which contains "Elements".
Elements can be different Models (in this case a FreetextElement and a CheckboxElement). The whole thing is hooked up with a polymorphic pivot table,
which contains the area_id, the element_id and the element_type.
The basic relationship works fine.
If I for example say:
$area->freetextElements
Then I get all the freetextElements that are attached to that particular area.
My issue is that I'd like a relationship function, which gets all the elements that are attached to the area, regardless of their model.
Here are the areas relations:
public function freetextElements()
{
return $this->morphedByMany(ElementFreetext::class, 'element', 'coaching_element_area_element');
}
public function checkboxElements()
{
return $this->morphedByMany(ElementCheckbox::class, 'element', 'coaching_element_area_element');
}
//find a better solution for this
public function elements()
{
return array_merge( $this->freetextElements->all(), $this->checkboxElements->all());
}
The last function "elements" is just to illustrate what I'm trying to achieve.
Any suggestions? Thanks in advance.
Best Regards
So I have found a solution to this issue. It's not the cleanest solution.
So I'm still open to any additional feedback, but I thought I leave this here for other people.
I simply created a model for the pivot table entries. Area->Elements is the relationship to the pivot table entries and That pivot table model is related to the individual elements via it's own relation. Now I can chain the relation by saying: Area->Elements->Element. It's not optimal, but it gets the job done.
So I understand how to load the roles for a user and the permissions for a role.
But now I have a user table, a role table, and a permission table. I also have role_user table for linking users and roles. And of course a permission_role for linking permissions and roles.
Now when I want to get all the roles for the user, I simply do something like this:
public function roles()
{
return $this->belongsToMany('Uppdragshuset\AO\Tenant\Models\Role');
}
Similarly I can fetch permissions for roles like so:
public function permissions()
{
return $this->belongsToMany(Permission::class);
}
Now according to the documentation on laravel, I can directly fetch permissions for a user by using the hasManyThrough relation too like so:
public function permissions()
{
return $this->hasManyThrough(Permission::class, Role::class);
}
But this is returning with an error saying:
Unknown column 'role.user_id' in 'field list'
I think I understand why. Laravel is looking for user_id field in the role table but it does not understand that it is a many to many relation and it should look for it in the pivot table.
So what is the way around this? Is there a way around this in Eloquent or will I have to resort to using the query builder? And if yes, how to do the same thing with the query builder?
HasManyThrough can only be used to connect two HasMany relationships. There is no native relationship for your case.
I created a HasManyThrough relationship with unlimited levels and support for BelongsToMany:
Repository on GitHub
After the installation, you can use it like this:
class User extends Model {
use \Staudenmeir\EloquentHasManyDeep\HasRelationships;
public function permissions() {
return $this->hasManyDeep(Permission::class, ['role_user', Role::class, 'permission_role']);
}
}
I have a couple of models that I have included pivot tables for to avoid a polymorphic relation.
role table
id
name
description
restriction table
id
rule
status
restriction_role table
id
restriction_id
role_id
Reason for this setup is that both Roles and Restrictions can actually belong to multiple other models. In this case, a Role can only have 1 Restriction. I would normally define this as
class Role extends Eloquent {
public function restrictions()
{
return $this->hasOne('Restriction');
}
}
This obviously does not work because Laravel is unaware of the pivot table connecting this relation. I could easily accomplish this by using a many-to-many relationship instead, but this is not exactly how my model works. Not seeing anything in the documentation for defining this. Any thoughts?
I've solved this by using the belongsToMany relation and defining a custom accessor for it, like so:
public function foo()
{
return $this->belongsToMany(App\Bar::class);
}
public function getFooAttribute()
{
return $this->foo()->first();
}
As #deczo stated in the comments, belongsToMany() is about all that will work here. I recommend returning the first result using the first() method if you require only one result but cannot use a hasOne() relationship.
I have three tables in my database: Users, Books, and Reading. The structure of Reading is:
id, user_id, book_id
Now, I need to access to all the books that the user is reading.
First, I would like to know which kind of relationship is, one to many, many to many, Has Many Through, etc. And what do I have to specify in each model? I mean, in the users model hasMany('Reading') or whatever.
I want to access with something like this: Auth::user()->reading()->books()->get() or something similar.
The kind of relationship where one User can be reading several books and one Book can be read by many users is Many-to-Many relationship.
So, to define such a relation in Laravel you should use belongsToMany method:
class User extends Eloquent
{
function books()
{
return $this->belongsToMany("Book", "Reading", "user_id", "book_id");
}
}
class Book extends Eloquent
{
function users()
{
return $this->belongsToMany("User", "Reading", "book_id", "user_id");
}
}
$books = Auth::user()->books;
Notice, you don't need to call method ->books() but use a property ->books, otherwise you'd have to call it like Auth::user()->books()->get().