Retrieve from many to many relationship. Laravel - php

I'm trying to retrieve data from many to many relationship.I have two tables :
companies: [cid,name,origin]
vehicle_types: [id, type]
their pivot table: companies_vehicle_types: companies_id,vehicle_types_id
Relationship defined:
In Companies:
public function vehicle_types(){
return $this->belongsToMany('App\vehicle_types');
}
In vehicle_types
public function companies(){
return $this->belongsToMany('App\companies')->withTimestamps();
}
I want to retrieve companies where vehicle_types = specific type. How can i do that?
I tried doing following in my controller:
$vehicle_types=vehicle_types::all()->whereLoose('type','Bike');
foreach ($vehicle_types->companies as $vehicle_types) {
$company[]=$vehicle_types->pivot->name;
}
return $company;
But it doesn't seem to be working. It throws error of Undefined property: Illuminate\Database\Eloquent\Collection::$companies

Override the second, third and fouth argument in the relation if you are not following laravel's convention. See the documentation Many to Many Relation
Second argument determines the table name of the relationship's
joining table. 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:
public function vehicle_types(){
return $this->belongsToMany('App\vehicle_types', 'companies_vehicle_types', 'companies_id', 'vehicle_types_id');
}
Also, One $vehicle_type can have many companies, so:
$vehicle_types=vehicle_types::all()->whereLoose('type','Bike');
foreach ($vehicle_types as $vehicle_type) {
foreach($vehicle_type->companies as $company)
{
$company[]=$company->pivot->name;
}
endforeach
}
Again, I don't see name field in pivot table for this line to work: $company[]=$company->pivot->name;

Related

Many to many property returns null Laravel

I have two tables
booksmandala_originals and blog_categories .
Relation between these two is many to many and the pivot table name is bksm_original_categories
All other things completely works fine like data is being saved , updated but when I try to retrive data from blog_categories It gives me null even it has data like
In my
BooksmandalaOriginal.php
public function blog_categories()
{
return $this->belongsToMany('App\Models\Admin\BlogCategory', 'bksm_original_categories','bksm_originals_id','category_id')->withTimestamps();
}
In my BlogCategory.php
public function bksm_originals()
{
return $this->belongsToMany('App\Models\Admin\BooksmandalaOriginal','bksm_original_categories','bksm_originals_id','category_id')->withTimestamps();
}
My pivot migration looks like this .
Schema::create('bksm_original_categories', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedInteger('bksm_originals_id');
$table->unsignedInteger('category_id');
$table->foreign('bksm_originals_id')->references('id')->on('booksmandala_originals')->onDelete('cascade');
$table->foreign('category_id')->references('id')->on('blog_categories')->onDelete('cascade');
$table->timestamps();
}
);
When I try to retrive the booksmandala originals from blog categories like this
$category = BlogCategory::where('id',$id)->first();
$category->bksm_originals;
// It return empty array
But if I do like this .
$blog = BooksmandalaOriginal::find(1);
$blog->blog_categories;
// It return correct values
I have also tried doing this
$category = BlogCategory::find($id);
$blogs = $category->whereHas('bksm_originals', function($query) use ($category){
$query->whereIn('id',$category->id);
})->get();
It gives me this error
Argument 1 passed to Illuminate\Database\Query\Builder::cleanBindings() must be of the type array, int given
Your relationship on blog category doesn't have the correct keys set.
Read this: https://laravel.com/docs/7.x/eloquent-relationships#many-to-many
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
In addition to
customizing the name of the joining table, you may also customize the
column names of the keys on the table by passing additional arguments
to the belongsToMany method. 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
So in your case:
public function bksm_originals()
{
return $this->belongsToMany('App\Models\Admin\BooksmandalaOriginal','bksm_original_categories','category_id','bksm_originals_id')->withTimestamps();
}
Also to avoid these kinds of errors you should try to follow the Laravel naming conventions.

How to create relationship between 3 models in laravel?

