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

zaster's avatar

Livewire - File Upload Issue

The file is actually not getting uploaded to the folder. When i place a file in the folder(costing_worksheets) by renaming it as per my requirement the file(image) displays

My livewire component looks like this

<?php

namespace App\Http\Livewire;

use Carbon\Carbon;
use App\Models\Comp;
use App\Models\User;
use App\Models\Company;
use Livewire\Component;
use App\Models\Quotation;
use Livewire\WithFileUploads;

class QuotationForm extends Component
{
    use WithFileUploads;

    public Quotation $quotation;

    public $users;
    public $companies;
    public $comps;

    public $selectedUser = null;
    public $selectedCompany = null;
    public $photo;

    protected function rules()
    {
        return [
            'selectedUser' => 'required',
            'selectedCompany' => 'nullable',
            'quotation.title' => 'required',
            'quotation.date' => 'required',
            'quotation.to' => 'required',
            'quotation.address' => 'nullable',
            'quotation.description' => 'nullable',
            'quotation.comp_id' => 'required',
            'quotation.delivery' => 'nullable',
            'quotation.validity' => 'nullable',
            'quotation.costing' => 'nullable',
            'quotation.status' => 'required',
            'photo' => 'nullable|sometimes|image|max:512',
        ];

    }

    protected $validationAttributes = [
        'selectedUser' => 'Customer',
        'quotation.comp_id' => 'Comp',
        'photo' => 'attachment',
    ];

    //For real-time validation
    public function updated($propertyName)
    {
        $this->validateOnly($propertyName);
    }

    public function updatedSelectedUser()
    {
        //When a user is selected the companies related to that user should appear
        $user_id = $this->selectedUser;
        //dd($user_id);
        $user = User::findOrFail($user_id);
        $this->quotation->to = $user->name;
        $this->companies = $user->companies;
        $this->selectedCompany = $user->companies->first()->id;
        $this->quotation->to = $user->title . " " . $user->first_name . " " . $user->last_name;
    }

    public function updatedSelectedCompany($company_id)
    {
        $this->quotation->address = Company::find($company_id)->address;
    }

    public function mount(Quotation $quotation)
    {
        //FOR NEW AND EXISTING QUOTATION
        $this->quotation = $quotation ?? new Quotation();
        $this->users = User::where('is_customer', 1)->orderBy('name', 'ASC')->get();
        $this->companies = Company::all();
        $this->comps = Comp::all();

        //FOR NEW QUOTATION ONLY
        if($this->quotation->id == null)
        {
            $this->quotation->date = Carbon::now()->format('Y-m-d');

            $this->quotation->title = 'Quotation';

            $this->quotation->description = 'Item :
Qty :
Size :
Paper :
Print :
Each :
Total :';


            $this->quotation->status = "Pending";
        }
        //FOR EXISTING QUOTATION ONLY
        else
        {
            $this->selectedUser = $this->quotation->user_id;
            $this->companies = User::find($this->selectedUser)->companies;
            $this->selectedCompany = $this->quotation->company->id;
        }

    }

    public function save()
    {
        //FOR NEW AND EXISTING QUOTATION
        $this->validate();
        $imageToShow = $this->quotation->photo ?? null;

        //FOR NEW QUOTATION
        if($this->quotation->id == null)
        {
            Quotation::create([
                'user_id' => $this->selectedUser,
                'company_id' => $this->selectedCompany,
                'comp_id' => $this->quotation->comp_id,
                'comp_address' => Comp::find($this->quotation->comp_id)->address,
                'number' => $this->quotation->quotationNumber($this->quotation->comp_id),
                'date' => $this->quotation->date,
                'title' => $this->quotation->title,
                'to' => $this->quotation->to,
                'address' => $this->quotation->address,
                'description' => $this->quotation->description,
                'delivery' => $this->quotation->delivery ?? 0,
                'validity' => $this->quotation->validity ?? 0,
                'costing' => $this->quotation->costing,
                'status' => $this->quotation->status,
            ]);

            return redirect()->route('employees.quotations.edit', Quotation::latest()->first()->id);


        }

        //FOR EXISTING QUOTATION
        else
        {
            //dd($imageToShow);
            $fileName = "QID-" .$this->quotation->id . ".jpg";

            $this->quotation->fill([
                'user_id' => $this->selectedUser,
                'company_id' => $this->selectedCompany,
                'comp_id' => $this->quotation->comp_id,
                'comp_address' => Comp::find($this->quotation->comp_id)->address,
                'number' =>  $this->quotation->quotationNumber($this->quotation->comp_id, $this->quotation->id),
                'date' => $this->quotation->date,
                'title' => $this->quotation->title,
                'to' => $this->quotation->to,
                'address' => $this->quotation->address,
                'description' => $this->quotation->description,
                'delivery' => $this->quotation->delivery,
                'validity' => $this->quotation->validity,
                'costing' => $this->quotation->costing,
                'status' => $this->quotation->status,
                'photo' => $this->photo ? $this->photo->storeAs('costing_worksheets', $fileName, 'public') : $imageToShow,
            ]);

            $this->quotation->save();
            return redirect(request()->header('Referer')); //To refresh the page
        }
        return back();
    }

