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

kendrick's avatar

Image upload with Pivot Table (foreach loop)

Hello Community,

I am currently working on the Product Creation, so my authenticated business can create products. Therefore I want to provide a multiple Image upload for the product with an Pivot Migration (product_images) to store the images.

Problem

I am facing some problems with my Product Upload Controller, which doesn't find the Pivot column product_image. Plus, I am not sure if the Loop is working.

Would be happy about your expertise.

Image input:

(input type="file" name="images[]" multiple="true" /)

ProductUploadController:

$update = Auth::user()->products()->create([
            'business_id' => auth()->user()->id,
            'title' => $request->title,
            +++
            'price' => $request->price,
            'availability' => $request->availability,
            'product_image' => $request->product_image,
            
        ]);

        if($request->file('images')){

            $business = Auth::user();
            $image   = $request->file('images');

        foreach ($image as $product_image) {
                $filename = time() . '.' . $image->getClientOriginalExtension();            
                $location = public_path('uploads/business/products/'. $filename );          
                Image::make($image)->resize(812, null, function ($constraint){$constraint->aspectRatio();})->save($location);
                
                $product_image = new Picture;
                $business->product_image = $filename;
                $business->$product->products()->save($product_image);
                $business->save();
        }   
        }

Pivot Table: product_images:

public function up()
    {
        Schema :: create ('product_images', function(Blueprint $table){
            $table->increments('id');
            $table->unsignedInteger('product_id'); // 
            $table->string('product_image')->default('productdefault.jpg');
            $table->timestamps();
    });
    }

Product.php Model:

protected $fillable = [ 
        'title',
        +++
        'availability',
        'product_image',
    ];

    public function business()
    {
        return $this->belongsTo(Business::class, 'business_id');
    }

    public function images()
    {
          return $this->hasMany(Picture::class);
    }

Picture.php Model

    protected $table = 'product_images';
    protected $fillable = [ 
        'product_image',     
    ];

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

Error: Cant find the product_image Pivot column

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'product_image' in 'field list' (SQL: insert into `products` (`title`, `price`, `availability`, `product_image`, `business_id`) values (MM, 09, MM, , 1))

Thank you

0 likes
49 replies
Snapey's avatar

save all the headaches and just use spatie media library. You can attach media to any model with a simple trait addition

3 likes
kendrick's avatar

Hey @snapey Already installed it as a requirement, plus read the documentation. But there are some questions left.

$newsItem->addMediaFromRequest('image')->toCollection('images');

How would my loop look like for the image upload, like so?

foreach($request->file('images') as $image) {
            $message->addMedia($image)
                    ->toMediaLibrary();;
        }

Snapey's avatar

try

foreach($request->file('images') as $image) {
    $message->addMediaFromRequest($image)
        ->toCollection('images')
        }

kendrick's avatar

Syntax Error @snapey

Parse error: syntax error, unexpected '}'
foreach($request->file('images') as $image) {
            $business = Auth::user();
            $message->addMediaFromRequest($image)
                ->toCollection('images')
         }
        

Snapey's avatar

error will tell you which line its on...

Snapey's avatar

missing semicolon on previous line

kendrick's avatar

@snapey Content such as Price, Title, Brand etc, will be stored within DB, but image will not be stored within media table.

Invalid argument supplied for foreach()

Snapey's avatar

you have to actually read the instructions

kendrick's avatar

@Snapey

I edited my Model like this, but I don't get it yet.

Product.php Model:

use Spatie\MediaLibrary\HasMedia\HasMediaTrait;
use Spatie\MediaLibrary\HasMedia\Interfaces\HasMedia;


class Product extends Model implements HasMedia
{
    use HasMediaTrait;

    protected $guard = 'partner';
    
    protected $table = 'products';
    
    
    protected $fillable = [ 
        'title',
        'brand',
        'price',
        
    ];

     
    public function business()
    {
        return $this->belongsTo(Business::class, 'business_id');
    }

The error:

at HandleExceptions->handleError(2, 'Invalid argument supplied for foreach()', '/home/vagrant/app/Http/Controllers/ProductUploadController.php', 55, array('request' => object(Request), 'update' => object(Product)))
in ProductUploadController.php (line 55)

Structure within the ProductUploadController:

Validation

$update = Auth::user()->products()->create([
            'business_id' => auth()->user()->id,
            'title' => $request->title,
            'brand' => $request->brand,
            'price' => $request->price,
        ]);

        foreach($request->file('images') as $image) {
            $message->addMediaFromRequest($image)
                ->toCollection('media');
         }

kendrick's avatar

@Snapey

I am using the Product.php Model for the creation of a product, so I need another Model called Media in which I reference the relationship to my product?

Snapey's avatar

so first of all, referencing the array of images is not working. How are they being passed from the form?

next, you need to attach the images to the model just created, which somewhat confusingly you have called update, so this needs to be mentioned in your loop and not $message

first though, work out how to iterate over the multiple images with

foreach($request->file('images') as $image) {
      dump($image);
 }
die;

here you are not using the media library at all, just checking the files are being passed

1 like
Snapey's avatar

try this instead

foreach($request->images as $image) {
      dump($image);
 }
die;
1 like
kendrick's avatar

Thank you again @Snapey

The files will be passed

"118_TreeofLife_1200-900.jpg"
"T03254_10.jpg"

The form:

(form enctype="multipart/form-data" action="/success" method="POST")
    (input type="file" name="images[]" multiple="true" /)
(/form)

How do I attach the images to the Product Model? Because within the media migration there are columns such as model_id, model_type, collection_name, name, file_name etc & so I don't know how to pass data to the Media table, because I am not sure if I need a Media.php Model or if it is like integrated already in the package?

Snapey's avatar

no you dont need a model

once you can iterate over the files just add them to your model.

your final code should look like


$product = Auth::user()->products()->create([
            'business_id' => auth()->user()->id,
            'title' => $request->title,
            'brand' => $request->brand,
            'price' => $request->price,
        ]);

