Retrieve values from related table foreign key using Eloquent - laravel

Sorry if the question isn't clear.. I'm not super fluent in databases.
I have three tables:
companies equipment parts
----------- ----------- -----------
id id id
name company_id equipment_id
Using Eloquent, how do I get a Collection of all the parts that belong to the company with id=1
I know you setup relationships in the model. So now I can get all a company's equipment ($myCompany->equipment), and all equipment's parts ($myEquipment->parts), but I'm not sure how to easily get values in the reverse direction two tables away.
Thanks!

Laravel has such a beautiful documentation and API for this very thing. Take a look at the hasManyThrough relationship.
So in your Company model add this:
/**
* Get all of the parts for the company.
*/
public function parts()
{
return $this->hasManyThrough('App\Part', 'App\Equipment');
}

Related

How to use an array as a foreign key in a model and build a hasMany relationship in laravel

This is my schema as follows:
Medicines
id
price
description
etc..
Ecommerce Orders(has many Medicines)
id
user_id
products (array that holds the id's of the medicine's and quantity)
And in my EcommerceOrders Model i have
protected $casts = [
'products' => 'array',
];
public function items()
{
return $this->hasMany(Medicines::class,'id','products')->withTrashed();
}
What I'm trying to do is to create a relationship between ecommerceOrders and medicines so when i get the data of an order that a client has made i also get the data of the products he has orederd
How can i do this with the foreign key in this instance being an array
You need another table called a pivot table, "ecommerce_order_medicines" with the fields medicine_id, ecommerce_order_id, qty
You would have a record for each different medicine that belongs to the ecommerce order.
You should not store it the way you are doing right now, you won't be able to make any relationship with it stored as an array like that. You also are making it much more difficult to do any kind of reports in the future, because you won't be able to properly query your database when it's stored as an array with ID's and QTY in the same column with no relationship. You will likely have to process large sets of data through PHP instead which won't scale very well.

laravel - how to deal with model of similar type

I am trying to model a company and its relevant employee strucutre. I have 3 tables (company, position, employee) as below, and company haveMany position, and employee haveMany position. Position belongs to company, and position belongs to employee.
However, different position have some common field like onboard date, but have some fields are different. Forexmaple, CEO has a gurantee employment period, while other position dont. Quite a number of field is different too for different position.
In that case, should I using polymorphic to model? but as the company has quite a number of different position, this will create quite a lot new table in the database.
Do you have any advice on how to model different positions?
Companies
id
Position
Positions
id
type [CEO, manager, director, clerk, etc]
company_id
employee_id
Onboard Date
Ceased Date
Employees
id
position id
In that case, should I using polymorphic to model? but as the company has quite a number of different position, this will create quite a lot new table in the database.
No, why would be?
First of all, it should be manyToMany relation and not oneToMany because if you have two companies both of those can have CEO (for example) position and if you set $position->belongsTo(Company::class); it couldn't work.
It is polymorph relation there with positions as polymorphic angle of that triangle.
You would need
// companies
id
name
// employees
id
name
// positions
id
name
// positionables
position_id
positionable_id
positionable_type
With this, your models would be
class Company extends Model
{
public function positions()
{
return $this->morphToMany(Position::class, 'positionable');
}
}
class Employee extends Model
{
public function positions()
{
return $this->morphToMany(Position::class, 'positionable');
}
}
class Position extends Model
{
public function companies()
{
return $this->morphedByMany(Company::class, 'positionable');
}
public function employees()
{
return $this->morphedByMany(Company::class, 'positionable');
}
}
It allows you to set positions, companies and employees separately. Meaning, From dashboard you can make some new positions that will be available on frontend from select options let's say. Of course you should allow company and to employee to create new position (I suggest) and not just to use existing one but it could be out of scope of this question now: in example, when (and if) company creates new position (instead of selecting existing ones from options list), you would first create that position and store it into positions table and then associate company with it. Also, when using this kind of chained inputs to DB don't forget to use DB transactions. Into positionables table you would set other fields important for each relation (onboard_date, ceased_date, etc).
Documentation is very good and consult it if something is not clear (I hope it is already).
Disclaimer: I don't know rest of your project business plan and rest of project's requirements but for these three entities this is the best structure you can go with. I have set just mandatory members to models and tables for this example. Also in offered answer, I presumed use of Laravel's naming convention that's blindly followd from docs and this repo.
If the fields have no relationship with other tables, one possible way is to have a key-value table to store those fields and values:
position_fields
- id
- position_id
- key
- value
You can hence store the fields in key and the respective value in value. Then you may overwrite the __get magic method in Position model e.g.
public function __get($key){
$position_field = $this->hasMany(PositionField::class)->where('key', $field)->first();
return !!$position_field ? $position_field->value : $this->getAttribute($key);
}

