I a have pivot table and a relation on model Product:
public function product_bodies()
{
return $this->belongsToMany(static::class, 'product_bodies')->withPivot('product_id', 'product_body_id');
}
In the controller when I want to attach data:
$products = ['sadasdasd', 'asdasda', 'asdasd', 'asdasd']; //for column product_body_id
$product = Product::create($request->all());
$product->product_bodies()->attach($products);
I get the error:
General error: 1364 Field 'product_body_id' doesn't have a default
value
If I do this:
public function product_bodies()
{
return $this->belongsToMany(static::class, 'product_bodies', 'product_id', 'product_body_id')->withPivot('product_id', 'product_body_id');
}
Then all works well. But then I can't get pivot data with:
$product->product_bodies;
I get empty items..
How can I fix this problem?
Table product_bodies has 3 columns:
id
product_id
product_body_id
In product_body_id I pass strings.
I have 3 ideas:
You need to replace static::class to '\App\ProductBody' or ProductBody::class
public function product_bodies()
{
return $this->belongsToMany('\App\ProductBody', 'product_bodies')->withPivot('product_id', 'product_body_id');
}
$products must be array of product bodies ids.
$productBodiesIds = [1, 55, 66];
$product->product_bodies()->attach($productBodiesIds);
Maybe, sync instead of attach will be a better solution.
Related
I have Task model. My Task model has some relationships and it currently looks like this:
class Task extends Model
{
use HasFactory;
public $timestamps = false;
public function city()
{
return $this->hasOne(City::class, 'id', 'city_id');
}
public function type()
{
return $this->hasOne(Type::class, 'id', 'type_id');
}
public function note()
{
return $this->hasOne(Note::class, 'id', 'note_id');
}
public function operator()
{
return $this->hasOne(User::class, 'id', 'operator_id');
}
}
Now, in my TasksController I need to get Tasks that match certain criteria, like this:
$tasks = Task::whereCityId($city->id)->whereTypeId($type->id)->get()->toArray();
The problem is that fields named city_id type_id note_id operator_id will get my integer values that they have.
Instead I would like to get certain value from a related Model.
For example:
operator_id should be replaced with username from User table that corresponds to the user id.
An obvious solution to this would be to simply use foreach loop, go through my results and get the data I need and simply create another array with the information replaced, but I am not sure if this is the best idea and perhaps there is something better.
You have to change in your code:
$this->hasOne(ClassName::class, 'id', 'foreign_key');
To
$this->belongsTo(ClassName::class, 'foreign_key', 'id');
because Task's id does not available as foreign key in these tables. These table's id present in task table as foreign key so you have to use belongsTo() relationship to tell script from where these id belongs.
Then access properties like this:
$tasks = Task::with("type", "city", "operator")
->whereCityId($city->id)->whereTypeId($type->id)->get();
foreach($tasks as $task){
echo $task->city->name;
}
first you should fix your relation:
public function city()
{
return $this->hasOne(City::class,'city_id','id');
}
and so one the same error, foreign key in argument order comes before the primary key.
after that you can use addSelect:
$tasks = Task::whereCityId($city->id)->whereTypeId($type->id)
->addSelect(['userName' => User::select('name')
->whereColumn('users.id', 'tasks.operator_id')
->limit(1)])->get()->toArray();
i think this will help better than what you ask.
$tasks = Task::whereCityId($city->id)
->whereTypeId($type->id)
->with('operator')
->get()->toArray();
with('operator') is ORM feature that make you collection to include its relation as collection property. In this case it will convert to array property.
you could access it from your foreach function as
#foreach($task as $key)
$key['operator']['username']
#endforeach
Have a nice day
I'm trying to get sum of columns in relationship model but i get this error
Call to a member function addEagerConstraints() on float
Code
model
public function cableLentgh()
{
return $this->links()->sum('cable_length');
}
Logic
my model has relationship to link model like this
public function links()
{
return $this->hasManyThrough(Link::class, Segment::class, 'hthree_id', 'segment_id');
}
in links table I have column named cable_length where numbers are stored
now I want to have SUM of those numbers.
Any idea?
Update
full error detail
exception: "Error"
file: "C:\laragon\www\web\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Builder.php"
line: 578
message: "Call to a member function addEagerConstraints() on float"
If you relationship is correct then you should get the collection of links by the following call:
$this->link;
If it returns the collections, you can then run sum method of collection as below:
public function cableLentgh()
{
return $this->links->sum('cable_length'); //Notice () removed
}
I know this might not be the exact answer for your problem as you are trying to get the sum by query which is better option. As it's not working, then using collection is also an option that may solve your problem.
For me you should use the variable, and not the function link :
public function cableLentgh()
{
return $this->links->sum('cable_length');
}
I think it has something to do with the relationship ids',I would try to specify like in hasManyThrough documentation
class Country extends Model
{
public function posts()
{
return $this->hasManyThrough(
'App\Post',
'App\User',
'country_id', // Foreign key on users table...
'user_id', // Foreign key on posts table...
'id', // Local key on countries table...
'id' // Local key on users table...
);
}
}
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',);
}
I have 3 tables (items, category_questions_mapping and category_questions) in mysql database in which I have the following columns:
items table has following columns:
item_id, uuid, radius, category_id
category_questions_mapping has following columns:
category_id, category_question_id
category_questions has following columns:
category_question_id, data
I have created the model for the items table which is Items.php in which I have created the following method:
public function category_questions() {
return $this->hasOne('App\CategoryQuestionsMapping','category_id','category_id');
}
The above method is basically a relationship between category_id of the items table with the category_id of category_question_mappings table
Problem Statement:
I am wondering what changes I should make in the above method so that I am able to pull data column value from category_questions table. Is there any we can make a relationship in the above method so that it can pull the data column ?
The above method will be used in the controller for display.
To acess the category_question table columns you must define the relationship on the category_question_mapping model too, like:
public function category_questions() {
return $this->hasOne('App\CategoryQuestions','category_question_id','category_question_id');
}
then acess the field you want like $items->category_questions_mapping->category_questions->data.
By the way, I'd recommend naming the first relationship you showed like category_questions_mapping() as it is linking with the category_questions_mapping table.
You can't change only the category_questions method to solve the problem. But you can make 2 relations in 2 models and query data through 2 relations.
// App\Item
public function category_questions_mapping() {
return $this->hasOne(CategoryQuestionsMapping::class, 'category_id', 'category_id');
}
// App\CategoryQuestionsMapping
public function category_question() {
return $this->hasOne(CategoryQuestion::class, 'category_question_id', 'category_question_id');
}
// Somewhere else
// Get data:
$data = $item->category_questions_mapping->category_question->data;
// Find by data:
$items = \App\Item
::whereHas('category_questions_mapping.category_question', function ($query) {
$query->where('data', 'foo');
})
->get();
Your relationship use like this :
public function category_questions() {
return $this->belongsToMany('App\CategoryQuestions','category_questions_mapping','category_id', 'category_question_id);
}
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');