Self joins and eloquent - php

I have a user table that holds all my users. My application allows parents and their children via their own email addresses, but I need to be able to say that "child 1, is a related to parent 1 and parent 2" I want to store all this in the same table, it seems like it's a many-many relationship in so much as many users can belong to any number of other users.
How would I represent an internal many-many relationship in eloquent?
I hitting nothing but net with my attempts.

I would think you'd represent this the same way you would any other many-to-many relationship; only difference is that the same User model holds both the default and inverse relationship:
public function parents(){
return $this->belongsToMany(User::class, "users_users", "user_id", "parent_id");
}
public function children(){
return $this->belongsToMany(User::class, "users_users", "parent_id", "user_id");
}
Note: I may have user_id and parent_id backwards, but that can be adjusted easily.
The only catch I can see with this is trying to get children of children recursively, if that's a concern, but otherwise, this should work for a basic many-to-many.

Related

How do I handle multiple pivot relationships in Laravel?

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.

Lumen - Eloquent: Override name of joining table

I'm building a DB for a software where authentication is coupled with the companys LDAP Server.
I now have the two tables
AD_Groups
and
AD_Users
Which are joined in the table
AD_UsersXAD_Groups
I already learnt about establishing relationships in eloquent.
The many to many relationship is exemplified in the official docs by this:
https://laravel.com/docs/5.8/eloquent-relationships#many-to-many
Now, as you can see, the following feature of eloquent won't help me much:
"To define this relationship, three database tables are needed: users, roles, and role_user. The role_user table is derived from the alphabetical order of the related model names, and contains the user_id and role_id columns."
I therefore need to override this derived name by using the second parameter, as described here:
"As mentioned previously, to determine the table name of the relationship's joining table, Eloquent will join the two related model names in alphabetical order. However, you are free to override this convention. You may do so by passing a second argument to the belongsToMany method:
return $this->belongsToMany('App\Role', 'role_user');
But as seen in the above example from the docs, the infamous "snake case" is still applied to the name.
However, I'm affraid this might not work for my case.
Admittedly, AD_UsersXAD_Groups is pretty ugly, and I fear that eloquent/lumen will not be able to correctly identify its elements and apply the snake case rule correctly.
But I don't know for sure, and therefore I'm asking you what will be the most likely to work.
Using AD_UsersXAD_Groups or AD_UserXAD_Group
Because you have an "x", the Eloquent magic will never be able to match your table automatically.
You can override the table name in the relationship in your User model. You can also specify the keys if they are not Eloquent's expected "group_id" and "user_id":
function groups() {
return $this->belongsToMany(GroupModel::class, 'AD_UsersXAD_Groups', 'user_id_key', 'group_id_key')
}
And in your Group model you could do this to reverse it
function users() {
return $this->belongsToMany(UserModel::class, 'AD_UsersXAD_Groups', 'group_id_key', 'user_id_key')
}

Nested one to many relationships in Eloquent

Let's say I have three models with this relationsship
USER
hasMany (app/organisation)
ORGANISATION
hasMany (app/order)
ORDER
For one level I could just go
user->organisations()->get()
And get all the organisations tied to the user. But every organisation also have 0..many ORDER entities. So I want to do this:
user->organisations()->orders()->get()
To get a list of all the orders from all the organisations from a certain user. Is that possible this way?
What you can simply do is implement hasManyThrough() relationship on User model.
public function orders()
{
return $this->hasManyThrough(Order::class, organisation::class);
}
then you can query like,
$user->orders()->get();

Can two Eloquent ORM instances manipulate same DB table

