Laravel Relationships: 3 Models - laravel

I have a problem with laravel relationships.
I have 3 models:
City —(hasMany) —>Clinic—(hasMany) —>Stock
Stock —(belongsTo) —>Clinic —(belongsTo) —>City
I need get all cities which has stocks, looks like «Stock->cities». I can write sql-query:
SELECT ct.id, ct.name
FROM CfgCity as ct
RIGHT JOIN lr_clinics AS cl ON(ct.id=cl.city_id)
RIGHT JOIN lr_clinic_stocks AS st ON(cl.id=st.clinic_id)
WHERE st.deleted_at IS NULL
GROUP BY ct.id
But I want decision in laravel-orm, because it’s more readable and I don’t need write names of rows and tables. Is it possible?
Thanks.

From your question it is clear that city has relation with clinic and clinic has relation with stock that means city has relation with stock through clinic. That you can define it using laravel relationship.
City Model
class City extends Model {
public function clinics(){
return $this->hasMany(Clinic::class);
}
public function stocks(){
return $this->hasManyThrough(Stock::class, Clinic::class);
}
}
Fetch data
$cities = City::whereHas('stocks')->get();
For details you can check https://laravel.com/docs/5.6/eloquent-relationships#has-many-through

Related

Laravel: show data in laravel with two table

I want to display data in laravel.
This is the classrooms table:
This is the students table:
this is the classroom_student table :
I expect a result like this:
With class from the classroom table, year from the student table (the year the student was created), and data from the student table (data for each month, sample data:[2,4,6] means Jan: 2, Feb: 4, Mar: 6). I don't know how to make it. Can you help me? thank you
You need to setup a many to many relationship both of your models (classroom model and student model. It will look something like this:
class Classroom extends Model {
public function students(){
return $this->hasMany(Student:class, 'student_id');
}
}
class Student extends Model {
public function classrooms(){
return $this->hasMany(Classroom:class, 'classroom_id');
}
}
Here is also a reference to laravel docs for the exact solution:
https://laravel.com/docs/8.x/eloquent-relationships#many-to-many
You Should use HasMany Relation in both Models and while fetching data call this relation function to get data related to other model and set expected title for those data in Transformer.

One To Many with pivot not possible. How to redesign relationships?

I would like to do the following:
Product can have one Supplier. The Supplier contains some data like a name. Additionally there is a pivot-value that should be stored for Supplier that is assigned to Product (e.g. a delivery_service-string).
Example:
Product: A yummy Banana
Supplier: Banana Inc
-> If the Product "A yummy Banana" is supplied by Supplier it should be delivered by DHL. The important thing: You can not add DHL as a field to Supplier, as each Product to Supplier-relation should have it's own delivery-service-field.
As there can be many Products but each Product can only have one Supplier I thought about something like this:
Product
Schema:
- id
- supplier_id
Relation
public function supplier()
{
return $this->belongsTo(Supplier::class);
}
Supplier
Schema:
- id
- name
Relation
public function products()
{
return $this->hasMany(Product::class);
}
This works, but unfortunately I can not store pivot data in the supplier() relation.
At the moment I could imagine to store the value not in a pivot table but in a new row in the Product's schema. But I don't think this is the best way.
Any suggestions? :-)
One item have many childs
This is one-to-many
You need to store item_id in your child table
Item Table
id, name
Child Table
id, item_id, type
If you have a case EG
Each child can have a favorite item then you will have to create a many-to-many relation between them. (Which will be a separate relation)
Create a table "child_item" (pivot)
Child Item Table
child_id, item_id
then create a relation in your laravel
class User extends Model{
...
public function favorites(){
return $this->belongsToMany(Items::class); // Include the path using "use" on top
}
}
So now you get your 2 relations between child and item
One item can have many children
Many children can mark items as favorites

How to convert this SQL statement to laravel code?