        foreach($request->images as $image) {
            $product->addMediaFromRequest($image)
                ->toMediaCollection('images');
         }

the media is attached to the product due to the trait that you added to the Product model

1 like
kendrick's avatar

@snapey Ok, thanks

Now I got this error:


The current request does not have a file in a key named `118_TreeofLife_1200-900.jpg`

at RequestDoesNotHaveFile::create('118_TreeofLife_1200-900.jpg')
in FileAdderFactory.php (line 33)

kendrick's avatar

Still because the files uploaded as an array in the form doesn't work? @Snapey

Snapey's avatar

ok, ive never added multiple files so reading the docs you need to pass the key to each file rather than the uploaded file object

option 1

foreach($request->images as $key => $image) {
            $product->addMediaFromRequest($key)
                ->toMediaCollection('images');
         }

option 2

$files =$product->addAllMediaFromRequest();

foreach($files as $file) {
    $file->toMediaCollection('images');
}
1 like
kendrick's avatar

@Snapey

Option 1 returns error:

(1/1) RequestDoesNotHaveFile
The current request does not have a file in a key named `0`

Option 2 works, creates product, but stores no images in the Media Table

Snapey's avatar

this is frustrating because issues resolved simply take so long this way

            $product->addMediaFromRequest("images[{$key}]")
                ->toMediaCollection('images');
         }

1 like
kendrick's avatar

@Snapey I really appreciate your great patience and help, plus I am sorry for the frustrating energy.

Now it results in:

The current request does not have a file in a key named `images[0]`

Snapey's avatar

can you try something for yourself? like checking that you are actually getting some images passed to the controller?

Have you set your form up to send files? Does your form tag contain enctype="multipart/form-data" ?

kendrick's avatar

Thank you again @Snapey Form contains enctype tag

(form enctype="multipart/form-data" action="/success" method="POST")
    (input type="file" name="images[]" multiple="true" /)
(/form)

Also wrapped the foreach loop into if statement, doesn't result in error, but still won't store the images.

I will try if it works with a normal eloquent relationship, but thank you again for your great patience. It's an honor for me, to chat about solutions with you. Thanks

Snapey's avatar

if ypu are not getting instances of UploadFile class then it does not matter how you try and save them

kendrick's avatar

@Snapey

Anything striking about this eloquent relationship? (product created, images not stored)

Picture.php

public function products(){
        return $this->belongsTo(Product::class, 'product_id');
}

Product.php

public function pictures(){
          return $this->hasMany(Picture::class, 'product_image');
}

Pictures Table:

 Schema :: create ('pictures', function(Blueprint $table){
            $table->increments('id');
            $table->unsignedInteger('product_id'); // 
            $table->string('product_image')->default('productdefault.jpg');
            $table->timestamps();
 });

Controller:

if ($request->hasFile('images')) {
    foreach ($images as $image) {
        $image = $request->file('product_image');
        $filename = time() . '.' . $image->getClientOriginalExtension();
        $location = public_path('uploads/business/products/'. $filename );          
            Image::make($image)->resize(812, null, function ($constraint){$constraint->aspectRatio();})->save($location);
    }

    $product->pictures()->save($picture);
}
Snapey's avatar

Thought we established that you are not getting any files in your controller?

dd($request->images); and post the result

1 like
kendrick's avatar

Yes, it won't get any files. @Snapey

Yesterday it displayed the files with

foreach($request->images as $image) {
      dump($image);
 }
die;

, but now it doesn't. this is crazy

kendrick's avatar

I'm sending everything through one form with the enctype=multipart/form-data, also the other inputs with type=text. May this be a problem? @Snapey

Snapey's avatar

No. But it does depend on the accuracy of your form Can you show it?

1 like
kendrick's avatar

@snapey Form:

(form enctype="multipart/form-data" action="/success" method="POST")

        (h1 class="qsetp") Images/h1)
                                
        (input type="file" name="images[]" multiple="true" /)
        (hr)

        (h3 class="qsetp")Title(/h3)
        (div class="container" id="editedit11")
        (div class="form-group{{ $errors->has('title') ? ' has-error' : ''}}"")
        (input type="text" name="title" class="form-control" id="editfields22" placeholder="Title")
        @if ($errors->has('title'))
            (span class="help-block"){{ $errors->first('title') }}(/span)
        @endif          
        (/div)  
        (/div)

               (div class="form-group")
           (button type="submit" class="btn btn-default" id="button-profile")Create(/button)
        (/div)
            (input type="hidden" name="_token" value="{{ Session::token() }}")
                                
(/form)

'(' equals '<' / ')' equals '>'

Next

Please or to participate in this conversation.