How Do Inverse Relationships Work in Laravel Eloquent? - php

I have two models/tables: publisher and campaign.
Publisher
id | name
Campaign
id | name | PubID
I created a relationship to get the Publisher's campaigns.
$this->hasMany(Campaign::class, 'PubID'); /* In Publisher Model */
I believe the above line will help me to retrieve relevant campaigns, but I'm confused about the inverse relationship.
As you can see, there is no key campaign_id inside the publisher table. Would the below relationship be enough for the inverse?
return $this->belongsTo('App\Publisher'); /* In Campaign Model */
Can someone kindly guide me? I would appreciate it.

Yes, this is so called one to many relationship, which means one publisher has many campaigns. And the inverse is that a campaign belongs to a publisher.
So in order to get all the campaigns for the publisher you use:
Publisher::find($id)->campaigns;
In order to get what is the publisher of the campaign, you use:
Campaign::find($id)->publisher;
You don't need campaign_id inside the publisher table, that is known by the PubID in your campaign table.

You have two models and adding two foreign id. It is a many to many working. You just need add pivot table with campain_id and publiser_id
It’s a perfect example of many-to-many relationship: one publisher can belong to several campains, and one campains can have multiple publisher.
publishers
ID | NAME
campaigns
ID | NAME
campaign_publisher
campain_id | publisher_id
The final table in the list – campaign_publisher is called a “pivot” table, as mentioned in the topic title.
So, option 1:
class Campaign extends Model
{
/**
* The products that belong to the shop.
*/
public function publishers()
{
return $this->belongsToMany('App\Publisher');
}
}
So, option 2:
class Publisher extends Model
{
/**
* The shops that belong to the product.
*/
public function campaigns()
{
return $this->belongsToMany('App\Campaign');
}
}

You ,eed to specify the foreign key name in the belongsTo
return $this->belongsTo('App\Publisher','PubID');
Laravel Relationships

Related

One To Many (Inverse) or Many To Many?

I am struggling between to database designs:
I have Table A (Metrics) where stored app metrics for different dates and from different networks.
id
app_id
network
date
param1
param2
...
1
A_123
A
2020-12-01
2
C_123
C
2020-12-01
3
B_123
B
2020-12-01
4
A_123
A
2020-12-02
5
A_123
A
2020-12-03
5
A_456
A
2020-12-01
5
A_456
A
2020-12-02
5
B_456
B
2020-12-02
A_123, B_123 and C_123 is same app, but comes from different network, that's why I want to create mappings to give a common name.
And I have Table B (Mapping table)
id
app_id
name
1
A_123
App Name 1
2
B_123
App Name 1
3
C_123
App Name 1
4
A_456
App Name 2
5
B_456
App Name 2
Now I have One To Many (Inverse):
public function mapping() {
return $this->belongsTo('App\Models\Mapping', 'app_id', 'app_id');
}
but operations like update mapping data, seems a little difficult and not correct, because if I want to change mapping name and remove some app_id, I need to collect all TableB.id and pass it to script. And easier is just to delete([1,2,3]) and create 3 new records with new App name.
Then I thought that this is probably Many-To-Many, but seems not, because for example in Metric table for each app_id I have 10k records and if I want to map 4 id to 1 name, then for 1 mapping in table mapping_metric table would be 40k records.. and this seems is even worse then first design..
And my final thoughts, that if both methods are not working well, then probably my Metrics table not designed well or something else.
Do you have some ideas or you know some approach how can I map ids to name?
First for a good database design as our friend suggested your table have to be normalized so i suggest this illustration:
A table name apps
A table name networks
A pivot table name app_table
A table name metrics
and the relationship between them should be like:
apps belongsToMany networks (pivot:app_table)
networks belongsToMany apps (pivot:app_table)
apps hasMany app_table
app_table belongsTo apps
networks hasMany app_table
app_table belongsTo networks
app_table hasMany metrics
metrics belongsTo app_table
the only important thing is you have to make a model for your pivot itself
class App extends Model{
/**
* retrive networks
*
* #return BelongsToMany networks
*/
public function networks()
{
return $this->belongsToMany(App\Network::class, "app_table", "app_id", "network_id")
->withPivot("deleted_at")
->using(App\AppNetwork::class);
}
/**
* retrive app_networks
*
* #return hasMany [description]
*/
public function appNetworks()
{
return $this->hasMany(App\AppNetwork::class, "app_id")->withTrashed();
}
}
The Network Model Would be the Same with inverse relations.
but for pivot table model you have to extend from Illuminate\Database\Eloquent\Relations\Pivot and set public $incrementing = true; to increment id automatic
class AppNetwork extends Pivot
{
public $incrementing = true;
public function network()
{
return $this->belongsTo(App\Network::class);
}
public function app()
{
return $this->belongsTo(App\App::class);
}
public function metrics()
{
return $this->hasMany(App\Metrics::class, "app_network_id");
}
}
this were the primary relations that you can define in your for models.
for more complex relation you can define them using this tools:
hasManyThrough
eloquent join with getNamedAttribute or Laravel Scope
BelongsToThrough.

