Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

cotations88's avatar

Attributes Not Added To Product After Successful Save

Hi everyone, l am try laravel/livewire e-commerce project . l created attribute value table to save product attribute, but that table do not work ;please need help.

                                  <?php

namespace App\Livewire\Admin;

use Livewire\Component;
use Illuminate\Support\Str;
use App\Models\Category;
use Livewire\WithPagination;
use Livewire\WithFileUploads;
use App\Models\Product;
use App\Models\AttributeValue;
use App\Models\ProductAttribute;
use Carbon\Carbon;

class AdminAddProductComponent extends Component
{
    use WithFileUploads;

    public $name;
    public $slug;
    public $short_description;
    public $description;
    public $regular_price;
    public $sale_price;
    public $sku;
    public $stock_status = 'instock';
    public $image;
   
    public $inputs = [];
    public $attribute_arr = [];
    public $attribute_values;
    public $product_attribute_id;

    
       public function generateSlug()
    {
        $this->slug = Str::slug($this->name);
    }

    public function add()
    {
        if(!in_array($this->attr,$this->attribute_arr))
        {
            array_push($this->inputs,$this->attr);
            array_push($this->attribute_arr,$this->attr);
        }
    }

   public function remove($attr)
{
    unset($this->inputs[$attr]);
}

    public function addProduct()
    {
         $this->validate([
             'name'=> 'required',
             'slug'=> 'required',
             'short_description'=> 'required',
            'description'=> 'required',
            
         //   'images'=> 'required',
            'category_id'=> 'required',
        ]);
        $product = new Product();
        $product->name = $this->name;
        $product->slug = $this->slug;
      
        $product->featured = $this->featured;
        $product->quantity = $this->quantity;
        $imageName = Carbon::now()->timestamp.'.'.$this->image->extension();
        $this->image->storeAs('products',$imageName);
        $product->image = $imageName;
 
        $product->category_id = $this->category_id;

       if(is_integer($this->attribute_values)){
         foreach($this->attribute_values as $key=>$attribute_value)
         {
            $avalues = explode(",",$attribute_value);
           foreach($avalues as $avalue)
          {
           $attr_value = new AttributeValue();
           $attr_value->product_attribute_id = $key;
           $attr_value->value = $avalue;
           $attr_value->product_id = $product->id;
           $attr_value->save();
           }
          }
          }
     $product->save();
    
            // if(is_array($this->attribute_values)){
          //AttributeValue::where('product_id',$product->id)->delete();
        
         
        // $product->attr_value = $this->attr_value;
          
      
       
        session()->flash('message','Product has been added !');
    }


    public function render()
    {
        $categories = Category::orderBy('name','ASC')->get();
        $pattributes= ProductAttribute::all();
        return view('livewire.admin.admin-add-product-component',['categories'=>$categories,'pattributes'=>$pattributes]);
    }
}


My Model


namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class ProductAttribute extends Model
{
    use HasFactory;

    protected $fillable = [
        'name',
     ];

      public function product()
     {
      return $this->belongsTo(Product::class);
     }

     public function attributeValues()
     {
        return $this->hasMany(AttributeValue::class);
     }
}

PRoduct attribute table


namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class AttributeValue extends Model
{
    use HasFactory;

    
    protected $fillable = [
       'value',
       'product_id',
       'product_attribute_id',
    ];

     public function product()
     {
      return $this->belongsTo(Product::class);
     }

     public function pattributes()
     {
        return $this->hasMany(ProductAttribute::class);
     }
}

Table


use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('attribute_values', function (Blueprint $table) {
            $table->id();
            $table->unsignedBigInteger('product_attribute_id')->nullable();
            $table->string('value');
            $table->unsignedBigInteger('product_id')->nullable();
            $table->foreign('product_attribute_id')->references('id')->on('product_attributes')->onDelete('cascade');
             $table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('attribute_values');
    }
};
0 likes
28 replies
vincent15000's avatar

What is the type of $attribue_values ? I see the plural, is it an array ?

If yes, if(is_integer($this->attribute_values)) can only return false.

cotations88's avatar

@vincent15000 Thanks for your answer l replaced if(is_array($this->attribute_values)) but nothing changes, ATTRIBUTE_VALUES table remain blank after saving.

1 like
vincent15000's avatar

@cotations88 Now you have the answer, the variable is empty, so you know why it doesn't save anything in the database.