So I have two tables Animals and Adoptions
The animal table holds [animalID, name, DOB]
Adoptions hold [id, animalID, userID, approved]
I need to write a statement which would match the animalID in both the tables and would return the name and DOB of the animal where approved is 0.
I have hardly any previous experience with either mySQL or Laravel so my assumption would be that the SQL query would look like this:
SELECT animalName, DOB
FROM animal
INNER JOIN
Adoption ON adoption.animalID = animal.animalID
WHERE
Adoption.approved = 0
Currently I am returning all of the animals in the table. So I need to add the join and do the checking to see if the animalID in the adoptions table has a value of 0
public function available ()
{
//JOIN ANIMAL AND ADOPTION TABLES
//RETURN ALL ANIMALS WHERE APPROVED = 0
$animalQuery = Animal::all();
return view('/available', array('animals'=>$animalQuery));
}
public function available ()
{
//JOIN ANIMAL AND ADOPTION TABLES
//RETURN ALL ANIMALS WHERE APPROVED = 0
$animalQuery = Animal::select('animals.id','animals.name', 'animals.DOB')
->join('adoptions', 'adoptions.animalid', '=', 'animals.id')
->where('adoptions.approved', 0)
->get();
return view('/available', array('animals'=>$animalQuery));
}
This is my answer which worked for me
First of all, you would need two models. An Animal model and an Adoption model. Laravel uses models to access your database table.
Using the Animal model you could create a query like this:
\App\Animal::with('adoption')->select('name','dob')->get();
Then inside your Animal model, you would need to create the relationship between the animal and adoption:
public function adoption()
{
return $this->hasOne('App\Animal', 'animalID', 'animalID');
}
This would be one way to get an animal, with the adoption information.
I really recommend reading through the Laravel documentation for relationships and eloquent, and possibly read up on some SQL.
https://laravel.com/docs/5.8/eloquent
https://laravel.com/docs/5.8/eloquent-relationships
Assuming you have an Adoption model, and adoption relation on your Animal model, you can do the following:
$animals = Animal::select('animalName`, `DOB`)
->with(['adoption' => function($query) {
$query->where('approved', false);
})->get();

Double relation in eloquent, no results

TL:DR;
City model - Locations model - Offers model.
1 city hasMany locations, locations belongToMany offers
City::with('locations.offers')->where('slug','=', $city)->first();
shows 0 offers from relation even though there is an offer record connected to location (which is connected to the city).
Longer version:
I have 3 models which should be connected to each other. City, Location & Offer.
I have the given city, and want to retrieve all locations with offers which are connected to the city. In the output of:
City::with('locations.offers')->where('slug','=', $city)->first();
I see the city and all locations connected to the city. Each location has an empty offer relation.
Model City:
class City extends Model
{
public function locations()
{
return $this->hasMany('App\Location');
}
}
Model Location
class Location extends Model
{
public function city()
{
return $this->belongsTo('App\City');
}
public function offers()
{
return $this->belongsToMany('App\Offer','location_offer','offer_id','location_id');
}
}
Model Offer
class Offer extends Model
{
public function locations()
{
return $this->belongsToMany('App\Location','location_offer','offer_id','location_id');
}
}
Database is pretty basic:
city table holds the city information (id+title)
location table has city_id (and location title)
location_offer table has location_id & offer_id
offer has offer information.
Clearly I'm doing something wrong, but can't seem to figure it out. Any tips would be greatly appreciated.
Your code is perfect there is a small mistake in your relation
public function offers()
{
return $this->belongsToMany('App\Entities\Offers','location_offer','location_id','offer_id');
}
You need to check this link the third argument is wrong
The third argument is the foreign key name of the model on which you are defining the relationship, while the fourth argument is the foreign key name of the model that you are joining to:
Check the Queries
This is the one that will be executed by your code
select `offer`.*, `location_offer`.`offer_id` as `pivot_offer_id`, `location_offer`.`location_id` as `pivot_location_id` from `offer` inner join `location_offer` on `offer`.`id` = `location_offer`.`location_id` where `location_offer`.`offer_id` in ('1', '2')
See join is wrong :
join location_offer on offer.id = location_offer.location_id
This is the right one
select `offer`.*, `location_offer`.`location_id` as `pivot_location_id`, `location_offer`.`offer_id` as `pivot_offer_id` from `offer` inner join `location_offer` on `offer`.`id` = `location_offer`.`offer_id` where `location_offer`.`location_id` in ('1', '2')
join location_offer on offer.id = location_offer.offer_id

several tables with many-to-one relationship

I'm using octobercms which uses eloquent models.
I have several tables (Books, Movies, Comics...) and I need to link them to an agegroup table. Every book (movie, comic) gets exactly one agegroup.
My first intention was this:
table agegroup:
id
...
table book:
id
agegroup_id
...
table movie:
id
agegroup_id
...
But I dont get how to put that into an Eloquent model.
Bonus question: there are other similar links (every book, movie etc. has exactly one section) where I need basically the same fields as in the agegroup table: should I reuse that (how?) or create another similar table?
Relationships don't have a single direction, they're two-ways, so one-to-many is the same as many-to-one, only the perspective changes. Meaning that from one perspective a model has many others, and from the other a model belongs to another model. Even the naming used in defining the relationships is very intuitive: hasMany and belongsTo. So here's how you would configure the relationship between a Book model and a AgeGroup model.
A book belongs to only one age group:
class Book extends Model
{
public $belongsTo = [
'ageGroup' => 'Acme\Blog\Models\AgeGroup'
];
}
Then you can get the age group of a book like this:
Book::find(1)->ageGroup->name; // I'm assuming age groups have names
The revers of that relationship is that an age group can have many books associated to it:
class AgeGroup extends Model
{
public $hasMany = [
'books' => 'Acme\Blog\Models\Book'
];
}
Then you can get all books that belong to an age group like so:
foreach (AgeGroup::find(1)->books as $book) {
// access book details like: $book->title;
}
The same logic applies to movies and whatever other entities that can have one age group.

Resources