我是旅行者的新手,有没有办法在旅行者中通过CSV上传用户。我想我必须为此制作一个自定义模板,任何能指出我正确方向的人,我都会非常感激。
答案 0 :(得分:0)
我知道这是一个古老的问题,但是由于这是我研究同一件事时遇到的第一件事,因此我想添加一个答案,以便那些来这里的人能够受益。 < / p>
此解决方案适用于Laravel 8.9.0和Voyager 1.4
在上传CSV之前有一个选择,这不是必需的,但是很好,因此您不必在上传前调整CSV。
我确实使用了另一种资源,它在 Laravel 5.5 中,您可以从Laravel-5.5 CSV Import
查看原始代码完成我自己的项目后,我还将添加一个用Laravel 9.0更新的fork。
无论如何,我使用Laravel-Excel 3.1.24来读取CSV。该资源正在使用旧版本。
让我们开始编码
在将其与Voyager连接之前,首先应该知道需要编写视图和控制器来完成这项工作。
此外,我们将需要我们的模型。对于您的用户模型,请确保已添加所需的所有字段。创建具有相同需求的迁移。
例如您的用户模型是否具有此功能;
protected $fillable = [
'name',
'email',
'password',
];
确保您的迁移;
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
设置模型和迁移后,您将需要其他模型来存储CSV。在使用CSV和数据库字段进行选择时,这将对您有所帮助。 它只有三个字段; 'csv_filename','csv_header','csv_data'。
设置模型后,我们需要将config / app.php添加到我们的选择中。
'db_fields' => [
'name',
'email',
'password',
]
我们将从CSV获得的字段,如果您的CSV文件中没有密码,则可以删除密码。
在进入我们的控制器之前,我们应该添加Laravel-Excel。根据文档,您需要做的就是在终端上运行此命令。
composer require "maatwebsite/excel:3.1.24"
这会将Laravel-Excel添加到我们的项目中。我们的控制器将需要“导入”,这是Laravel-Excel附带的可帮助我们导入文件的类。为此;
php artisan make:import CsvImport --model=User
您可以使用它来快速入门,如建议的Laravel-Excel文档一样。现在我们可以进入控制器了。我们将创建控制器vie Laravel命令。我们将需要一堆东西;
use App\Imports\CsvImport; //This is needed for Laravel-Excel.
use Illuminate\Http\Request;
use App\Models\User; //Our user model.
use App\Models\CsvData; //Our model for csv.
use App\Http\Requests\CsvImportRequest; //I'll share this in a sec.
use Maatwebsite\Excel\Facades\Excel; //This is from Laravel-Excel
use Illuminate\Support\Str; //This is for basic password creation
class ImportController extends Controller
{
我们需要的功能是
public function form()
{
return view('import.form');
}
此功能非常简单。它将返回我们的观点。第二个是当我们解析CSV并将其保存时添加CSV_Data。但是首先,我们需要Laravel想要的请求。
php artisan make:request CSVImportRequest
我要分享我的;
class CsvImportRequest extends FormRequest
{
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'csv_file' => 'required|file'
];
}
现在我们可以返回到控制器了;
public function parseImport(CsvImportRequest $request)
{
//we getting with the request the file. So you need to create request with
//Laravel. And you should add this to your Controller as use App\Http\Requests\CsvImportRequest;
$path = $request->file('csv_file')->getRealPath();
if ($request->has('header')) {
//this is coming from Laravel-Excel package. Make sure you added to your
//controller; use Maatwebsite\Excel\Facades\Excel;
$data = Excel::toArray(new CsvImport, request()->file('csv_file'))[0];
} else {
$data = array_map('str_getcsv', file($path));
}
if (count($data) > 0) {
//checking if the header option selected
if ($request->has('header')) {
$csv_header_fields = [];
foreach ($data[0] as $key => $value) {
$csv_header_fields[] = $key;
}
}
$csv_data = array_slice($data, 0, 2);
//creating csvdata for our database
$csv_data_file = CsvData::create([
'csv_filename' => $request->file('csv_file')->getClientOriginalName(),
'csv_header' => $request->has('header'),
'csv_data' => json_encode($data)
]);
} else {
return redirect()->back();
}
//this is the view when we go after we submit our form.We're sending our data so we can select to match with db_fields.
return view('import.fields', compact('csv_header_fields', 'csv_data', 'csv_data_file'));
}
现在是导入功能。
public function processImport(Request $request)
{//we are getting data from request to match the fields.
$data = CsvData::find($request->csv_data_file_id);
$csv_data = json_decode($data->csv_data, true);
$request->fields = array_flip($request->fields);
foreach ($csv_data as $row) {
$contact = new User();
foreach (config('app.db_fields') as $index => $field) {
//using config app.db_fields while matching with request fields
if ($data->csv_header) {
if ($field == "null") {
continue;
} else if ($field == "password") {
//this is checkin if password option is set. If not, it is creating a password. You can eliminate this according to your needs.
if (isset($request->fields['password'])) {
$pw = $row[$request->fields['password']];
} else {
$pw = Str::random(10);
}
} else
$contact->$field = $row[$request->fields[$field]];
} else
//same with the if but without headers. You can create a function to avoid writing
//codes twice.
{
if ($field == "null") {
continue;
} else if ($field == "password") {
if (isset($request->fields['password'])) {
$pw = $row[$request->fields['password']];
} else {
$pw = Str::random(10);
}
} else
$contact->$field = $row[$request->fields[$index]];
}
}
$user = User::where(['email' => $contact->email])->first();
//checking for duplicate
if (empty($user)) {
$contact->password = bcrypt($pw);
$contact->save();
} else {
$duplicated[] = $contact->email;
//if you want you can keep the duplicated ones to check which ones are duplicated
}
}
//you can redirect wherever you want. I didn't need an success view so I returned
//voyagers original users view to see my data.
return redirect(route('voyager.users.index'));
}
现在,我们可以创建路线了。由于我们正在使用Voyager,所以请不要忘记添加voyager。,因此我们可以在voyager管理面板中使用它。
use App\Http\Controllers\ImportController;
Route::group(['prefix' => 'admin','as' => 'voyager.', 'middleware' => 'admin.user'],
function()
{
Route::get('import',[ImportController::class, 'form'])->name("import.form");
Route::post('import/parse', [ImportController::class, 'parseImport'])-
>name("import.parse");
Route::post('import/process', [ImportController::class, 'processImport'])-
>name("import.process");
});
此外,我们在导入和选择时需要一个视图。我在视图/导入中创建了视图。
对于表单刀片,您希望将其与voyager一起使用,因此您应该
@extends('voyager::master')
使用它具有相同的主题。之后,您需要在HTML中添加一个部分。
@section('content')
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">CSV Import</div>
<div class="panel-body">
<form class="form-horizontal" method="POST" action="{{ route('voyager.import.parse') }}" enctype="multipart/form-data">
{{ csrf_field() }}
<div class="form-group{{ $errors->has('csv_file') ? ' has-error' : '' }}">
<label for="csv_file" class="col-md-4 control-label">CSV file to import</label>
<div class="col-md-6">
<input id="csv_file" type="file" class="form-control" name="csv_file" required>
@if ($errors->has('csv_file'))
<span class="help-block">
<strong>{{ $errors->first('csv_file') }}</strong>
</span>
@endif
</div>
</div>
<div class="form-group">
<div class="col-md-6 col-md-offset-4">
<div class="checkbox">
<label>
<input type="checkbox" name="header" checked> File contains header row?
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-8 col-md-offset-4">
<button type="submit" class="btn btn-primary">
Parse CSV
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
如您所见,我们使用“旅行者”。添加我们的路线。这也将帮助我们进行Voyager设置。我们的第二个视图是我们选择db_fields的位置。
@extends('voyager::master')
@section('content')
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">CSV Import</div>
<div class="panel-body">
<form class="form-horizontal" method="POST" action="{{ route('voyager.import.process') }}">
{{ csrf_field() }}
<input type="hidden" name="csv_data_file_id" value="{{ $csv_data_file->id }}" />
<table class="table">
@if (isset($csv_header_fields))
<tr>
@foreach ($csv_header_fields as $csv_header_field)
<th>{{ $csv_header_field }}</th>
@endforeach
</tr>
@endif
@foreach ($csv_data as $row)
<tr>
@foreach ($row as $key => $value)
<td>{{ $value }}</td>
@endforeach
</tr>
@endforeach
<tr>
@foreach ($csv_data[0] as $key => $value)
<td>
<select name="fields[{{ $key }}]">
<option value="null">Do Not Save</option>
@foreach (config('app.db_fields') as $db_field)
<option value="{{ (\Request::has('header')) ? $db_field : $loop->index }}"
@if ($key === $db_field) selected @endif>{{ $db_field }}</option>
@endforeach
</select>
</td>
@endforeach
</tr>
</table>
<button type="submit" class="btn btn-primary">
Import Data
</button>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
就这样!现在我们有了导入集。我们只需要使用Voyager进行配置。
旅行者设置
首先,我们需要一个菜单项才能进入导入视图。进入“旅行者”面板后,您需要转到菜单构建器来创建菜单项。您所要做的就是将项目的网址设置为/ admin / import,单击该项目时,将转到我们的导入表单视图。对于其他选项,您可以根据需要更改它们。
您可能还需要从用户BREAD Model更改为App \ Models \ User,以便它可以接收我们创建的所有字段。