Я использую Laravel 5.6 и настроил проверка формы запроса для моей формы, которая представляет одну строку, проверяет ее, а затем добавляет в базу данных. Это все отлично работает.
Для пакетного импорта нескольких строк у меня есть импорт CSV. CSV анализируется в массив, а затем каждая строка массива содержит данные того же типа, что и в моей форме, и поэтому может использовать те же правила проверки.
Я немного растерялся, как на самом деле реализовать это, поскольку данные, проанализированные из CSV, находятся в массиве, а не в объекте запроса, который ищет запрос проверки формы.
Есть ли у кого-нибудь советы о том, как лучше использовать мою проверку формы для формы и CSV без дублирования кода?
РЕДАКТИРОВАТЬ
Если кому-то это интересно, моим окончательным решением было не использовать проверку формы запроса. В моем случае было проще добавить правила проверки и сообщения в некоторые защищенные функции внутри контроллера. Это означает, что их можно повторно использовать в каждой из функций контроллера, которые в этом нуждаются (store, 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++;
}
}
Затем я использовал количество успехов / ошибок / дубликатов, чтобы отправить обратно подходящую сумку сообщений об ошибках и / или флэш-сообщения.
Вы можете подойти к нему, создав макрос объекта Request, чтобы превратить CSV в массив, а затем использовать промежуточное ПО для анализа входящего запроса, если это CSV-файл, и объединения его во входящий запрос. Тогда проверка вашего приложения может проверить его с помощью проверки массива.
Начните с того, что заставите поставщика услуг разместить макрос запроса:
php artisan make:provider RequestMacroParseCsvProvider
Тогда в сервис-провайдере:
Добавьте это вверху, чтобы добавить класс Request:
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, и вы можете проверить parsedCsv
запросить ключ с помощью Laravel’s проверка массива.
Вы можете внести некоторые улучшения, чтобы сделать его более гибким, если хотите. Я сделал нечто похожее, но не совсем связанное с файлами, в другом проекте, где мне нужно было изменить запрос, прежде чем он добрался до проверки моего контроллера, и он заработал.
Надеюсь это поможет.
Других решений пока нет …