I am trying to find out the best way to define the following relation using Laravel's Eloquent Laravel.
I have a User table and 3 Objects ( Player, Team, League) that the user can add as favorites.
I know I can create three pivot tables with the User Model and each one of the objects but then I will need to run a Union query to list all favorites from user regardless of type.
User
id
Favorite
id
user_id
favorited_id ( player_id or team_id or league id)
favorite_type ( player , team or league)
Player
id
Team
id
League
id
Here is my model.
https://www.dropbox.com/s/6au8giufaejcghc/Screen%20Shot%202014-04-07%20at%209.06.51%20AM.png
i'd do it the same with a Favourite table. laravel covers this with its polymorphic relations.
your tables could look like
class Favourite extends Eloquent {
public function favourable()
{
return $this->morphTo();
}
}
class Team extends Eloquent {
public function favourite()
{
return $this->morphMany('Favourite', 'favourable');
}
}
...
your Favourite table would look like
Favourite
favourable_id: int
favourable_type: string
you'd call it like a normal property on the model like $player->favourable().
You can either use polymorphism as suggested by user3158900, or my preference would be to use Laravel's Query Builder to perform the Union query.
http://laravel.com/docs/queries#unions
$first = DB::table('users')->whereNull('first_name');
$users = DB::table('users')->whereNull('last_name')->union($first)->get();
Related
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');
I am new in laravel, I already know how to join tables using the query builder. I just like to learn how to use relationships to avoid repetition of codes and to simplify it. I can join 2 tables, but I can't get the 3rd table.
I like to display employees assigned tasks information from the Tasks table, this table only has the project id that needs to be joined to the Projects table. Other employees can join in existing projects with other employees.
Employee model:
public function tasks()
{
return $this->hasMany('\App\Task', 'project_coder', 'id');
}
Task model:
public function projects()
{
return $this->hasMany('\App\Project', 'id', 'project_id');
}
Projects model:
public function belongsToTasks()
{
return $this->belongsToMany('\App\Task', 'project_id', 'id');
}
I can only get the IDS from Task model. the ID will be use to fetch the project info from project tables. Unfortunately I cant do that part.
Employees controller:
public function show($id)
{
$data = Employees::find($id);
return view('show-employee')->withInfo($data);
}
Is it good practice to use query builder rather than relationships?
UPDATE:
Employees table
{
"id":1,
"name": "Juan"
}
Tasks table
{
"id":1, // autoincrement and will not be use for linking to other tables.
"project_id": 1, //use to connect to project table
"project_coder": 1 // use to connect to employees table
}
Projects table
{
"id":1,
"name": "First Project"
}
To deal with this is best to create pivot table like employee_task
where table will have just two columns task_id and employee_id
then you can define in Task model
public function employees()
{
return $this->belongsToMany('\App\Employee', 'employee_task');
}
and Employee model
public function tasks()
{
return $this->belongsToMany('\App\Task', 'employee_task');
}
now you can see all employee tasks and rest of you relations work just fine
$data = Employees::find($id);
$data->tasks //you get all tasks assigned to this employee
$data->tasks()->first()->projects //you get all your projects for first task
$data->tasks()->first()->employees //all employees assigned to first task with this employee
Also recommend to you to lookup pivot tables, attach(), detach() and sync() functions. you can check it here : https://laravel.com/docs/5.7/eloquent-relationships#updating-many-to-many-relationships
UPDATE:
Ok I understand now what you are trying to do. You already have pivot table. I was little confused with your Project model which is not necessary.
You can remove your Project class if you have it just for this relation
and update your model relations as I wrote above. You don't need project_id and project_coder_id in this relation. Also change the column names to more conventional names like employee_id and task_id as I mentioned or whatever your table names are.
And you can rename employee_task pivot table name to your project table or you can rename it as well.
EDIT
When you use Project model for another data, you need to create 4th table as I mentioned above.
FINAL
drop project_coder column in Tasks table - unecessary column
create pivot table employees_task with employee_id,task_id
create mentioned relations with pivot table
I assume that Project hasMany() tasks and Task only belongsTo() one project. So need to create these relations as well.
Then you can use these relations like this:
$employee = Employee::find($id);
$task = Task::find($id);
$project = Project::find($id);
$employee->tasks //all tasks assigned to employee
$task->employees //all employees assigned to task
$task->project //project info assigned to task
$employee->tasks()->first()->project //project data from first task of employee
$project->tasks()->first()->employees //all employees assigned to first project task
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
I have two tables:
treatments (
id,
name
)
companies (
id,
name
)
And I need to build a relation to a "price" table. I thougth in something like follows:
prices (
treatment_id,
company_id,
price
)
But i don know how to apply the ORM to a php aplication. I'm using Laravel with Eloguent's ORM. I think that the real question would be if this is a good way to design the db. Perhaps I should make it diferent?
Any advices?
Thanks,
Ban.
If a Company can have multiple Treatments and a treatment can be bought from multiple companies at different prices, then you have a Many-to-many relationship, with prices being the pivot table (which if you would adhere to convention would be named company_treament, but that's not a must). So you'll need to have two models for Treatments and Companies, which would look like this:
class Company extends \Eloquent {
public function treatments()
{
return $this->belongsToMany('Treatment', 'prices')->withPivot('price');
}
and
class Treatment extends \Eloquent {
public function companies()
{
return $this->belongsToMany('Company', 'prices')->withPivot('price');
}
}
The treatments() and companies() methods from the models are responsible for fetching the related items. Usually the hasMany method only requires the related model as the first parameter, but in your case the pivot table name is non-standard and is set to prices by passing it as the second parameter. Also normally for the pivot table only the relation columns would be fetched (treatment_id and company_id) so you need to specify the the extra column using withPivot. So if you want to get the treatments for a company with the id 1 list you whould to something like this:
$treatments = Company::find(1)->treatments;
The opposite is also true:
$companies = Treatment::find(1)->companies;
If you need to access the price for any of those relations you can do it like this:
foreach ($treatments as $treatment)
{
$price = $treatment->pivot->price;
}
You can read more about how to implement relationships using Eloquent in the Laravel Docs.
EDIT
To insert a relation entry in the pivot table you can use attach and to remove one use detach (for more info read the Docs).
$treatment->companies()->attach($companyId, array('price' => $price));
$treatment->companies()->detach($companyId);
To update a pivot table entry use updateExistingPivot:
$treatment->companies()->updateExistingPivot($companyId, array('price' => $price));
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.