bojan1994's avatar

Multiple file uploads validation problem

Hi,

I have a problem with validation of multiple file uploads. I have two inputs in form, documentFile (which is type="file") and documentName (which is type="text") and user can add more rows by clicking on add button. I have done many array validations before without a problem but now i'm missing something. I succeeded to validate second field easily, but first always passes. Strange thing is, when i modify first input to be type="text" rather then type="file", everything works.

Here's the code:

DocumentationRequest.php
/**
 * Get the validation rules that apply to the request.
 *
 * @return array
 */
 public function rules()
 {
     return [
         'documentFile.*' => ['required'],
         'documentName.*' => ['required'],
     ];
 }

/**
 * Custom messages.
 *
 * @return array
 */
 public function messages()
 {
     return [
         'documentFile.*.required' => __('beneficiary.DocumentFileRequired'),
         'documentName.*.required' => __('beneficiary.NameRequired'),
     ];
 }
form.blade.php
<div class="row" id="documentation-body-row-0">
    <div class="col-lg-6">
        <p class="mb-2">
            <span class="text-danger">*</span> {{ __('beneficiary.Document') }}
        </p>
        <div class="custom-file">
            <input type="file" 
                class="form-control @if($errors->has('documentFile.*')) is-invalid @endif" 
                id="documentFile[0]" 
                name="documentFile[0]">
            <label class="custom-file-label" 
                for="documentFile[0]">{{ __('beneficiary.SelectDocument') }}
            </label>
        </div>
        @error('documentFile.*')
            <div class="invalid-feedback d-block">
                {{ $message }}
            </div>
        @enderror
    </div>
    <div class="col-lg-6 form-group">
        <label for="documentName[0]">{{ __('beneficiary.Name') }}</label>
        <input type="text" 
            name="documentName[0]" 
            id="documentName[0]" 
            class="form-control @if($errors->has('documentName.*')) is-invalid @endif">
        @error('documentName.*')
            <div class="invalid-feedback d-block">
                {{ $message }}
            </div>
        @enderror
    </div>
</div>
0 likes
4 replies
bojan1994's avatar

Hi @marianomoreyra

Yes, that is included in my form.

And also, validation is working when request is not an array. So, it's not working only in case when i pass an array of data.

MarianoMoreyra's avatar

I'm kind of confused @bojan1994

On you original post you said:

I succeeded to validate second field easily, but first always passes. Strange thing is, when i modify first input to be type="text" rather then type="file", everything works.

But now you say it only works when it's not an array?

So, when you change it from file to text, it doesn't work either if it's an array?

Please, share the entire Form, including the foreach statement that creates the array.

bojan1994's avatar

@marianomoreyra

Second field is text type, so user can manually enter document name and validation for that field makes no problems.

First field is file type and that field always passes even if it's empty.

At the beginning, this request didn't accepted an array of data, so you had only two fields, one for document upload and one for document name and in that stage validation for both fields worked. Now, the logic is slightly different, so u have + button so you can add more that one rows (another document upload field and document name field). I changed the logic of store method to work with array of data and changed form request to work with array of data, insert is working properly, validation for second field (document name) is working properly, only input for upload document doesn't working properly (it always passes). I tried (just because i could not find the problem in code) to change input type from file to text and validation works.

create.blade.php
<form action="{{ route('documentation.store', ['beneficiary' => $beneficiary]) }}" 
    method="POST" 
    enctype="multipart/form-data">
        @include('beneficiaries.documentation.partials.form', [
            'model' => null,
            'beneficiary' => $beneficiary,
        ])
</form>
form.blade.php
@csrf
<div class="kt-portlet__body kt-portlet__body">
    <div class="kt-section">
        <div class="kt-section__body" id="documentation-body">
            <div class="row" id="documentation-body-row-0">
                <div class="col-lg-6">
                    <p class="mb-2">
                        <span class="text-danger">*</span> 
                            {{ __('beneficiary.Document') }}
                    </p>
                    <div class="custom-file">
                        <input type="file" 
                            class="form-control @if($errors->has('documentFile.*')) is-invalid @endif" 
                            id="documentFile[0]" 
                            name="documentFile[0]">
                            <label class="custom-file-label" for="documentFile[0]">
                                {{ __('beneficiary.SelectDocument') }}
                            </label>
                    </div>
                    @error('documentFile.*')
                        <div class="invalid-feedback d-block">
                            {{ $message }}
                        </div>
                    @enderror
                </div>
                <div class="col-lg-6 form-group">
                    <label for="documentName[0]">
                        {{ __('beneficiary.Name') }}
                    </label>
                    <input type="text" 
                        name="documentName[0]" 
                        id="documentName[0]" 
                        class="form-control @if($errors->has('documentName.*')) is-invalid @endif">
                        @error('documentName.*')
                            <div class="invalid-feedback d-block">
                                {{ $message }}
                            </div>
                        @enderror
                </div>
            </div>
        </div>
        <div class="kt-section__body mt-3 add-remove-documentation">
            <div class="row d-flex justify-content-between">
                <button
                    id="add_row"
                    class="btn btn-success btn-sm"
                >
                    <i class="fas fa-plus"></i>
                    {{ __('beneficiary.Add') }}
                </button>
                <button
                    id='delete_row'
                    class="btn btn-danger btn-sm"
                >
                    <i class="fas fa-minus"></i>
                    {{ __('beneficiary.Remove') }}
                </button>
            </div>
        </div>
    </div>
</div>
<div class="kt-portlet__foot">
    <div class="kt-form__actions">
        <button type="submit" class="btn btn-success">
            {{ __('beneficiary.Save') }}
        </button>
        <a href="{{ route('beneficiaries.show', ['beneficiary' => $beneficiary]) }}" 
            type="reset" 
            class="btn btn-secondary">
                {{ __('beneficiary.Cancel') }}
        </a>
    </div>
</div>
store method
public function store(DocumentationRequest $request, Beneficiary $beneficiary)
{
    foreach ($request->documentFile as $key => $file) {
        $documentation = $beneficiary->documentation()
            ->create($request->except(['documentFile.*', 'documentName.*']));

        $documentation->addMedia($file)
            ->usingName($request->documentName[$key])
            ->toMediaCollection('beneficiary-documentation');
    }

    notify()->success(__('beneficiary.SuccessfullyCreateMessage'));

    return redirect()->route('beneficiaries.show', [
        'beneficiary' => $beneficiary,
    ])->withInput(['tab' => 'documentation']);
}

Please or to participate in this conversation.