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

vainway 's avatar

Error Call to a member function store() on null

am getting this error above I don't where it's coming from I have been using the same method for a long time with no problem. or getting another error that resume is required even though it is added Experiences.php

<?php

namespace App\Http\Livewire;

use Livewire\Component;
use App\Models\Skill;
use App\Models\Language;
use App\Models\Experience;
use App\Models\SelectOption;
use Illuminate\Http\Request;
use Livewire\WithFileUploads;

class Experiences extends Component
{
    use WithFileUploads;

    public $degree;
    public $lesson_type = [];
    public $resume;

    public $language;
    public $proficiency;
    public $selectedSkills = [];
    
    public $Selectedlanguage = [];
    public $allLanguages = [];

    protected function rules ()
    {
        return [
            'position_title' => 'required|min:3',
            'job_type' => 'required',
            'resume' => 'required|file|mimes:png,jpg,pdf|max:5120',
            'selectedSkills' => 'required|array|max:6',
        ];
    }

    public function mount()
    {
        $this->language = Language::where('language', 'English')->get();

        $this->allLanguages = Language::all();
        // $this->Selectedlanguage = [
        //     ['language_id' => '23', 'proficiency' => '']
        // ];
    }

    public function addLanguage() {
        $this->Selectedlanguage[] = ['language_id' => '', 'proficiency' => ''];
    }

    public function removeLanguage ($index) {
        unset($this->Selectedlanguage[$index]);
        $this->Selectedlanguage = array_values($this->Selectedlanguage);
    }
    
    public function render()
    {
        $this->skills = Skill::all();
        $this->select = SelectOption::all();
        return view('livewire.experiences', [
            'skills' => $this->skills,
            'select' => $this->select
        ]);
    }

    public function updated($field) 
    {
        $this->validateOnly($field);
    }

    public function Experience (Request $request)
    {
        $this->validate();

        $path = $this->resume->store('public/storage/Resumes');

        $experts = Experience::create([
            'degree' => $this->position_title,
            'lesson_type' => $this->job_type,
            'resume' => $path,
        ]);

        $experts->skills()->attach($this->selectedSkills);

        foreach($request->Selectedlanguage as $language) {
            $experts->languages()->attach($language['language_id'], ['proficiency' => $language['proficiency']]);        
        }
        
        return redirect()->back()->with('success', 'Your Post was posted Successful');
    }
}

experience.blade.php

