I have Post model with relation:
public function prices() {
return $this->morphedByMany('App\Price', 'postable');
}
I have a separate table postables with columns:
- postable_id
- postable_type
- custom (type: json)
Why when I want do: $post->pivot->custom I get null, why? When I do dd($post) column custom not found in collection.
You have to specify the custom attributes when you define the relation, like this:
public function prices() {
return $this->morphedByMany('App\Price', 'postable')->withPivot('custom');
}
If you want to cast the custom attribute, you would have to create a model for the pivot table, like this:
use Illuminate\Database\Eloquent\Relations\Pivot;
class Postable extends Pivot
{
protected $casts = [
'custom' => 'array',
];
}
Reference this model in your relation definition:
return $this->morphedByMany('App\Price', 'postable')
->using('App\Postable')
->withPivot('custom');
Now you can retrieve the value like this:
foreach ($post->prices as $price) {
echo $price->pivot->custom;
}
Related
I just have a table that has relation belongsToMany, BUT it was a mistake by developer so I can not change this structure SO I need to get only first(). However, when I take only first it return empty array but I need in object
$animals = Cat::query()->with(['types' => function($query) {
$query->first(); //wrong
}])
So how I can get only first? Because I need to order by this field and I can't because it is array
you can do this in two ways:
1- using hasOne relation:
class Cat {
public function firstType() {
return $this->hasOne(Type::class, 'type_id', 'id')->latest();
}
}
2- using staudenmeir/eloquent-eager-limit
after installing it you can write:
class Cat extends Model
{
use \Staudenmeir\EloquentEagerLimit\HasEagerLimit;
public function firstType() {
return $this->hasMany(Type::class, 'type_id', 'id')->latest()->limit(1);
}
}
class Type extends Model
{
use \Staudenmeir\EloquentEagerLimit\HasEagerLimit;
// ......
}
the advantage of HasEagerLimit trait is that you can limit the result not only to one but any number you want ...
now you can write:
$animals = Cat::query()->with('firstType');
You can add a attribute getter and set up into appends attribute. follow bellow example:
class Cat {
protected $appends = ['type'];
public function getTypeAttribute() {
// return the first element from your array of the belongsToMany relationship if it exists
return isset($this->types[0])? $this->types[0] : null;
}
}
That's important to remember this method will bring just one type. If you want to get the same type everytime, you create a diferente table where the cat table has the type_id column.
obs: Sorry for my english, it's still in working progress.
This is my tables structure:
Attribute.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Attribute extends Model
{
protected $guarded = [];
public function products()
{
return $this->belongsToMany('App\Product');
}
}
Product.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
protected $guarded = [];
public function attributes()
{
return $this->belongsToMany('App\Attribute');
}
}
I want to get the value column for each row.
What code should I write in my controller to access this value?
Laravel version: 6.9.0
Thanks
You can solve this problem by adding the following method of your end of the relationship
withPivot(['value']);
public function attributes()
{
return $this->belongsToMany('App\Attribute')->withPivot(['value']);
}
And also
public function products()
{
return $this->belongsToMany('App\Product')->withPivot(['value']);
}
When we implements Many To Many relationship,it default create a intermediate table
In your case that table is attribute_product table, we might reference this table as Pivot
table.
This tables value was retrieve by those model by pivot attribute name as follows:
$product = App\Product::find(1);
foreach ($product->attributes as $attribute) {
echo $attribute->pivot->product_id;
}
To add Extra column in (Pivot table)
By default, only the model keys [$attribute_id,$product_id] will be present on the attribute_product table. If your pivot table contains extra attributes, you must specify them when defining the relationship:
return $this->belongsToMany('App\Attribute')->withPivot('column1', 'column2','value');
To change pivot Attribute Name to your given name
you may wish to rename your intermediate table accessor to values instead of pivot.
return $this->belongsToMany('App\Attribute')
->as('values')
Then you will retrieve by $attribute->values->product_id instead of $attribute->pivot->product_id
When dealing with belongsToMany relation, you use a pivot table to record the relation.
For many pivot tables, the relations are just created and then deleted. They won't have their own property, so you never update them.
I know I can do this to auto-set both updated_at and created_at.
class Foo extends Model
{
public function bars() {
$this->belongsToMany(Bar::class)->withTimestamps();
}
}
But how to use only created_at? I have no idea.
You could take another approach:
Skip the withTimestamps() method (to avoid adding both created_at and updated_at columns).
Add a custom pivot column: created_at.
So your code:
class Foo extends Model
{
public function bars() {
$this->belongsToMany(Bar::class)->withPivot('created_at');
} // ^^^^^^^^^^^^^^^^^^^^^^^^
}
Now, with this approach you will need to set the value of created_at manually when creating records:
$foo = Foo::find(1);
$foo->bars()->attach($someId, ['created_at' => now()->format('d-m-Y H:i:s')]);
// or whatever you use as date ^^^^^^^^^^^^^
Also, this column won't be casted as a Date by default -as opposed to what Laravel do with timestamp columns- so this:
$foo->bars()->first()->pivot->created_at
won't be an instance of Carbon. If you want it though, you could create a custom Pivot model, then specify the column to cast and update your relationship to use the custom Pivot model:
Pivot model FooBar.php
class FooBar extends Pivot // <--
{
protected $casts = [
'created_at' => 'datetime:d-m-Y H:i:s',
];
}
Then in your Foo.php class:
class Foo extends Model
{
public function bars() {
$this->belongsToMany(Bar::class)->using(FooBar::class)->withPivot('created_at');
// ^^^^^^^^^^^^^^^^^^^^
}
}
I've got Tag and Attendee Eloquent models, they are in many-to-many relation. Pivot table has also two more attributes – value_int and value_string. My Attendee model looks like this:
class Attendee extends Model
{
public $timestamps = false;
protected $fillable = [
'event_id'
];
public function tags() {
return $this->belongsToMany('App\Models\Tag', 'attendee_tag', 'attendee_id', 'tag_id')
->withPivot(['value_string', 'value_int']);
}
public function scoreTagValue($tag_id) {
return $this->tags->where('tag_id', '=', $tag_id)->first();
}
}
What I want is to obtain pivot values based on Attendee model and variable tag_id, so I've written scoreTagValue function, but it always returns null and I don't know why :( I'm calling it this way:
$attendee->scoreTagValue($tag_id). Thanks for your help :)
You need to access the relation, not the property:
public function scoreTagValue($tag_id) {
return $this->tags()->where('tag_id', '=', $tag_id)->first();
}
Also, according to the docs, withPivot() does not take an array, so:
->withPivot('value_string', 'value_int');
When creating an entry using create() - Why does it return a relationship of pilot_id table instead of just showing the value of pilot_id?
For example, in the repository class:
public function createFlight()
$flight = App\Flight::create([
'name' => 'Flight 10'
'pilot_id' => 4
]);
return $flight;
}
In the controller:
public function show()
{
$data = $this->flight->createFlight();
return $data
}
It would return json on the screen but it is not showing the relationship table (pilot) of pilot_id.
Try adding the following to your Flight model, like so. By default you need to tell Laravel to include any relationships.
protected $with = ['pilot'];
That will make it so everytime it includes the relationship. If this is not desirable, then you will want to load the relationships when you return the flight, like so.
return $flight->load(['pilot']);
It shows pilot_id is 4 because that's what its value is. Did you create a relationship on the Flight so that Laravel knows how to retrieve the model for Pilot? It should look something like this:
public function pilot()
{
return $this->hasOne('App\Pilot');
}
When you return a model directly from the controller, it invokes the toJson() method to convert the object to a string. If you want to append the contents of a related model you can do so by adding the relationship to the $with variable on the Flight model.
protected $with = ['pilot']