CSV Content Validation with FormRequest Rules in Laravel

In this example I am going to show and brief my implementation of validating CSV row content with custom CSV Content Validation rule created in FormRequest in my Laravel application.

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 );
}

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',
                ])
            ]
        ];
    }
}

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

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;
    }
}

I hope this small example of CSV Content Validation helps someone.

Leave a Reply