<div class="current-step">
            <div class="form-group">
                <label>Add your Degree.</label>
                <input type="text" wire:model="degree" placeholder="Ex: Bachelor Degree" class="form-control @error('degree') is-invalid @enderror" required>
                @error('degree')
                    <span class="invalid-feedback" role="alert">
                        <strong>{{ $message }}</strong>
                    </span>
                @enderror 
            </div>
            <div class="form-group">
                <label for="lesson_type">learning Day Session</label>
                <div class="form-check">
                    <label class="form-check-label">
                        <input class="form-check-input" type="checkbox" wire:model="lesson_type" value="yes"> {{ __('Yes') }}
                        <span class="form-check-sign">
                            <span class="check"></span>
                        </span>
                    </label>
                </div>
                <div class="form-check">
                    <label class="form-check-label">
                        <input class="form-check-input" type="checkbox" wire:model="lesson_type" value="daily"> {{ __('No, only Daily Notes.') }}
                        <span class="form-check-sign">
                            <span class="check"></span>
                        </span>
                    </label>
                </div>
                <div class="form-check">
                    <label class="form-check-label">
                        <input class="form-check-input" type="checkbox" wire:model="lesson_type" value="switch"> {{ __('reading books') }}
                        <span class="form-check-sign">
                            <span class="check"></span>
                        </span>
                    </label>
                </div>
                @error('lesson_type')
                    <span class="invalid-feedback" role="alert">
                        <strong>{{ $message }}</strong>
                    </span>
                @enderror                      
            </div>
        </div>
        <div class="current-step">
            <div class="row">
                <div class="col-lg-12">
                    <div class="form-group">
                        <label>Add Your Skills</label>
                        <div wire:ignore class="bootstrap-tagsinput info-badge">
                            <select wire:model.defer="selectedSkills" class="form-control js-select2-multi" data-placeholder="Enter Skills here..." multiple>                            
                                @foreach($skills as $skill)
                                    <option value="{{ $skill->id }}">{{ $skill->name }}</option>
                                @endforeach
                            </select>
                        </div>
                        @error('selectedSkills')
                            <span class="invalid-feedback" role="alert">
                                <strong>{{ $message }}</strong>
                            </span>
                        @enderror
                    </div>
                </div>
            </div>
            <div class="row">
                <div class="col-lg-12">
                    <div class="language-table">
                        <label>which languages you speak.</label>
                        <p>do you speak any other languages?.</p>
                        <div class="table-responsive">
                            <table id="myTable" class="table">
                                <thead class=" text-primary">
                                    <th>Languages</th>
                                    <th>Proficiency</th>
                                    <th>Options</th>
                                    <th></th>
                                </thead>
                                <tbody>
                                    @foreach($language as $lingo)
                                    <tr>
                                        <td>
                                            <input type="text" name="Selectedlanguage" class="form-control" value="{{ $lingo->language }}" disabled>
                                        </td>
                                        <td>
                                            <select wire:model="proficiency"  class="form-control">
                                                <option value="select">Select Level</option>
                                                @foreach($select as $options)
                                                    <option value="{{ $options->proficiency }}">{{ $options->proficiency }}</option>
                                                @endforeach
                                            </select>
                                        </td>
                                        <td></td>
                                    </tr>
                                    @endforeach
                                @foreach($Selectedlanguage as $index => $languages)
                                    <tr>
                                        <td>
                                            <select name="Selectedlanguage[{{ $index }}] [language_id]" wire:model="Selectedlanguage.{{ $index }}.language_id" class="form-control">
                                                <option value="">Select Language</option>
                                                @foreach($allLanguages as $language)
                                                    <option value="{{ $language->id }}">{{ $language->language }}</option>
                                                @endforeach 
                                            </select>
                                        </td>
                                        <td>
                                            <select wire:model="Selectedlanguage.{{$index}}.proficiency" name="Selectedlanguage[{{ $index }}] [proficiency]" class="form-control">                                                
                                                @foreach($select as $options)
                                                    <option value="{{ $options->proficiency }}">{{ $options->proficiency }}</option>
                                                @endforeach
                                                <option value="">Select Level</option>
                                            </select>
                                        </td>
                                        <td>
                                            <a href="#" wire:click.prevent="removeLanguage({{ $index }})"><i class="fa fa-trash fa-2x"></i></a>
                                        </td>
                                    </tr>
                                @endforeach
                                </tbody>
                            </table>
                        </div>
                        <div class="row">
                            <div class="col-lg-8">
                                <a href="#" wire:click.prevent="addLanguage">+ Add more</a>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
		<div class="row"> 
                <div class="col-md-12">
                    <div 

                    wire:ignore

                    x-data 
                    
                    x-init="

                    FilePond.registerPlugin(FilePondPluginImagePreview);

                    FilePond.setOptions({
                        AllowMultiple: 'multiple' ? 'true' : 'false',
                        server: {
                            process: (fieldName, file, metadata, load, error, progress, abort, transfer, options) => {
                                @this.upload('resume', file, load, error, progress)
                                
                            },
                            revert: (filename, load) => {
                                @this.removeUpload('resume', filename, load)
                            },
                        },
                    });

                    FilePond.create($refs.input);

                    " 
                    >
                        <label>Upload Your Resume</label>
                        <input type="file" x-ref="input" wire:model="resume" multiple>
                    </div>
                </div>
            </div>
        </div>

I think that's all

0 likes
15 replies
lbecket's avatar

As the error indicates, resume is null, which seems reasonable since I don't see it being set anywhere in this class.

SilenceBringer's avatar

@vainway for sure you need to init it somewhere. In mount, maybe. Even you do not have resume prop declared at all

SilenceBringer's avatar

@vainway

class Experiences extends Component
{
   // other stuff

	public $resume;
    public $language;
	// other stuff

    public function mount()
    {
        $this->language = Language::where('language', 'English')->get();

		$this->resume = new IDoNotKnowWhatIsResumeButYouNeedToInitItHereInOrderToUseItLater(); // init resume - not ssure what it is. Model? Service? Repo?

        $this->allLanguages = Language::all();
        // $this->Selectedlanguage = [
        //     ['language_id' => '23', 'proficiency' => '']
        // ];
    }

	// ...
}
vainway 's avatar

@SilenceBringer resume is just a column in the experience table, or try to give me an example on just how you can use it within your own codes

mlewis's avatar

$resume was already declared in your Livewire component & is in your form & is in your form rules array.

In your form rules array you are expecting a single file of certain mime types, which is processed on submission as a single file

However in your form you are using wire:ignore on the resume field so that you can use the FilePond plugin and you have defined the file input field as accepting multiple (even though your form rules expect single) which is conflicting.

I assume you have on the main form wire:submit.prevent="Experience", but it is not shown?

Forget about FilePond for a minute, remove it's use and replace it with a simple file upload field type expecting a single file, and see if that works.

<div class="row"> 
                <div class="col-md-12">
<label>Upload Your Resume</label>
                        <input type="file" wire:model="resume">
</div>
</div>
vainway 's avatar

@mlewis I changed it and it worked but I still want to use Filepond because am using it everywhere on the same project I don't why on this Experience page It started showing an error but on other pages, it is working fine.

I submitted the form and I got a new error Array to string conversion

1 like
mlewis's avatar

@vainway Good to hear - its all part of the bug squishing process - first get it working without the plugin, now you know that is just the implementation of FilePond to resolve, rather than anything to do with your livewire properties that sends you down the wrong path.