You need to search why the variable is empty.

cotations88's avatar

@vincent15000 l use this input to save it

@foreach($inputs as $key => $value)
    <div class="form-group">
        <label class="col-md-4 control-label">{{$pattributes->where('id',$attribute_arr[$key])->first()->name}}</label>
        <div class="col-md-12">
            <input type="text" placeholder="{{$pattributes->where('id',$attribute_arr[$key])->first()->name}}" class="form-control input-md" wire:model="attribute_values.{{$value}}" />                                        
        </div>
        <div class="col-md-12">
            <button type="button" class="btn btn-danger btn-sm" wire:click.prevent="remove({{$key}})">Remove</button>
        </div>
    </div>
@endforeach           
1 like
tangtang's avatar

@cotations88

  • does the data inserted in product table but not in attribute_value table ?
  • what desired value for this attribute_values is like 2,1,88,3,23,6,4,8 when you dd it ?

and refactor the code before this foreach

this is for comparison

your recent code

	if(is_integer($this->attribute_values)){
		foreach($this->attribute_values as $key=>$attribute_value){
			$avalues = explode(",",$attribute_value);
			foreach($avalues as $avalue){
				$attr_value = new AttributeValue();
				$attr_value->product_attribute_id = $key;
				$attr_value->value = $avalue;
				$attr_value->product_id = $product->id;
				$attr_value->save();
			}
		}
	}
	$product->save();

follow this logic for updated code

	// your other code here . . . .

	$product->save(); // move this code before foreach
	// why, because in the foreach task you call the $product->id
	// this means you need the id product is avaliable
	// without saving it first, this product id will never can be save in the attribute_values table
	// because in the migration you make it must be in the product first
	// $table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');

	// then this is for saving the data in attribute_values table

	$attributeValuesArray = explode(",", $this->attribute_values); // do the explode outside the foreach
	// avoid using is_integer, do another logic if you understand this value is represent for what
	// like is this value is string or integer or date or another type

	// this is the updated code
	foreach ($attributeValuesArray as $key => $attribute_value) {
    	$attr_value = new AttributeValue();
    	$attr_value->product_attribute_id = $key;
    	$attr_value->value = $attribute_value;
    	$attr_value->product_id = $product->id; // this is the reason why you save the product first
    	$attr_value->save();
	}

	// and here another code in your controller, I assume another code is fine

in this reference $this->attribute_values have the value like this structure "2,1,88,3,23,6,4,8"

you need to make sure how $this->attribute_values represent the data for first (even you say this is array data, the array it self have many type and can be nested array too) so you need to give the example data from this attribute_values . without that, no one can tell you how to resolve this issue.

1 like
cotations88's avatar

@tangtang Thanks for answer me.

class AttributeValue extends Model
{
    use HasFactory;

    
    protected $fillable = [
       'value',
       'product_id',
       'product_attribute_id',
    ];

If product attribute is COLOR : attribute_value = Red,Green,Black,Blue...

If product attribute is SIZE : attribute_value = S,M,L,XL,XXL,XXXL

If product attribute is wEIGHT : attribute_value = 1.50CM,1.70CM,1.90CM

Hope you see what l'am taking about.

1 like
tangtang's avatar

@cotations88

let's breakdown this issue, seems like this issue is lack of database structure or maybe you just confused how to ask what you really need.

is this input in your blade works ?

and the input displayed the data you need ?

can the user type the value of this input ?

or this input is added with another button from the blade ?

when user click this add button, the input is added to the form wih static value ?

and you have the controller to check, if this product attribute is COLOR, the add button will just add the COLOR value ?

can you tell the user story for this product (from the first time how to add product and select this attribute and then save the product) ? so we can figure out how exacly to execute this laravel code for this product controller.

1 like
cotations88's avatar

@tangtang I have impression that the database no longer works, the old databases created at the beginning (product category users) of the project work, but the new databases product_attribute ,orders and shipping address do not work. All my routes were undefined until I found a way to update them. How to update inputs and database in laravel/livewire ?

1 like
vincent15000's avatar

@cotations88 Do you respect the naming convention for the tables and the models ? If not you need to set the name of the table directly in the model like this.

protected $table = 'my_table_name';
tangtang's avatar

@cotations88

It's not like the new database table isn't running well. these table just need the right input data to work (apart from how you code it).

my base understanding from this issue.

you want to save the Product, and this product have the ProductAttribute, base on this ProductAttribute every Product can have many AttributeValue.

and I assume this Product can have many ProductAttribute too ? am I right ?

and from your code, assume this code is work.

