Lumen - Eloquent: Override name of joining table - php

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')
}

Related

What are the differences between viaTable() and via()?

I can't understand the difference between viaTable() and via(). Tried to search the information on the internet, but couldn't find any useful ones. Could someone explain me that? When which one should be used?
via() uses exisiting relation name so you have to create the method establishing the relation first.
viaTable() allows to connect another table "on-the-fly" so you don't have to use exisiting relation name (so you don't have to create method establishing the relation) but you need to configure it using this method's arguments.
When you are defining Many_To_Many relations you can use both, the difference is when you use via(), you need to define a relation before that (usually in your junction table's model) and use that relation with via() to define it as a Many_To_Many relation which points to the junction table's model. But when you use viaTable(), you can define Many_To_Many relations only with using the junction table's name and only between your two main table models (no need to define relation in your junction table's model).
Here is a brief explanation from Yii2 guide:
When declaring such relations, you would call either via() or
viaTable() to specify the junction table. The difference between via()
and viaTable() is that the former specifies the junction table in
terms of an existing relation name while the latter directly uses the
junction table.
Here are two examples of defining Many_To_Many relations using both approaches from Yii2 documentation (Its a Many_To_Many relation for an online market which an order can have multiple items[things that are being sold in this market] and also an item can be for multiple orders of different people or the same person):
Defining relation using via():
class Order extends ActiveRecord
{
public function getOrderItems()
{
return $this->hasMany(OrderItem::className(), ['order_id' => 'id']);
}
public function getItems()
{
return $this->hasMany(Item::className(), ['id' => 'item_id'])
->via('orderItems');
}
}
Defining relation using viaTable():
class Order extends ActiveRecord
{
public function getItems()
{
return $this->hasMany(Item::className(), ['id' => 'item_id'])
->viaTable('order_item', ['order_id' => 'id']);
}
}
P.S: I personally think using viaTable() is more logical and convenient.
P.S: You can find complete and well-explained documentation about Many_To_Many relations in Yii2 from This Section of its document.
As in Yii2 Guide ...
When declaring such relations, you would call either via() or
viaTable() to specify the junction table.
The difference between via()
and viaTable() is that the former specifies the junction table in
terms of an existing relation name while the latter directly uses the
junction table. For example,
http://www.yiiframework.com/doc-2.0/guide-db-active-record.html#junction-table

hasMany vs belongsToMany in laravel 5.x

I'm curious why the Eloquent relationship for hasMany has a different signature than for belongsToMany. Specifically the custom join table name-- for a system where a given Comment belongs to many Roles, and a given Role would have many Comments, I want to store the relationship in a table called my_custom_join_table and have the keys set up as comment_key and role_key.
return $this->belongsToMany('App\Role', 'my_custom_join_table', 'comment_key', 'role_key'); // works
But on the inverse, I can't define that custom table (at least the docs don't mention it):
return $this->hasMany('App\Comment', 'comment_key', 'role_key');
If I have a Role object that hasMany Comments, but I use a non-standard table name to store that relationship, why can I use this non-standard table going one way but not the other?
hasMany is used in a One To Many relationship while belongsToMany refers to a Many To Many relationship. They are both distinct relationship types and each require a different database structure - thus they take different parameters.
The key difference is that in a One To Many relationship, you only need the two database tables that correspond to the related models. This is because the reference to the relation is stored on the owned model's table itself. For instance, you might have a Country model and a City model. A Country has many cities. However, each City only exists in one country. Therefore, you would store that country on the City model itself (as country_id or something like that).
However, a Many To Many relationship requires a third database table, called a pivot table. The pivot table stores references to both the models and you can declare it as a second parameter in the relationship declaration. For example, imagine you have your City model and you also have a Car model. You want a relationship to show the types of cars people drive in each city. Well, in one city people will drive many different types of car. However, if you look at one car type you will also know that it can be driven in many different cities. Therefore it would be impossible to store a city_id or a car_id on either model because each would have more than one. Therefore, you put those references in the pivot table.
As a rule of thumb, if you use a belongsToMany relationship, it can only be paired with another belongsToMany relationship and means that you have a third pivot table. If you use a hasMany relationship, it can only be paired with a belongsTo relationship and no extra database tables are required.
In your example, you just need to make the inverse relation into a belongsToMany and add your custom table again, along with the foreign and local keys (reversing the order from the other model).
Try to understand with text and a figure.
One to One(hasOne) relationship:
A user has(can have) one profile. So, a profile belongs to one user.
One to many(hasMany):
A user has many(can have many) articles. So, many articles belong to one user.
Many to many(BelongsToMany):
A User can belong to many forums. So, a forum belongs to many users.