    public function render()
    {
        return view('livewire.quotation-form');
    }
}

<div>
    <form method="post" wire:submit.prevent="save">
    @csrf
        <div class="grid grid-cols-1 p-4 xl:grid-cols-12 gap-x-4">
            <div class="grid grid-cols-1 xl:col-span-6 xl:grid-cols-12 gap-y-4 gap-x-4">
                <div class="col-span-12 xl:col-span-6">
                    <x-jet-label for="user" value="{{ __('CUSTOMER') }}" class="font-bold text-left" />
                    <select wire:model="selectedUser"
                        class="block w-full mt-1 border-gray-300 rounded-md shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50">
                                <option value="" selected>Choose a Customer</option>
                                @foreach($users as $user)
                                <option value="{{ $user->id }}">{{ $user->name }}</option>
                                @endforeach
                        </select>
                    <x-jet-input-error for="selectedUser" class="mt-2" />
                </div>

                @if($selectedCompany == null)
                <div class="col-span-12 xl:col-span-6">
                    <x-jet-label for="company" value="{{ __('COMPANY') }}" class="font-bold text-left" />
                    <select wire:model="selectedCompany" class="block w-full mt-1 border-gray-300 rounded-md shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50">
                            <option value="" selected>Choose a Company</option>
                    </select>
                    <x-jet-input-error for="selectedCompany" class="mt-2" />
                </div>
                @else

                <div class="col-span-12 xl:col-span-6">
                    <x-jet-label for="company" value="{{ __('COMPANY') }}" class="font-bold text-left" />
                    <select wire:model="selectedCompany" class="block w-full mt-1 border-gray-300 rounded-md shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50">
                            @foreach($companies as $company)
                                <option value="{{ $company->id }}">{{ $company->name }}</option>
                            @endforeach
                    </select>
                    <x-jet-input-error for="selectedCompany" class="mt-2" />
                </div>
                @endif


            <div class="col-span-12 xl:col-span-12">
                    <x-jet-label for="title" value="{{ __('title') }}" class="font-bold text-left uppercase" />
                    <x-jet-input wire:model.lazy="quotation.title" id="title" type="text" class="block w-full mt-1"  />
                    <x-jet-input-error for="quotation.title" class="mt-2" />
                </div>

                <div class="col-span-12 xl:col-span-4">
                    <x-jet-label for="date" value="{{ __('date') }}" class="font-bold text-left uppercase" />
                    <x-jet-input wire:model.lazy="quotation.date" id="date" type="date" class="block w-full mt-1"  />
                    <x-jet-input-error for="quotation.date" class="mt-2" />
                </div>

                <div class="col-span-12 xl:col-span-8">
                    <x-jet-label for="to" value="{{ __('To') }}" class="font-bold text-left" />
                    <x-jet-input wire:model.lazy="quotation.to" id="to" type="text" class="block w-full mt-1"  />
                    <x-jet-input-error for="quotation.to" class="mt-2" />
                </div>

                <div class="col-span-12 xl:col-span-12">
                    <x-jet-label for="address" value="{{ __('ADDRESS') }}" class="font-bold text-left" />
                    <textarea wire:model.lazy="quotation.address" name="address" id="address" cols="100" rows="4" class="block w-full mt-1 border-gray-300 rounded-md shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"></textarea>
                    <x-jet-input-error for="quotation.address" class="mt-2" />
                </div>

                <div class="col-span-12 xl:col-span-12">
                    <x-jet-label for="description" value="{{ __('DESCRIPTION') }}" class="font-bold text-left" />
                    <textarea wire:model.lazy="quotation.description" name="description" id="description" cols="120" rows="7" class="block w-full mt-1 border-gray-300 rounded-md shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"></textarea>
                    <x-jet-input-error for="quotation.description" class="mt-2" />
                </div>

                <div class="col-span-12 xl:col-span-4">
                    <x-jet-label for="comp" value="{{ __('COMP') }}" class="font-bold text-left" />
                    <select wire:model="quotation.comp_id"
                        class="block w-full mt-1 border-gray-300 rounded-md shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50">
                        <option value="">Select</option>
                        @foreach($comps as $comp)
                            <option value="{{ $comp->id }}">{{ $comp->short_name }}</option>
                        @endforeach
                    </select>
                    <x-jet-input-error for="quotation.comp_id" class="mt-2" />
                </div>

                <div class="col-span-12 xl:col-span-2">
                    <x-jet-label for="delivery" value="{{ __('DELIVERY') }}" class="font-bold text-left" />
                    <x-jet-input wire:model.lazy="quotation.delivery" id="delivery" type="text" class="block w-full mt-1"  />
                    <x-jet-input-error for="quotation.delivery" class="mt-2" />
                </div>
                <div class="col-span-12 xl:col-span-2">
                    <x-jet-label for="validity" value="{{ __('VALIDITY') }}" class="font-bold text-left" />
                    <x-jet-input wire:model.lazy="quotation.validity" id="validity" type="text" class="block w-full mt-1"  />
                    <x-jet-input-error for="quotation.validity" class="mt-2" />
                </div>

                <div class="col-span-12 py-6 xl:col-span-4">
                    <x-success-button class="w-full" type="submit">
                        {{ $quotation->id ? 'Update' : 'Save' }}
                    </x-success-button>
                </div>

            </div>
            {{-- @dd($quotation->photo); --}}
            <div class="grid grid-cols-1 xl:grid-cols-12 xl:col-span-6">

                <div class="grid grid-cols-1 xl:grid-cols-12 xl:col-span-12">
                    <div class="col-span-12 ">
                        <x-jet-label for="costing" value="{{ __('COSTING') }}" class="font-bold text-left" />
                        <textarea wire:model.lazy="quotation.costing" name="costing" id="costing" cols="100" rows="15" class="block w-full mt-1 border-gray-300 rounded-md shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"></textarea>
                        <x-jet-input-error for="quotation.costing" class="mt-2" />
                        <br>

                        @if($quotation->id != null)
                            <p><b class="uppercase">attach costing worksheet</b></p>
                            <input type="file" wire:model="photo">
                            @error('photo') <span class="text-red-400 error">{{ $message }}</span> @enderror
                        @endif

                    </div>
                    <div class="col-span-12 mb-5 xl:col-span-6">
                        <x-jet-label for="status" value="{{ __('STATUS') }}" class="font-bold text-left" />
                        <select wire:model="quotation.status"
                            class="block w-full mt-1 border-gray-300 rounded-md shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50">
                                <option value="Pending">Pending - Costing is Pending</option>
                                <option value="Completed">Completed - Costing is Completed</option>
                                <option value="Sent">Sent - Quotation Sent to Customer</option>
                                <option value="Approved">Approved</option>
                        </select>
                        <x-jet-input-error for="quotation.status" class="mt-2" />
                    </div>
                </div>
            </div>
        </div>
    </form>

    <hr><hr><hr><hr><hr>
    {{-- @dd($quotation->photo) --}}
    <div class="grid grid-cols-1 p-4 xl:grid-cols-12 gap-x-4">
        <div class="col-span-12 ">
            @if ($quotation->photo)
                <p><b><u>Costing Worksheet Preview</u></b></p>
                <img src="{{ Storage::url($quotation->photo) }}" alt="costing-image">
            @endif
        </div>
     </div>
</div>

Quotation class

..
protected $guarded = [];
0 likes
5 replies
zaster's avatar

This works in the production environment. However, doesn't work in the local environment.

zaster's avatar

Ran

php artisan optimize

in the production environment and now it doesn't work again.

Sinnbeck's avatar

@zaster are you calling env() anywhere in your code? Did you try using dd() in development to inspect your data?

zaster's avatar

@Sinnbeck

are you calling env() anywhere in your code?

No

Did you try using dd()

I tried this in edit mode

$this->photo

and it returns

null

Which means nothing is getting uploaded right (that's the issue)

frankielee's avatar

have you checked the PHP errors.log(not laravel log)? or have you tried to increase the post_max_size, max_execution etc.

Please or to participate in this conversation.