	if(is_integer($this->attribute_values)){
		foreach($this->attribute_values as $key=>$attribute_value){
			$avalues = explode(",",$attribute_value);
			foreach($avalues as $avalue){
				$attr_value = new AttributeValue();
				$attr_value->product_attribute_id = $key;
				$attr_value->value = $avalue;
				$attr_value->product_id = $product->id;
				$attr_value->save();
			}
		}
	}
	$product->save();

using this $attr_value->product_attribute_id = $key; will not get the right id for product_attribute_id, why ? because this is from the index each array value like 0,1,2,3, etc and I guest that no id is 0 from your product_attributes table.

and other cause is just like like my first response above.

now from your question seems like you already build the form in your blade. can you show the printscreen of this form after you type all the necessary data?

cotations88's avatar

@tangtang


                       <div class="mb-3 mt-3"> 
                       <label for="name" class="form-label">Name</label>
                       <input type="text" name="name" class="form-control" placeholder="Enter Product Name" wire:model="name" wire:keyup="generate">
                       @error('name')
                       <p class="text-danger">{{$message}}</p>
                       @enderror
                       </div>
                       <div class="mb-3 mt-3"> 
                       <label for="slug"  class="form-label">Slug</label>
                       <input type="text" name="slug" class="form-control" placeholder="Enter Product Slug" wire:model="slug">
                        @error('slug')
                       <p class="text-danger">{{$message}}</p>
                       @enderror
                       </div>
                 
                       </div>   
                       <div class="mb-3 mt-3"> 
                       <label for="images"  class="form-label">Images</label>
                       <input type="file" name="images" class="form-control"  wire:model="images" multiple>
                       @if($images)
                         @foreach($images as $image)
                       <img src="{{$image->temporaryUrl()}}" width="120px">
                         @endforeach
                       @endif
                        @error('images')
                       <p class="text-danger">{{$message}}</p>
                       @enderror
                       </div> 
                         <div class="mb-3 mt-3"> 
                       <label for="category"  class="form-label">Category</label>
                       <select  name="category_id" class="form-control"  wire:model="category_id">
                            <option value="">Select Categories</option>
                        @foreach($categories as $category)
                           <option value="{{$category->id}}">{{$category->name}}</option> 
                        @endforeach                      
                       </select>
                        @error('category_id')
                       <p class="text-danger">{{$message}}</p>
                       @enderror
                       </div> 
                        <div class="mb-3 mt-3" style="display:flex;"> 
                       <label for="attr"  class="form-label" style="font-weight: bold;">Product Attribute</label>
                       <select  class="form-control"  wire:model="attr" required> 
                            <option value="0">Select Attribute</option>
                        @foreach($pattributes as $pattribute)
                           <option value="{{$pattribute->id}}">{{$pattribute->name}}</option> 
                        @endforeach                      
                       </select>
                       <div class="col-md-1">
                           <button type="button" class="btn btn-info" wire:click.prevent="add" >Add</button>
                       </div>
                        @error('attr')
                       <p class="text-danger">{{$message}}</p>
                       @enderror
                       </div> 
@foreach($inputs as $key => $value)
    <div class="mb-3 mt-3">
        <label class="mb-3 mt-3">{{$pattributes->where('id',$attribute_arr[$key])->first()->name}}</label>
   
            <input type="text" placeholder="{{$pattributes->where('id',$attribute_arr[$key])->first()->name}}" class="mb-3 mt-3" wire:model="attribute_values.{{$value}}" />                                        
        </div>
        <div class="col-md-1">
            <button type="button" class="btn btn-danger btn-sm" wire:click.prevent="remove({{$key}})">Remove</button>
        </div>
    </div>
@endforeach            
                      <button type="submit" class="btn btn-primary float-end">Submit  </button>

                     </form>
                     </div>
                     </div>
                    </div>
                </div>
            </div>
        </section>
    </main>
</div>    

LivewireComponent

<?php

namespace App\Livewire\Admin;

use Livewire\Component;
use Illuminate\Support\Str;
use App\Models\Category;
use Livewire\WithPagination;
use Livewire\WithFileUploads;
use App\Models\Product;
use App\Models\AttributeValue;
use App\Models\ProductAttribute;
use Carbon\Carbon;

class AdminAddProductComponent extends Component
{
    use WithFileUploads;

    
    

