CSV Загрузить "Вояджер"

Я новичок в voyager, есть ли способ загружать пользователей через CSV в voyager. Я предполагаю, что мне придется создать для этого собственный шаблон, любой, кто может указать мне правильное направление в этом вопросе, я был бы очень признателен.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
2
0
485
1

Ответы 1

Я знаю, что это старый вопрос, но поскольку это первое, с чем я сталкиваюсь, когда исследую то же самое, я хотел добавить ответ, чтобы те, кто приходит сюда, могли извлечь выгоду.

Это решение для Laravel 8.9.0 и Voyager 1.4.

Здесь есть выбор перед загрузкой CSV, это не обязательно, но полезно, поэтому вам не нужно настраивать CSV перед загрузкой.

Я использовал другой ресурс для этого, который был в Laravel 5.5, вы можете увидеть исходные коды из Импорт CSV для Laravel-5.5

Я также добавлю форк, который обновился до Laravel 9.0 после того, как я закончил свой собственный проект.

Во всяком случае, я использую 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 в наш проект. Нашему контроллеру потребуется «import», который является классом, который помогает нам импортировать файлы, поставляется с Laravel-Excel. За это;

php artisan make:import CsvImport --model=User

Вы можете использовать его для быстрого старта, как рекомендовано в документации Laravel-Excel. Теперь мы можем войти в наш Контроллер. Мы создадим контроллер для команд 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");
});

Также нам понадобится представление при импорте и выборе. Я создал свои представления в views / import.

Для вашего лезвия формы вы хотите использовать его с 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.

НАСТРОЙКИ VOYAGER

Во-первых, нам нужен пункт меню для доступа к нашему представлению импорта. После того, как вы попали в панель «Вояджер», вам нужно перейти в конструктор меню, чтобы создать пункт меню. Все, что вам нужно сделать, это сделать URL-адрес элемента как / admin / import, при этом, когда вы щелкнете этот элемент, вы перейдете к нашему представлению формы импорта. Что касается других параметров, вы можете изменить их по своему усмотрению.

Вам также может потребоваться изменить свою пользовательскую модель BREAD на App \ Models \ User, чтобы она могла получать все созданные нами поля.

Другие вопросы по теме