My many-to-many relations are saving data only once for each items and I can not find the mistake I possibly did when attaching multiple attributes to multiple items.
Here are my models:
Item
<?php
...
class Item extends Model
{
protected $fillable = [
'external_id',
'url',
'created_at',
'updated_at'
];
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function attributes()
{
return $this->belongsToMany(AttributeValue::class);
}
}
Attribute
<?php
...
class Attribute extends Model
{
protected $fillable = [
'name'
];
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function values()
{
return $this->belongsToMany(AttributeValue::class);
}
}
AttributeValue
<?php
...
class AttributeValue extends Model
{
protected $fillable = [
'attribute_id',
'name',
];
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function items()
{
return $this->belongsToMany(Item::class);
}
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function attribute()
{
return $this->belongsTo(Attribute::class);
}
}
As you can see, I try to separate attribute and its values for better access to each values like $item->attributes()
or $attribute->values()
.
My migrations look like this:
Item
<?php
...
class CreateItemsTable extends Migration
{
public function up()
{
Schema::create('items', function ( Blueprint $table ) {
$table->increments('id');
$table->string('external_id');
$table->string('url');
$table->timestamps();
}
}
attributes
<?php
...
class CreateAttributesTable extends Migration
{
public function up()
{
Schema::create('attributes', function ( Blueprint $table ) {
$table->increments('id');
$table->string('name');
$table->timestamps();
}
}
attribute values
<?php
...
class CreateAttributeValuesTable extends Migration
{
public function up()
{
Schema::create('attribute_values', function ( Blueprint $table ) {
$table->increments('id');
$table->text('name');
$table->integer('attribute_id')->unsigned();
$table->foreign('attribute_id')->references('id')->on('attributes')->onDelete('cascade');
$table->timestamps();
}
}
...and last but not least, the pivot table created with Jeffrey Way's cool Laravel Extended Generators
attribute value item pivot
<?php
...
class CreateAttributeValueItemPivotTable extends Migration
{
public function up()
{
Schema::create('attribute_value_item', function ( Blueprint $table ) {
$table->integer('attribute_value_id')->unsigned()->index();
$table->foreign('attribute_value_id')->references('id')->on('attribute_values')->onDelete('cascade');
$table->integer('item_id')->unsigned()->index();
$table->foreign('item_id')->references('id')->on('items')->onDelete('cascade');
$table->primary([ 'attribute_value_id', 'item_id' ]);
});
}
}
I know, this is a lot of code but I think this is neccesary for helping me with this issue.
Imagine, I am getting objects for different items with attributes like brand, size, height etc.
When I try to attach them to my pivot table like
$items = $this->getExternalItemsObject();
...
foreach($items as $item) {
$attributes = $item->Attributes->AttributesValueList;
foreach ( $attributes as $attribute )
{
$itemAttribute = Attribute::firstOrCreate([ 'name' => $attribute->Name ]);
$itemAttributeValue = AttributeValue::firstOrCreate(
[ 'name' => $attribute->Value[0] ],
[ 'attribute_id' => $itemAttribute->id ]
);
$itemAttributeValue->items()->attach($item->id);
}
Now, the when looping through the first item, everything works fine. All attribute ids are stored in the pivot table with the related item id. But for the second, third, nth item which has sometimes the same attributes like brand (let's say Nike or something like this) the relations are skipped and not beeing saved.
This is really curios and honestly drives my crazy a little bit.