    public $inputs = [];
    public $attribute_arr = [];
    public $attribute_values = [];
    public $product_attribute_id;


       public function generateSlug()
    {
        $this->slug = Str::slug($this->name);
    }

    public function add()
    {
        if(!in_array($this->attr,$this->attribute_arr))
        {
            array_push($this->inputs,$this->attr);
            array_push($this->attribute_arr,$this->attr);
        }
    }

   public function remove($attr)
{
    unset($this->inputs[$attr]);
}

    public function addProduct()
    {
       
            'featured'=> 'required',
            'quantity'=> 'required',
             'image'=> 'required',
         //   'images'=> 'required',
            'category_id'=> 'required',
        ]);
        $product = new Product();
        $product->name = $this->name;
       
}
        $product->category_id = $this->category_id;
  if(is_array($this->attribute_values)){
         foreach($this->attribute_values as $key=>$attribute_value)
         {
            $avalues = explode(",",$attribute_value);
           foreach($avalues as $avalue)
          {
           $attr_value = new AttributeValue();
           $attr_value->product_attribute_id = $key;
           $attr_value->value = $avalue;
           $attr_value->product_id = $product->id;
           $attr_value->save();
           }
          }
          }
          dd($this->attribute_values); 
      
        //  $product->sync(AttributeValue::where('product_attribute_id',$this->product_attribute_id));
     $product->save();
    
         
tangtang's avatar

@cotations88

you haven't provided the print screen results from your form yet. but it's okay. you give the form instead.

base on your form seems like there a little miss in your foreach task in controller.

update the code base this reference and remember the $product->save(); is added before the foreach task.

// your other code . . . .

$product->save();

foreach ($this->attribute_values as $key => $attribute_value) {
	$attr_value = new AttributeValue();
	$attr_value->product_attribute_id = $this->attribute_arr[$key]; // this is the new code
	// this will added the index base on the attribute ids
	$attr_value->value = $attribute_value;
	$attr_value->product_id = $product->id; // if the produc isn't saved first, this code line will not work
	$attr_value->save();
}

// your other code . . . .

and did you try to read and analyze all the response ? seems like you just try to copy paste the code without know what or why the reason the code work or not.

so instead you understanding the code, you just give the code here, you did not even answer the related question from the respond response.

I doubt if you even read the reply. you just wait for the full code answer right ? 🤣

cotations88's avatar

@tangtang It will give

foreach() argument must be of type array|object, bool```  

This is why l try (is_integer ) or ( is_array) to  fix it 

l am tired of this error, and l am looking for another way or restart project.
tangtang's avatar

@cotations88

even using is_array or is_integer the result is always false and the foreach task will never be executed, thats why the we needs to know what the dd result of this $this->attribute_values ?

do the dd before the foreach task

it the dd is null, thats means $this->attribute_values doesn't even read on the controller.

cotations88's avatar

@tangtang Yes dd is null it is why l pasted all code here ,maybe it miss something. Product database is saving data but but attribute value table remain blank. l don't know why inputs can be add and can't save data. l'am using node 20.9 ,php 8.1.12 and laravel 10.30.0

tangtang's avatar
tangtang
Best Answer
Level 6

@cotations88

you needs to refactor the code in your form.

each time user click add attr build two inputs inside @foreach($inputs as $key => $value)

one for input type hidden, the value for this hidden inputs is attr id

and second input is for the value

with this technique you will have the array data you needs.

and for the controller the foreach task is more like this foreach ($this->inputs as $input)

1 like
cotations88's avatar

@tangtang Please l have another problem here on update $this->inputs = $product->attributeValues->where('product_id',$product->id)->unique('product_attribute_id')->pluck('product_attribute_id'); Call to a member function where() on null

tangtang's avatar

@cotations88

do the if logic before execute this where() query

if ($product->attributeValues) {
    $this->inputs = $product->attributeValues
        ->where('product_id', $product->id)
        ->unique('product_attribute_id')
        ->pluck('product_attribute_id');
} else {
    // do another code here if the  $product->attributeValues is not available
}
1 like

Please or to participate in this conversation.