Are you hoping to allow multiple resume files to be uploaded in this form, or just one?

The original posted code showed conflicting ideas (in the component you wanted 1 file, in the form you indicated multiple).

vainway 's avatar

@mlewis how can I make it accept multiple in the component then and how can I get rid of that new error Array to string conversion

mlewis's avatar

@vainway So array to string is because of the multiple. I am guessing that the following might work, however I don't know if FilePond does anything special, I don't use it myself... I'm assuming not, but have obviously written this in here so check for any typos in your own IDE when using it.

It is roughly how my own multi file upload component works (minus my own file processing) so hopefully this works or gets you close enough to do the rest...

You should change your resume property resumes (as it is an array of files)

public $resumes = [];

You can then change your rules to

'resumes' => ['required'],
'resumes.*' => ['file','mimes:png,jpg,pdf'],

You need to change your Experience() form submission function to handle multiple files

foreach($this->resumes as $resume) {
$path = $resume->store('public/storage/Resumes');
// Do something with the uploaded file... your previous posted code only permits one resume per expert stored... so you'll need to figure that bit out for yourself.
}

Change your form field row to

<div class="row"> 
                <div class="col-md-12">
                    <div 

                    wire:ignore

                    x-data 
                    
                    x-init="

                    FilePond.registerPlugin(FilePondPluginImagePreview);

                    FilePond.setOptions({
                        AllowMultiple: true,
                        server: {
                            process: (fieldName, file, metadata, load, error, progress, abort, transfer, options) => {
                                @this.upload('resumes', file, load, error, progress)
                                
                            },
                            revert: (filename, load) => {
                                @this.removeUpload('resumes', filename, load)
                            },
                        },
                    });

                    FilePond.create($refs.input);

                    " 
                    >
                        <label>Upload Your Resume</label>
                        <input type="file" x-ref="input" wire:model="resumes" multiple>
                    </div>
                </div>
            </div>
        </div>
vainway 's avatar

@mlewis am still getting the same error resumes is required but I got Array to string conversion because I was using your example below

<div class="row"> 
                <div class="col-md-12">
<label>Upload Your Resume</label>
                        <input type="file" wire:model="resume">
</div>
</div>
mlewis's avatar

@vainway Re: 1st one - sounds like FilePond isn't doing anything then, as said I'm not a user so hopefully someone else can spot something on that. Do you get any output in the dev console when you drop a file onto it?

Re: 2nd one my apologies, I didn't understand as you said you changed it and it worked so assume you meant successfully uploaded and stored.

Going back to that version of code then (simple non filepond upload, using singular resume)

If you dd($this->resume) on the form submission, what is the output?

vainway 's avatar

@mlewis results I got on dd($this->resume);

Livewire\TemporaryUploadedFile {#4336 ▼
  #storage: Illuminate\Filesystem\FilesystemAdapter {#4355 ▼
    #driver: League\Flysystem\Filesystem {#4353 ▼
      #adapter: League\Flysystem\Adapter\Local {#4352 ▼
        #pathSeparator: "\"
        #permissionMap: array:2 [▼
          "file" => array:2 [▼
            "public" => 420
            "private" => 384
          ]
          "dir" => array:2 [▼
            "public" => 493
            "private" => 448
          ]
        ]
        #writeFlags: 2
        -linkHandling: 2
        #pathPrefix: "C:\xampp\htdocs\project\storage\app\"
      }
      #plugins: []
      #config: League\Flysystem\Config {#4354 ▼
        #settings: []
        #fallback: null
      }
    }
    #temporaryUrlCallback: null
  }
  #path: "livewire-tmp/b6mHxUBE07oIyET4pq1wnAT3NErvQv-metaMjcwLmpwZw==-.jpg"
  -test: false
  -originalName: "b6mHxUBE07oIyET4pq1wnAT3NErvQv-metaMjcwLmpwZw==-.jpg"
  -mimeType: "application/octet-stream"
  -error: 0
  #hashName: "eksDi0bsAlq0GIYNkewWMk4Ml31LkB20htSU5JQY"
  +"disk": "local"
  path: "C:\xampp\htdocs\project\storage\app\livewire-tmp"
  filename: "b6mHxUBE07oIyET4pq1wnAT3NErvQv-metaMjcwLmpwZw==-.jpg"
  basename: "php103D.tmp"
  pathname: "C:\Users\User\AppData\Local\Temp\php103D.tmp"
  extension: "tmp"
  realPath: "C:\xampp\htdocs\project\storage\app\livewire-tmp/b6mHxUBE07oIyET4pq1wnAT3NErvQv-metaMjcwLmpwZw==-.jpg"
  size: 110059
  writable: false
  readable: false
  executable: false
  file: false
  dir: false
  link: false
}
mlewis's avatar

@vainway well that looks as expected -- what's the full error when it says array to string conversion, what lines it pointing at ?

Please or to participate in this conversation.