我正在使用Laravel5.6,并为我的表单设置了一个表单请求验证,该表单提交一行,对其进行验证,然后添加到数据库中。一切都很好。
对于多行的批量导入,我有一个CSV导入。CSV被解析为数组,数组的每一行包含与我的表单中提供的数据类型完全相同的数据。因此,它可以使用相同的验证规则。
我有点不知道如何实际实现这一点;从CSV解析的数据位于一个数组中,而不是表单验证请求正在寻找的请求对象中。
有没有人知道如何在不重复代码的情况下对表单和CSV使用我的表单验证?
编辑
如果有人感兴趣,我的最后解决方案是不使用表单请求验证。在我的例子中,将验证规则和消息添加到控制器内的一些受保护的函数更容易。这意味着它们可以在需要它的每个控制器函数(存储、csvStore等)中重用。没有重复的代码。在这种情况下,我不知道表单请求验证功能有什么好处。
//reformat CSV into array
$master = [];
$line_id = 1;
foreach ($data as $row) {
//skip blank rows
if (empty($row['sku'])) continue;
//build master
foreach($row as $key => $value){
if(!empty($value)) $master[$row['sku']][$key] = $row[$key];
}
//add line number for debugging
$master[$row['sku']]['line_number'] = $line_id;
$line_id++;
}
//Validate each row of CSV individually
$error_messages = new MessageBag();
$error_count = 0;
$duplicate_count = 0;
if(empty($master)){
//empty $master
$error_messages->add('', 'CSV file does not contain valid data or is empty');
flash()->message('Nothing was imported');
return redirect()->back()->withErrors($error_messages);
} else {
foreach($master as $row){
$validator = Validator::make($row,$this->createValidationRules(), $this->createValidationMessages());
//Check validation
if ($validator->fails()){
$master[$row['sku']]['valid'] = false;
if(isset($validator->failed()['sku']['Unique'])){
$duplicate_count ++;
if(!request('ignore-duplicates') && !request('ignore-errors')) $error_messages->merge($validator->errors()->messages()); //save error messages
} else {
$error_count ++;
if(!request('ignore-errors')) $error_messages->merge($validator->errors()->messages()); //save error messages
}
} else {
$master[$row['sku']]['valid'] = true;
}
}
}
//add successful rows to DB
$success_count = 0;
foreach($master as $row){
if($row['valid'] == true){
$productCreate = new ProductCreate();
$productCreate->create($row);
$success_count++;
}
}然后,我使用成功/错误/重复计数返回一个合适的错误消息包和/或闪存消息。
发布于 2018-06-08 17:18:24
您可以通过创建请求对象宏来将CSV转换为数组,然后使用中间件来解析传入的请求(如果它是csv文件)并将其合并到传入的请求中。然后,应用程序的验证可以使用数组验证来验证它。
首先,让服务提供者容纳您的请求宏:
php artisan make:provider RequestMacroParseCsvProvider
然后在服务提供商中:
将其添加到顶部以拉入请求类:
use Illuminate\Http\Request;
在提供程序的注册方法中:
Request::macro('parseCsv', function ($fileNameKey) {
// Note: while working inside of the request macro closure, you can access the request object by referencing $this->{key_of_request_item}
// You will be running your parser against $fileNameKey which will be the key of the request file coming in. So you'd access it like:
if ($this->hasFile($fileNameKey)) {
// Your code to parse the csv would go here. Instantiate your csv parsing class or whatever...
// $file = $this->file($fileNameKey);
// Store the parsed csv in an array, maybe named $parsedCsv?
}
return empty($parsedCsv) ? [] : $parsedCsv;
});在config/app.php中注册服务提供者
App\Providers\RequestMacroParseCsvProvider::class,
创建一个中间件来检查传入的请求是否包含csv
php artisan make:middleware MergeCsvArrayIntoRequest
在handle方法中:
if ($request->has('your_csv_request_key')) {
$parsedCsv = $request->parseCsv('your_csv_request_key');
// Then add it into the request with a key of 'parsedCsv' or whatever you want to call it
$request->merge(['parsedCsv' => $parsedCsv]);
}
return $next($request);在app/Http/Kernel.php中注册您的中间件
protected $middleware = [
...
\App\Http\Middleware\MergeCsvArrayIntoRequest::class,
...
];或者把它放到$routeMiddleware中,如果你不希望它是全球性的。
'parse.csv' => \App\Http\Middleware\MergeCsvArrayIntoRequest::class,现在,您的中间件正在拦截和转换您上传的任何CSV文件,您可以使用Laravel的parsedCsv 数组验证验证数组验证请求密钥。
如果你愿意的话,你肯定可以做一些改进,使它更加灵活。在另一个项目中,我做了一些类似的事情,但不是完全与文件相关的,在这个项目中,我需要修改请求,然后它才会到达我的控制器的验证并开始工作。
希望这能有所帮助。
https://stackoverflow.com/questions/50764995
复制相似问题