Laravel relations relation

I have an understanding issue with Laravel Eloquent Models and relations.
I have a user table user. These users can add car license plates, which I save in user_plates. I have a database which contains car models and types. The table name is cars. I have the models App\User, App\UserPlates and App\Car.
The user_plates table has the fields id,plate,user_id,car_id.
I save the plate, the associated user (in user_id) and the selected car (car_id (id from table cars))
I added plates() with belongTo function to my User Model which already successfully returns all plates associated with that user. But now I want to get the associated car (car_id inside user_plates). How do I achieve this using Eloquent? The car table does not have any connection to the user table, only user_plates has a car_id and a user_id.
I need to achieve this:
User -> Plates (can be multiple) -> Plate -> Car. I know how to achieve this using simple MySQL Joins but I want to do it right with Eloquent. Thanks for any help!
Laravel: 6.4.0
So, if your database is set up as...
users user_plates cars
----- ----------- ----
id id id
etc. plate etc.
user_id
car_id
Your models are set up as...
// in model: User
public function user_plates()
return $this->hasMany('UserPlate'); // fill out fully qualified name as appropriate…
// in model: UserPlate
public function user()
return $this->belongsTo('User');
public function car()
return $this->belongsTo('Car');
// in model: Car
public function user_plates()
return $this->hasMany('UserPlate’);
To return a collection of cars belonging to user $id you should be able to run:
$cars = User::findOrFail($id)-> user_plates->pluck('car');

Laravel: Complicated Eloquent Relationship - hasManyThrough or belongsToMany approach?

I have three Models (Organization, User, Visit) and 4 tables (organizations, users, organization_user, visits). I'm trying to get the accumulative total of user visits for an Organization.
Organization
------------
id,
name
User
---------
id,
name
Organization_User
----------------
id,
organization_id,
user_id
Visit
--------------
id,
user_id
views
Just to clarify, there is no Organization_User model, that is just the pivot table used by User and Organization:
$organization->belongsToMany('User');
$user->belongsToMany('Organization');
I could query all the user_ids from the pivot table by group_id, and then get all the visits for each user_id, but what's the more Eloquent approach?
A User hasMany Visits and a Visit belongsTo a User. A Visit doesn't belong to an Organization.
Solved it by using whereIn(). Basically with no change to my current relationship setup...to get accumulative views I did this:
$org = Organization::find($org_id);
return DB::table('visits')->whereIn('user_id', $org->users->modelKeys())->sum("views");
The modelKeys() returns all the user ids tied to that Organization. Then I get the sum of all the views for those users.
*Note it's also important to use Organization::find and not DB::table('organization') in order to maintain the Eloquent relationship. Otherwise $organization->users will give an error.
I think you might want a 'Has Many Through' relationship like so:
class Organization extends Model
{
public function visits()
{
return $this->hasManyThrough('App\Visit', 'App\User');
}
}
Then you could call count().
Laravel 5.1 doc

How to get courses through transactions table Laravel

I want to get all users with courses through transaction table.
Here is my db structure
course
id | name | description | price
transactions
id | course_id | user_id | name | description | expires
users
id | username | email
http://laravel.io/bin/da08n
I have tried with joins but it returns the same user multiple times.
DB::table('transactions')->join('users', 'transactions.user_id', '=', 'users.id')->join('courses', 'transactions.course_id', '=', 'courses.id')->distinct()->get();
How can I achieve this with Eloquent or in an other way?
Well.
you have a table called transactions, and a table of courses. Now, each transaction is related to a course.
Pay Attention: You have one record in one table which is related to another one record in another table, this is called one-to-one relationship.
In laravel, you achieve this by using Model's relationship.
You have one model called 'Transaction', and another model which is called 'Courses".
You get, for example one record from courses table by using Cources::find($myId).
Now, if you want to get a record of transactions by relating it to courses table., you should do this (in Laravel):
In your translation model define a method called course:
public function course ()
{
$this->hasOne("course"); // course is the name of another model which should be related
}
And then you use it like this:
$result = Transaction::find($myCourseId)->course();
Though for your case, you want to get many records through matching one record of a table to the another record of another table. Well:
In Transaction model add the following method:
public function Users()
{
return $this->hasManyThrough('User', 'Course');
}
With the above method you should be able to get the Users through Course method based on transactions.
More on that, please visit:
http://laravel.com/docs/eloquent#relationships

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