Eloquent: How to define a one-to-one relationship on the same model

Say I have a Tennis players model, and each player has a mate they're tied to for doubles games. How would I define that relationship in Eloquent? I'm used to the usual scenario in the docs (and have seen the same in many codebases) where the one-to-one relationship points to an entry in another table which makes it straight-forward where to put hasOne() and belongsTo().
A player can only have one mate plus no two players share the same mate, and their relationship is determined by the value in a mate_id field. So ideally I'd want to do $player->mate to get the mate.
So what goes in the mate() method that I'll add on the Player model, to satisfy the requirement of a hasOne() and belongsTo() as shown in the docs? Thanks
Wouldn't hasOne relation work here?
Try this in your model
public function mate()
{
return $this->hasOne('Player', 'mate_id');
}
I don't think we would need the reverse relationship, as doing $player->mate() on any one player will give the other.
You need to make new table, which might be called "mate".
mate
id
player_id (unique, not null)
player_id (unique, not null)
Then you pair them from Players table with belongsToMany().
Unique constraint says that a Player cant be in more than 1 pair.
The one-to-one as I want it works when I define only the belongsTo(), it won't work if I use hasOne() as in the other answers.
public function mate()
{
return $this->belongsTo('App\Player', 'mate_id');
}

two foreign keys, how to map with laravel eloquent

I have two tables in MySQL, where the first one is called users and the second one is called games. The table structure is as follows.
users
id (primary)
email
password
real_name
games
id (Primary)
user_one_id (foreign)
user_one_score
user_two_id (foreign)
user_two_score
My games table is holding two foreign relations to two users.
My question is how do I make the model relations for this table structure?? - According to the laravel documentation, I should make a function inside the model and bind it with its relations
for instance
public function users()
{
$this->belongsTo('game');
}
however I can't seem to find anything in the documentation telling me how to deal with two foreign keys. like in my table structure above.
I hope you can help me along the way here.
Thank you
A migration:
$table->integer('player1')->unsigned();
$table->foreign('player1')->references('id')->on('users')->onDelete('cascade');
$table->integer('player2')->unsigned();
$table->foreign('player2')->references('id')->on('users')->onDelete('cascade');
And a Model:
public function player1()
{
$this->belongsTo('Game', 'player1');
}
public function player2()
{
$this->belongsTo('Game', 'player2');
}
EDIT
changed 'game' to 'Game' as user deczo suggested.
Unfortunately the way you have this setup is not likely to work in the current context. You may have more luck with the belongsTo method, but again that only supports one relationship.
You could implement a user1() belongsTo, a user2() belongsTo and finally just declare a non eloquent function to return both (something like $users = array($this->user1(), $this->user2())

Laravel 4 One to One relationship

I would like to have a one to one relationship with a pivot table or by referencing an ID in a table.
I currently have a Films table that has a one to many relationship with a Stock table, each stock item needs a format, however I would like the formats to be a set list of formats so I created a Formats table that only has 2 columns ID and Name
Normally I would just add a Format_ID column to the Stock table however I'm unsure how this would work with the Eloquent ORM or if it's even possible / best practice
Sorry if this is hard to understand, cant quite figure out the best way of explaining it
The structure you desire is pretty standard practice. It's quite possible!
Which Eloquent relationship you'd use depends on the direction of the relationship. Each Stock has one Format (one-to-one). But each Format can be assigned to multiple Stock (one-to-many).
For the former, your Stock Eloquent model would have a hasOne() one-to-one relationship.
class Stock extends Eloquent {
public function format()
{
return $this->hasOne('Format');
}
}
For the latter, your Format eloquent model would have a hasMany() one-to-many relationship.
class Format extends Eloquent {
public function stock()
{
return $this->hasMany('Stock');
}
}
Note that having both of these defined is totally acceptable and normal. It really just depends on which direction you need your relationship to go. If you never need to look up what Stock belongs to a specific Format, you don't need the one-to-many relationship.
Also note that you may need to add a column key parameter if your column names are not easily guessable by Eloquent. E.g.:
return $this->hasOne('Format', 'my_format_id');

Categories