DEV Community

Arvind Kumar
Arvind Kumar

Posted on

Validate CSV row content with Custom validation rules with FormRequest in Laravel

In this example I am going to show and brief my implementation of validating CSV row content.

Scenario

I need to create a simple custom CSV importer to import a few rows into my Laravel application database. I want to validate the incoming data in the columns of each row to make sure that data is what we expect to be. For example, some of columns should be string type and some integer etc.

Solution

Since I am using FormRequest validation method I need to implement it to adapt to FormRequest mechanism. I thank to this post for providing me a base for it.

I am not going to create a new Laravel application and I will just show the relevant code only.

Here is the store method of UserController.php


namespace App\Http\Controllers\API;

use App\Http\Requests\UserImportRequest;
use App\Http\Controllers\Controller;
use App\Http\Traits\CsvParser;
use App\Models\User;

class UserController extends Controller
{
    use CsvParser;

public function store( UserImportRequest $request, Merchant $merchant )
{
    $fileContents = request()->file('field_csvfile')->get();
    $csvData = $this->CsvToArray($fileContents);
    $imported = [];
    foreach( $csvData as $row ) {
        $imported[] = User::create(
            $row
        );
    }
    return response( $imported );
}
Enter fullscreen mode Exit fullscreen mode

Here is UserImportRequest.php, the FormRequest file

namespace App\Http\Requests;

use Illuminate\Validation\Factory as ValidationFactory;
use \Illuminate\Contracts\Validation\Validator;
use Illuminate\Validation\ValidationException;
use Illuminate\Foundation\Http\FormRequest;
use App\Rules\CsvContent;

class UserImportRequest extends FormRequest
{
    public function __construct(ValidationFactory $validationFactory)
    {
        $validationFactory->extend(
            'dob_custom_check',
            function ($attribute, $value, $parameters) {
                //If valid date ; write your own "date check" logic
                return true; //Else
                //return false
            },
            ':attribute is not valid'
        );
    }
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'field_csvfile' => [
                'bail',
                'file',
                'mimes:csv,txt,xls,xlsx',
                new CsvContent( [
                    'first_name' => 'required|date',
                    'last_name' => 'required|date',
                    'email' => ['required','unique:users'],
                    'date_of_birth' => ['required, 'date', 'dob_custom_check'],
                    'address' => 'required|string',
                    '' => 'required|string',
                ])
            ]
        ];
    }
}
Enter fullscreen mode Exit fullscreen mode

Here is the CsvParser trait App\Http\Traits\CsvParser.php

namespace App\Http\Traits;

trait CsvParser {
    public function CsvToArray( $content )    {
        $rows = array_map('str_getcsv', explode(PHP_EOL, $content));
        $rowKeys = array_shift($rows);
        $formattedData = [];
        foreach ($rows as $row) {
            if( sizeof($row) == sizeof($rowKeys) )  {
                $associatedRowData = array_combine($rowKeys, $row);
                if (empty($keyField)) {
                    $formattedData[] = $associatedRowData;
                } else {
                    $formattedData[$associatedRowData[$keyField]] = $associatedRowData;
                }
            }
        }
        return $formattedData;
    }
}
Enter fullscreen mode Exit fullscreen mode

I hope it helps someone.

Top comments (2)

Collapse
 
emekambah profile image
Emeka Mbah

What if you have 3 million rows to import?

Collapse
 
ivan_chesh profile image
Ivan Adamovich

can you show please code of your CsvContent class please?