SQL scheme:
bulletins
id increment
deals
id increment
seller_id
buyer_id
deals_items - items = bulletins
id increment
title
desc
bulletin_id
deal_id
How can I get deal row by bulletin id? In raw SQL it looks like:
select `deals`.* from `deals` inner join `deals_items` on `deals_items`.`deal_id` = `deals`.`id` where `deals_items`.`bulletin_id` = 10572
I tried:
public function deals()
{
return $this->hasManyThrough(DealItem::class,Deal::class, 'bulletin_id','dealid','id');
}
But it seems a wrong way. Can't find right way in laravel doc about relation.
#HCK shows right way.
but when I doing $bulletin->deals() in blade template I got empty collection of deals.
When just $bulletin->deal - all is fine, we have collection of deals.
I using protected $with = ['deals'] in my bulletin model, but what is different call method or property? Why with method empty result?
#Amarnasan was close, but the order of the foreign keys was wrong. Try this:
Deal.php
public function bulletins()
{
return $this
->belongsToMany(Bulletin::class, 'deals_items', 'deal_id', 'bulletin_id')
->withPivot('title','desc');
}
Bulletin.php
public function deals()
{
return $this
->belongsToMany(Deal::class, 'deals_items', 'bulletin_id', 'deal_id')
->withPivot('title','desc');
}
From the docs:
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');
In addition to customizing the name of the joining table, you may also
customize the column names of the keys on the table by passing
additional arguments to the belongsToMany method. 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:
return $this->belongsToMany('App\Role', 'role_user', 'user_id', 'role_id');
Update
When you access the relationship as a method: $bulletin->deals() you are accessing the relationship itself. This will return an instance of \Illuminate\Database\Eloquent\Relations\BelongsToMany (in your case). Here the query is not executed yet, so you could keep adding constrains to your query, for example:
$bulletin
->deals()
->where('seller_id', 45) // <---
->skip(5) // <---
-> ... (And so on)
When you access it as a dynamic property, you are already executing the query, so this will return a Collection instance. Is the same as calling the relationship as a method and then attach the ->get() at the end, so this two are equivalent:
$bulletin->deals()->get()
// equals to:
$bulletin->deals
Check this other answer, it answers your question.
DealClass:
public function bulletins()
return $this->belongsToMany('App\Bulletin', 'deals_items ', 'bulletin_id', 'deal_id')->withPivot('title','desc');
}
BulletinClass:
public function deals()
return $this->belongsToMany('App\Deal', 'deals_items ', 'deal_id', 'bulletin_id')->withPivot('title','desc');
}
deals model -
public function bulletins()
return $this->belongsToMany(Bulletin::class, 'deals_items ', 'bulletin_id', 'deal_id');
}
bulletin model:-
public function deals()
{
return $this
->belongsToMany(Deal::class, 'deals_items', 'deal_id', 'bulletin_id',);
}

Laravel 5.6 OneToOne relation not working

I have a BuildingImage model with a OneToOne relation to BuildingType:
BuildImage Model:
/**
* Get the source type of the Building Image.
*/
public function type()
{
return $this->hasOne('App\BuildingType');
}
BuildingType Model:
/**
* Get the Building Image that owns the building type.
*/
public function buildingImage()
{
return $this->belongsTo('App\BuildingImage');
}
My tables:
building_images table -> source is the building type id
building_types table
When I try to do this in my controller just to test:
(an ImageRequest has one or more Builings and a Building has one BuildingType)
$imageRequest = ImageRequest::findOrFail($id);
$buildings = $imageRequest->buildingImages;
foreach ($buildings as $building) {
dd($building->type);
}
I get this error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column
'building_types.building_image_id' in 'where clause' (SQL: select *
from building_types where building_types.building_image_id = 45
and building_types.building_image_id is not null limit 1)
What am I doing wrong here?
That's because by default laravel will look for a primary key named {model}_id, and given that you are using a different column name (source), you need to specify when defining the relationship:
As the documentation states:
Eloquent determines the foreign key of the relationship based on the model name. In this case, the Phone model is automatically assumed to have a user_id foreign key. If you wish to override this convention, you may pass a second argument to the hasOne method:
return $this->hasOne('App\Phone', 'foreign_key');
Additionally, Eloquent assumes that the foreign key should have a value matching the id (or the custom $primaryKey) column of the parent. In other words, Eloquent will look for the value of the user's id column in the user_id column of the Phone record. If you would like the relationship to use a value other than id, you may pass a third argument to the hasOne method specifying your custom key:
return $this->hasOne('App\Phone', 'foreign_key', 'local_key');
Now that that is clear. Let's talk about the relationship itself.
You are defining that a BuildImage has one BuildingType. But with that logic, the foreign key should be stored in the building_types table, and not the other way around (source column appears in the building_images table). And -I'm just assuming that- many BuildImage can belongs to an specific BuildingType. So, if this assumption is correct:
a BuildImage belongs to a specific BuildingType.
a BuildinType can be specify in many BuildImages
So, you should define your relationship like this:
BuildImage.php
public function type()
{
return $this->belongsTo('App\BuildingType', 'source');
}
BuildingType.php
public function images()
{
return $this->hasMany(BuildingImage::class, 'source');
}
Your BuildImage model should be
/**
* Get the source type of the Building Image.
*/
public function type() {
return $this->hasOne('App\BuildingType',"id","source");
}
And BuildingType Model should be
/**
* Get the Building Image that owns the building type.
*/
public function buildingImage()
{
return $this->belongsTo('App\BuildingImage',"source","id");
}
This should work.
For more info have a look
https://laravel.com/docs/5.7/eloquent-relationships#one-to-one
Have you tried to indicate the index ID like this?
public function buildingImage()
{
return $this->belongsTo('App\BuildingImage', 'image_request_id');
}
Eloquent determines the foreign key of the relationship based on the
model name. In this case, the Phone model is automatically assumed to
have a user_id foreign key. If you wish to override this convention,
you may pass the second argument to the hasOne method:
return $this->hasOne('App\Phone', 'foreign_key');
https://laravel.com/docs/5.7/eloquent-relationships#one-to-one