I've been working with PHP for years but have never really ventured out of procedural programming except when working with things like IPB and Magento. I'm trying to advance to the next level and get a better understanding of application structures, OOP, and some common PHP frameworks. That being said, I apologize if my question sounds immature or technically incorrect, I'm new to all of this.
Anyway, I was thinking about the structure of a simple forum. Forgetting about categories, tags, users, roles, advanced editors/bbcode, etc for now and just focusing on the topics and posts...
Because a topic is essentially a series of linked posts ordered by their created_at column, is there a necessity for an actual topics table or could one not simply have a parent column in the posts table? Topics would be identified as posts with a parent equal to their own id, null or 0; something that would otherwise be unused.
If that were the db schema, how would it be laid out in the code, and if relevant, Laravel? Could you still create a Topic model? What would be the pros and cons to having two models working from a single table?
Lastly, how would you approach it if you were creating it? Would you use two tables? A pivot table? Something else? Please explain why you would implement it that way.
For the database design, self referencing tables are a valid design pattern and useful in cases of nested hierarchies such as Categories that can contain sub-categories that can also contain sub-categories ect ect... In this case sub-categories are categories that have a parent but there is no other distinction between them.
It's up to you to decide if a Topic and Post is an identical entity with a parent-child relationship. Personally the way I define the objects I don't feel they are.
The topic-post relationship you're describing is probably more of a One to Many relationship with the topic being the owner or maybe even a Many to Many relationship. This depends on the answer to, "can your topic have many posts? Can your posts be part of many topics?"
If you answered yes and no, then it is a One to Many with topics being the parent aka owner in the relationship.
If you answered yes and yes, then you have a Many to Many relationship. In SQL these are represented by a table with two columns that reference id's from two tables.
If you answered no and yes, then you have a One to Many with posts being the parent aka owner in the relationship.
In laravel, depending on the relationship, your models would include a method that looks like this:
One to Many:
class Topic extends Eloquent
{
public function posts()
{
return $this->hasMany('Post');
}
}
Laravel One-to-Many Relationships
Many to Many:
In laravel the term "pivot table" refers to the table with references to the other objects.
class Post extends Eloquent
{
public function topics()
{
return $this->belongsToMany('Topic');
}
}
class Topic extends Eloquent
{
public function posts()
{
return $this->belongsToMany('Post');
}
}
Laravel Many-to-Many
Self referencing model:
For a self referencing parent child relationship like I explained before you could create something like this, as you can see it's just a one-to-many and the many-to-one in the same model.
class Category extends Eloquent
{
public function parent()
{
return $this->belongsTo('Category', 'parent_id');
}
public function children()
{
return $this->hasMany('Category', 'parent_id');
}
}
There is also the Polymorphic Relation.
This is useful when you have the same entity with just a different type. For example in this table you can have an insurance policy for an employee and a manager. The personType column in the insurancePolicies table defines who the insurance policy belongs to.
Image from codecommit.com
Our laravel models in this case would look like:
class InsurancePolicy extends Eloquent
{
public function insurable()
{
return $this->morphTo();
}
}
class Manager extends Eloquent
{
public function insurance()
{
return $this->morphMany('InsurancePolicy', 'person');
}
}
class Employee extends Eloquent
{
public function insurance()
{
return $this->morphMany('InsurancePolicy', 'person');
}
}
Most everything of what I've explained can also be found in the laravel docs

Laravel 4 Polymorphic with multiple Pivot Tables

I'm trying to create a polymorphic relationship with multiple pivot tables. I have a table of requirements that can be assigned to accounts, roles, trips, and countries. This needs to be a many to many relationship because the same requirement could apply to multiple countries and/or trips and/or accounts etc.
I then need a table listing outstanding requirements for the user. For example: if a user has a certain account and there are requirements related to that account, then those requirements would be added to the user's list of requirements.
One solution I have is to first assign the requirements to the accounts, roles, trips, and countries using Pivot tables in a Many to Many relationship. Then using a polymorphic relationship I would connect the user to whichever pivot tables relate.
But I don't know how to do this or if it is even possible?
Here are my tables:
user_requirements
- id
- user_id
- requireable_id
- requireable_type
account_requirement
- id
- account_id
- requirement_id
role_requirement
- id
- role_id
- requirement_id
trip_requirement
- id
- account_id
- requirement_id
country_requirement
- id
- account_id
- requirement_id
Laravel 4.1 now has support for polymorphic many to many relationships.
Example below shows how I have implemented sharing Photos with both Products and Posts.
DB Schema
photos
id integer
filename string
alt string
photoable
id integer
photoable_id integer
photoable_type string
Models
Photo Model
class Photo extends Eloquent
{
public function products(){
return $this->morphedByMany('Product', 'photoable');
}
public function posts(){
return $this->morphedByMany('Post', 'photoable');
}
}
Product Model
class Product extends Eloquent
{
public function photos(){
return $this->morphToMany('Photo', 'photoable');
}
}
Post Model
class Post extends Eloquent
{
public function photos(){
return $this->morphToMany('Photo', 'photoable');
}
}
With the above, I can access all photos which are attached to a product as follows:
$product = Product::find($id);
$productPhotos = $product->photos()->all();
I can also iterate over to display all photos as any collection of models.
foreach ($productPhotos as $photo)
{
// Do stuff with $photo
}
The above can be replicated almost exactly to your requirements.
create a requirements table
create a requireable table
In Requirement model, declare all morphedByMany relationships
In Country, Trip, Role etc. declare morphToMany relationships
nb - I've typed this out freehand in S/O with no code editor, so there will probably be a typo, error or two - but concept remains the same.
A polymorphic relation in Laravel 4 is intended for single MODEL associations, therefore you cannot achieve what you are trying to build with this method. This is due to the fact that a pivot table doesn't represent a Model.

Categories