Laravel belongsToMany pivot with multiple columns

I currently have two tables in the DB and a pivot table to join them when I need to do a belongsToMany lookup. The basic example is one DB table is 'teams' and the other is 'members'. I can utilize the belongsToMany method on both the team and members model to pull their relationship with each other. A team can have many members, and a member can belong to many teams.
public function teams()
{
return $this->belongsToMany(Team::class);
}
public function members()
{
return $this->belongsToMany(Member::class);
}
Pivot: team_member
team_id | member_id
---------------------
1 | 1
2 | 1
3 | 2
1 | 2
How can I expand on that pivot table to include a type of member for each team? For example, member1 is a leader on team1. member1 is an assistant on team2. member1 is a generic member on team3... and so on. Can I just add a column to that same pivot table? Would it be the membertype_id? How can I relate that to another model/table?
This is pretty common, and Laravel handles it already. Add extra columns to the pivot table and expand your relationships to use withPivot():
public function teams(){
return $this->belongsToMany(Team::class)->withPivot(["teamRole", ...]);
}
Then accessing is as simple as:
$user = \App\User::with(["teams"])->first();
$team = $user->teams->first();
$teamRole = $team->pivot->teamRole;
See the Documentation for more information:
https://laravel.com/docs/5.6/eloquent-relationships
To answer the second part, which is essentially a "Triple Pivot", that requires extra functionality. See
Laravel - Pivot table for three models - how to insert related models?
for more information, and an associated Package (by the answerer on that question, not maintained, but good for an example)
https://github.com/jarektkaczyk/Eloquent-triple-pivot

Trying to achieve a hasManyThrough type relationship

I'm trying to achieve something that is similar to Laravel's hasManyThrough, but I'm not sure my DB is set up appropriately or I'm just missing something.
I am trying to display a page for admins to show all of the sites we support. I would like to have a simple column that shows a distinct count of how many customers are attached to each site. To do this, I was going to go through the orders table and retrieve a distinct list of users, then simply use the ->count() method inside my view.
Here is my DB setup (simplified):
sites table (primary key: 'id'):
id | ...
users table (primary key: 'id'):
id | first_name | last_name | ...
orders table (primary key: 'order'):
id | order | user_id | site_id | ....
Site model:
public function customers()
{
return $this->hasManyThrough('App\User', 'App\Order', 'site_id', ' id')->distinct();
}
I realize right away that the key difference between my DB setup and the documentation is I do not have an order_id in my users table, but it doesn't make sense that I do since a user can have many orders.
It is worth noting: I also have a table user_orders. I'm not sure if I should be using that instead. user_orders has the following set up:
id | user_id | order
You can see that it is simply an intermediate table to hold connections between users and orders (remember order is the PK in orders, not id).
So, can anyone help me understand what I am doing wrong?
You could get away with a Join. I give you this sample code to guide you
public function customers()
{
return $this->hasMany('App\Order')
->leftjoin('users', 'users.id', 'orders.user_id')
->groupBy('users.id'); //Is this needed?
//Above code will return you a collection of Order though, but with the user data.
//Let's try using the User model
return App\User::whereHas('orders', function($query) use ($this->id) {
$query->where('site_id', $this->id);
})->get();
}

Mapping relationships to generic models in Datamapper for Codeigniter

I have a number of different models in a system backed by the Datamapper library for Codeigniter such as Posts and Pages and am interested in adding Likes and Comments to the system. The way I see it, Likes and Comments can apply to any sort of model that extends Datamapper. How would I go about defining such a relationship (keep Likes for any sort of model in the same table, as well as Comments)?
I tend to create separate tables for likes and comments. I usually create this sort of schema:
Likes
-----
id // autoincrement
obj // the related model (the name of the model that is being liked)
obj_id // the foreign key
user_id // the user id that liked the model object
created // timestamp
updated // timestamp
Then the comments table:
Comments
--------
id // autoincrement
obj // the related model (same as above)
obj_id // the foreign key
message // the comment itself
user_id // the user id that commented on the model object
created // timestamp
updated // timestamp

Resources