Accessing values from laravel Many to Many relationship

I have two tables doctors and specializations and a pivot table doctor_specialities.
In Doctor model, I have defined relationship like this-
public function specializations(){
return $this->belongsToMany('App\Specialization', 'doctor_specialities', 'speciality_id', 'doctor_id');
}
And in the Specialization model, the relationship is like this-
public function doctors(){
return $this->belongsToMany('App\Doctor', 'doctor_specialities', 'speciality_id', 'doctor_id');
}
I am getting all the doctors of a specialization like this-
$doctors = Specialization::find($request->specialization)->doctors
->where('city_id', $request->city);
It's working fine. I am getting the correct output.
But now I want to print all the specializations of each doctor but it is returning an empty array.
foreach ($doctors as $doctor) {
var_dump($doctor->specializations);
}
The output I'm getting is-
object(Illuminate\Database\Eloquent\Collection)[218]
protected 'items' =>
array (size=0)
empty
How can I print specializations of each doctor??
For your updated question, while defining the specializations relation on the Doctor model, the third argument is the foreign key name of the model on which you are defining the relationship (Doctor in your case), while the fourth argument is the foreign key name of the model that you are joining to (Specialization). The relationship should be defined as follows:
public function specializations(){
return $this->belongsToMany('App\Specialization', 'doctor_specialities', 'doctor_id', 'speciality_id');
}
Please refer the documentation here.
are you sure you are getting a single doctor? how is it possible to get single doctor while querying for Specialization?
$specialization = Specialization::find($request->specialization)->doctors
->where('city_id', $request->city);
i guess you are not clear about what you are trying to achieve?
if you want doctors of a particular specialization you should do this;
$specialization = Specialization::with(['doctors' => function ($query) {
$query->where('city_id', $request->city);
}])->find( $request->specialization);
and loop through doctors
foreach($specialization->doctors as $doctor){
do what ever you want
}

Laravel eager relationships empty query

I have 3 tables : hotels, hotels_data, hotels_types
Table hotels have id, type, stars, etc... type field is set as foreign key referencing type_id in hotels_types. I'm managing to get the correct data from hotels_data but have an empty result on getting hotels_types title and I don't understand why.
The code is the following :
class Hotel extends Eloquent {
public function getList() {
$data = Hotel::select('id','stars')->with('HotelData', 'HotelType')->paginate(10);
return View::make('hotels.index')->with('hotels', $data);
}
public function HotelData()
{
return $this->hasOne('HotelsData')->select('id','hotel_id','title');
}
public function HotelType()
{
return $this->hasOne('HotelType','type_id', 'type')->select('id','type_id','title');
}
}
You're using the wrong relationship for HotelType()
Your Hotel model should use the inverse of hasOne, which is belongsTo, because it contains the foreign key to HotelType (when a table contains a foreign key, it always belongs to the table being pointed to).
The following should work:
public function hotelType() {
return $this->belongsTo('HotelType','type', 'type_id')->select('id','type_id','title');
}
I've obtained the desired result with the following:
Hotel::select('hotels.*','hotels_types.title as type')
->join('hotels_types', 'hotels.type', '=', 'hotels_types.type_id')
->with('HotelData');

Categories