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 );
}
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
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;
}
}
I hope it helps someone.
Top comments (2)
What if you have 3 million rows to import?
can you show please code of your CsvContent class please?