我想在Laravel 5.8中构建一个功能,该功能可以帮助我上传CSV文件并将数据导入数据库,但是所有功能都应处于后台(服务器端)流程中,一旦完成,请发送电子邮件至登录用户。我想在开始该过程之前获得更好的理解,应该在Scheduler
的帮助下进行操作,否则会有更好的方法或库可以帮助我实现此功能。
期待听到您的想法:)
谢谢。
答案 0 :(得分:2)
从头开始:
创建一个invoices
表和相应的模型:
php artisan make:model发票-m
您的模型应如下所示:
<?php
namespace App;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
class Invoice extends Model
{
protected $table = 'invoices';
protected $fillable = [
'user_id',
'processed',
'path'
];
public function scopeNotProcessed(Builder $query)
{
return $this->where('processed', '=', false);
}
}
这是invoices
表:
public function up()
{
Schema::create('uploads', function (Blueprint $table) {
$table->increments('id');
$table->string('path')->nullable(false);
$table->boolean('processed')->default(false)->nullable(false);
$table->timestamps();
});
}
完成这些操作后,请按以下步骤操作:
创建一个存储库,它将上传您的csv文件。该文件应放置在
app/Repositories/CSVRepository
:
<?php
namespace App\Repositories;
use Illuminate\Support\Facades\Storage;
use App\Invoice;
class CSVRepository {
/**
* CSVRepository constructor.
*/
public function __construct()
{
//
}
/**
* @param $file
* @param $extension
* @return mixed
*/
public function uploadCSV($file, $extension){
return $this->upload($file, $extension);
}
/**
* @param $file
* @param $extension
* @return mixed
*/
private function upload($file, $extension){
$path = Storage::putFileAs("myFileName", $file, uniqid().".".$extension);
$uploadedFile = Invoice::create([
'path' => $path,
'processed' => false,
]);
return $uploadedFile;
}
}
现在,创建您的控制器,它将使用CSVRepository
将文件上传到服务器:
上传功能应如下所示:
public function upload(CSVRepository $CSVRepository)
{
try{
$file = Input::file('file');
$extension = strtolower($file->getClientOriginalExtension());
if ($extension !== 'csv'){
$errors['file'] = 'This is not a .csv file!';
return redirect()->back()->withInput()->withErrors($errors);
}
$CSVRepository->uploadCSV($file, $extension);
$message = array(
'type' => 'success',
'text' => 'Your file has been uploaded! You will receive an email when processing is complete!',
'title' => 'Success',
);
session()->flash('message', $message);
return redirect('route-to-redirect');
}catch (\Exception $exception){
return abort(Response::HTTP_INTERNAL_SERVER_ERROR, 'Internal Server Error');
}
}
现在,您需要一项工作来为您处理文件:
开始使用artisan命令创建命令:
php artisan make:command ProcessCSVCommand
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Invoice;
use Illuminate\Support\Facades\Storage;
class ProcessCSVCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'csv:process';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Process an uploaded CSV file';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
try{
//Retrieve only no processed files:
$invoices = Upload::notProcessed()->get();
if (count($files) < 1){
$this->info('No files found');
return;
}
//Process the files:
$invoices->map(function($invoice){
$file = fopen("storage/app/".$invoice->path, "r");
while (!feof($file)){
$line = fgets($file);
//Here you have a loop to each line of the file, and can do whatever you need with this line:
if(strlen($line) > 0){ //If the line is not empty:
// Add your logic here:
}
// Don't forgot to change your `processed` flag to true:
$invoice->processed = true;
$invoice->save();
}
});
}catch (\Exception $exception){
$this->error("Something went wrong");
return $exception->getMessage();
}
}
}
现在,打开您的app/Console/Commands/Kernel.php
文件:
在$commands
数组中注册新命令:
$commands = [
Commands\ProcessCSVCommand::class,
];
安排在服务器上运行的作业,检查要处理的文件,如果可以,请处理文件:
在同一文件中,现在使用schedule
函数:
protected function schedule(Schedule $schedule)
{
$schedule->command('csv:process')
->everyFiveMinutes();
}
希望有帮助。
答案 1 :(得分:1)
队列是进行此类工作的方式。上传文件本质上需要在一个请求中完成,但是除此之外,您可以创建一个队列,该队列将减少将CSV转换为数据库中的记录的速度。
答案 2 :(得分:0)
我认为您可能要考虑使用“队列”并监听https://laravel.com/docs/5.8/queues#job-events处提到的作业处理事件,然后从那里发送邮件