redsquirrelstudio/laravel-backpack-import-operation

一个操作,使您的 CRUDs 能够使用您熟悉和喜爱的 Backpack api 进行可配置的导入

1.6.8 2024-02-29 21:16 UTC

README

Latest Version on Packagist

Total Downloads

添加一个可配置的界面,允许您的管理员用户

  • 上传电子表格文件。
  • 将文件的列映射到您的 CRUD 模型字段。
  • 导入他们的数据。

并允许您作为开发者

  • 使用您熟悉的 Backpack API 定制每个 CRUD 的导入行为。
  • 选择队列或即时导入。
  • 完全自定义操作的行为。

"Buy Me A Coffee"

如果您正在寻找一支优秀的开发者团队来处理您的 Backpack/Laravel 开发,请在 Sprechen 上联系我们

还需要 CRUD 的完整导出?请查看 redsquirrelstudio/laravel-backpack-export-operation

Screenshot of the operation's mapping screen

后台驱动导入的是 maatwebsite/excel,如果您愿意,可以为操作定义自己的导入类。

然而,真正的力量在于能够使用与定义您的列表视图相同的语法来快速配置导入。

目录

  1. 安装
  2. 使用
  3. 列类型
    1. 文本
    2. 数字
    3. 布尔值
    4. 日期
    5. 数组
  4. 主键
  5. 无主键的导入
  6. 验证
  7. 添加示例文件
  8. 添加您自己的列
  9. 自定义导入类
  10. 禁用用户映射
  11. 完成时删除电子表格
  12. 队列导入
  13. 配置
    1. 文件上传
    2. 队列
    3. 更改导入日志模型
    4. 自定义翻译
    5. 自定义视图
  14. 事件
  15. 限制访问
  16. 致谢
  17. 许可

安装

环境要求

  • PHP 扩展 php_zip
  • PHP 扩展 php_xml
  • PHP 扩展 php_gd2
  • PHP 扩展 php_iconv
  • PHP 扩展 php_simplexml
  • PHP 扩展 php_xmlreader
  • PHP 扩展 php_zlib

步骤 1.

使用 composer 需求此包

composer require redsquirrelstudio/laravel-backpack-import-operation

如果它尚未在项目中,这将安装 maatwebsite/excel

步骤 2. (可选)

位于:RedSquirrelStudio\LaravelBackpackImportOperation\Providers\ImportOperationProvider 的服务提供程序将被默认自动发现和注册。虽然如此,如果您像我一样,可以将其添加到 config/app.php 中。

    'providers' => ServiceProvider::defaultProviders()->merge([
        /*
         * Package Service Providers...
         */
        //Some other package's service providers...
        RedSquirrelStudio\LaravelBackpackImportOperation\Providers\ImportOperationProvider::class,
    ])->toArray(),

步骤 3.

发布配置文件

php artisan vendor:publish --tag=laravel-backpack-import-operation-config

这将创建一个新的文件 config/backpack/operations/import.php,允许您自定义诸如上传文件应存储在磁盘和路径之类的设置。

步骤 4.

发布并运行迁移

php artisan vendor:publish --tag=laravel-backpack-import-operation-migrations

然后

php artisan migrate

使用

在您的 CRUD 控制器中需要导入操作的地方。

等等...

添加导入操作

class ExampleCrudController extends CrudController
{
    use \Backpack\CRUD\app\Http\Controllers\Operations\ListOperation;
    use \Backpack\CRUD\app\Http\Controllers\Operations\CreateOperation;
    use \Backpack\CRUD\app\Http\Controllers\Operations\UpdateOperation;
    use \Backpack\CRUD\app\Http\Controllers\Operations\DeleteOperation;
    use \Backpack\CRUD\app\Http\Controllers\Operations\ShowOperation;
    use \RedSquirrelStudio\LaravelBackpackImportOperation\ImportOperation;
    //...

但是等等!还有更多!

配置导入

配置 CRUD 导入与配置列表或显示视图非常相似,以下是一个示例

    //Probably some more CRUD config...
    
    protected function setupImportOperation()
    {
        CRUD::addColumn([
           'name' => 'id',
           'label' => 'ID',
           'type' => 'number',
        ]);

        CRUD::addColumn([
           'name' => 'name',
           'label' => 'Name',
           'type' => 'text',
        ]);  
    }
    
    //Fetch functions or something...  

setupImportOperation() 函数中,您可以通过名称、标签和类型添加 CRUD 列,在大多数情况下。每个列都对应一个模型字段。

列的类型很重要,因为它指定了在数据保存到模型之前,电子表格中的数据将如何被处理。

=========重要==========

这里指定的列对应于模型字段,而不是电子表格列。用户可以在界面中将任何电子表格列分配给任何导入列。

=============================

列类型

文本

最简单的列类型,只需将电子表格中的文本保存到模型字段。

示例

CRUD::addColumn([
   'name' => 'name',
   'label' => 'Name',
   'type' => 'text',
]);  

数字

此列将检查数字是否为数字,如果是,则将其保存到模型,否则将使用 null。 (此字段也支持小数值)。

示例

CRUD::addColumn([
   'name' => 'age',
   'label' => 'Age',
   'type' => 'number',
]);  

布尔值

默认情况下,此列将评估列是否包含:'true'、'1' 或 'y'(不区分大小写)。但您可以使用 'options' 键指定哪些应该被视为真或假。

示例

CRUD::addColumn([
   'name' => 'active',
   'label' => 'Active Customer',
   'type' => 'boolean',
   'options' => [
        false => 'No',
        true => 'Yes',
    ]  
]);  

日期

此列将接收输入并尝试将其转换为日期时间,如果成功,则返回作为 Carbon\Carbon 实例的日期时间,否则将返回 null。

示例

CRUD::addColumn([
   'name' => 'date_of_birth',
   'label' => 'Birthday',
   'type' => 'date',
]);  

数组

此列非常适合仅导入一组选项中的一个或多个。 示例

CRUD::addColumn([
   'name' => 'type',
   'label' => 'Customer Type',
   'type' => 'array',
   'options' => [
        'retail' => 'Retail',
        'trade' => 'Trade',
        'other' => 'Other',
    ]
]);  

在此示例中,只有当列是 'Retail'、'Trade' 或 'Other' 时,才会保存导入的数据。在这些情况下,分别保存 'retail'、'trade' 和 'other'。

多个值

数组列也支持多个值。

示例

CRUD::addColumn([
   'name' => 'type',
   'label' => 'Customer Type',
   'type' => 'array',
   'multiple' => true,
   'options' => [
        'retail' => 'Retail',
        'trade' => 'Trade',
        'other' => 'Other',
    ]
]);  

在此示例中,用户可以导入以下数据

Retail,Trade,Other

并且该列将保存以下数组到模型的类型字段

[
    'retail',
    'trade',
    'other'
]

为了使此功能正常工作,请确保在 $casts 数组中将模型字段转换为数组,如下所示

  protected $casts = [
        'types' => 'array',
  ];

如果您希望用户能够指定以逗号分隔的任何值的列表,您可以在 CRUD 列配置中添加以下内容。

CRUD::addColumn([
   'name' => 'type',
   'label' => 'Customer Type',
   'type' => 'array',
   'multiple' => true,
   'options' => 'any'
]);  

使用此配置,用户可以输入任何他们喜欢的内容。例如,如果他们导入 dog,cat,rat - 它将被保存到模型中为

[
    'dog',
    'cat',
    'rat'
]

'options' => 'any'

不能与

'multiple' => true

一起使用,因为此列类型没有意义。在这种情况下,只需使用文本列。

主键

导入操作需要知道您的模型的主键,以便知道是否要根据行数据创建或更新。默认情况下,操作将尝试找到您添加的具有模型主键名称的列。

例如,如果您的模型的主键是 id,则操作将使用此列作为主键

CRUD::addColumn([
   'name' => 'id',
   'type' => 'number',
]);

您将在映射屏幕上看到哪个列被识别为主键。

如果找不到主键,则操作将改为查找您添加的第一个文本或数字列。

您还可以通过向列添加以下配置来将列设置为主键

CRUD::addColumn([
   'name' => 'id',
   'type' => 'number',
   'primary_key' => true,
]);

无主键的导入

您还可以禁用主键的要求,但这意味着您的导入只能创建新模型,而无法更新现有数据。这在您没有定义主键且依赖于模型的自动递增 ID 的情况下很有用。此设置还可以帮助您能够指定用户无法创建多个或更改现有数据的唯一列。

TLDR:启用此设置的导入无法更新现有数据,只能导入新数据。

将以下行添加到您的 setupImportOperation 函数

    protected function setupImportOperation()
    {
        $this->withoutPrimaryKey();
        //Some column config...

验证

验证导入操作与验证创建或更新方法类似,在 setupImportOperation 函数中调用以下函数

    protected function setupImportOperation()
    {
        CRUD::setValidation(CustomerRequest::class);
        //Some column config...

表单请求应验证模型所需的内容,而不是工作表的列,再次强调,因为列标题不重要,因为用户可以映射它们。

添加示例文件

您还可以为用户提供一个链接,以便他们下载一个包含您希望他们上传的数据的示例电子表格。要在 setupImportOperation 函数中设置此功能

    protected function setupImportOperation()
    {
        $this->setExampleFileUrl('https://example.com/link-to-your-download/file.csv');
        //Some column config...

这样做将提供他们上传文件时这样的链接

Screenshot of the operation's example download

添加您自己的列

导入操作提供了创建自定义处理器的选项。这只需要两个步骤。

步骤 1.

我已经包括了一个 artisan 命令来生成自定义列模板

php artisan backpack:import-column ExampleColumn

这将为您在 app\Imports\Columns 生成一个空的导入列。

<?php

namespace App\Imports\Columns;

use RedSquirrelStudio\LaravelBackpackImportOperation\Columns\ImportColumn;

class ExampleColumn extends ImportColumn
{
    public function output(): mixed
    {
        return $this->data;
    }
}

在构建自定义列时,您可以通过 $this->data 访问 $this->getConfig() 和您正在导入的模型,这是来自工作表列的输入。

按需处理数据,并从 output() 函数返回。

好了!

默认情况下,列类型名称将采用类名的第一部分,例如,如果您有 ExampleColumn,则标签将是 'Example'。您可以通过返回字符串来自定义它,在您的列中的 getName() 函数。

Screenshot of a column type label

第二步。

将您的新类添加到 config/backpack/operations/import.php 文件中的 'column_aliases' 数组下。键应该是您在 setupImportOperation 中指定的列类型

    //...
    // Aliases for import column types to be used in operation setup
    'column_aliases' => [
        'array' => Columns\ArrayColumn::class,
        'boolean' => Columns\BooleanColumn::class,
        'date' => Columns\DateColumn::class,
        'number' => Columns\NumberColumn::class,
        'text' => Columns\TextColumn::class,
        'column_type' => App\Imports\Columns\ExampleColumn::class
    ]

砰!

您的列已准备好使用。

CRUD::addColumn([
   'name' => 'name',
   'label' => 'Name',
   'type' => 'example',
]);  

注意:您可以跳过添加列别名,并直接在类型键中指定列类

CRUD::addColumn([
   'name' => 'name',
   'label' => 'Name',
   'type' => App\ImportColumns\ExampleColumn::class,
]);  

自定义导入类

如果您不想使用列映射界面,您还可以指定自己的导入类。为此,创建您的导入类

php artisan make:import <YourImportName>

然后,您可以按照 maatwebsite/excel 文档 来构建具有更精细控制的导入,如果需要的话。

此包为您的自定义导入类提供了一个 WithCrudSupport 接口,允许您的 IDE 获取方法占位符,为您提供导入日志 ID 和验证类。

use RedSquirrelStudio\LaravelBackpackImportOperation\Interfaces\WithCrudSupport;

class CustomImport implements OnEachRow, WithCrudSupport
{
    public function __construct(int $import_log_id, ?string $validator = null)
    {

    }

    public function onRow(Row $row)
    {
        $row = $row->toArray();
        //Your import handling

这可能会使事情变得更容易,您可以选择添加或取消添加,我不是您的老板!

一旦您创建了您的美丽导入类,请使用 setupImportOperation 函数中的此函数设置它

    protected function setupImportOperation()
    {
        $this->setImportHandler(CustomImport::class);
        //Some column config...

禁用用户映射

有时,您可能不希望用户映射他们的列,或者只是需要快速导入。在这些情况下,您可以禁用用户映射步骤。

当用户映射被禁用时,导入处理器将匹配工作表标题与您的 CRUD 列配置。

例如:名为 "name" 或 "Name" 的工作表列将与此配置匹配

CRUD::addColumn([
    'name' => 'name',
    'label' => 'Name',
    'type' => 'text',
]);

要启用此行为,将此行代码添加到 setupImportOperation() 函数中

    //...
    protected function setupImportOperation()
    {
        $this->disableUserMapping();
    //...

完成时删除电子表格

默认情况下,上传的电子表格在导入完成后将保留在存储中。这对于调试/记录目的很有用,但可能不符合您的需求。如果希望在导入完成后删除文件,请将此行代码添加到 setupImportOperation() 函数中

  //...
    protected function setupImportOperation()
    {
        $this->deleteFileAfterImport();
    //...

队列导入

在大多数情况下,如果您在按钮点击时使导入在后台处理,而不是让用户等待导入完成,这对用户来说会更好。

因此,您可以通过将此行代码添加到 setupImportOperation 函数中来排队您的导入

    //...
    protected function setupImportOperation()
    {
        $this->queueImport();
    //...

当然,为此要工作,您需要设置一个队列来分发作业到您的应用程序,为此,请按照 Laravel 的官方文档 进行。

配置

文件上传

默认情况下,电子表格将存储在默认磁盘的路径 /imports 中。但这可以通过更改以下环境变量来修改。

FILESYSTEM_DISK="s3"
BACKPACK_IMPORT_FILE_PATH="/2023/application-name/imports"

或者直接修改 config/backpack/operations/import.php 内部的选项。

    //...
    //Filesystem disk to store uploaded import files
    'disk' => "s3",
    
    //Path to store uploaded import files
    'path' => "/2023/application-name/imports",
    //...

队列

您还可以通过更改以下环境变量来修改队列,以及每个块处理的行数。

QUEUE_CONNECTION="import-queue"
BACKPACK_IMPORT_CHUNK_SIZE=300

或者直接在 config/backpack/operations/import.php 内部更改值。

    //...
    //Queue to dispatch import jobs to
    'queue' => 'import-queue',

    //Chunk size for reading import files
    'chunk_size' => 300,
    //...

导入日志

在极少数情况下,您可能还希望更改用于记录导入的模型,我实在想不出为什么要这样做,但肯定有人会想出理由。

如果这样做,请确保更新迁移,并在 config/backpack/operations/import.php 中指定您自己的模型。

//...
return [
    'import_log_model' => ImportLog::class,
    //...

翻译

如果需要,您可以更新操作翻译。为此,请运行

php artisan vendor:publish --tag=laravel-backpack-import-operation-translations

这将发布操作语言文件到 resources/lang/vendor/backpack/import-operation。存储在此目录中的文件优先于包的默认语言文件。

视图

如果需要,您可以更新操作视图。为此,请运行

php artisan vendor:publish --tag=laravel-backpack-import-operation-views

这将发布操作 blade 文件到 resources/views/vendor/backpack/import-operation。存储在此目录中的文件优先于包的默认视图。

事件

此包在导入过程中不同阶段会触发事件。这样,您可以跟踪导入行何时失败、成功,以及何时开始和结束导入。

导入开始事件

当导入开始处理时,会触发此事件。

RedSquirrelStudio\LaravelBackpackImportOperation\Events\ImportStartedEvent::class
负载
[
    //The Import being processed 
   'import_log' => RedSquirrelStudio\LaravelBackpackImportOperation\Models\ImportLog::class 
]

导入完成事件

当导入完成时,会触发此事件。

事件类
RedSquirrelStudio\LaravelBackpackImportOperation\Events\ImportCompleteEvent::class
负载
[
    //The Completed Import
   'import_log' => RedSquirrelStudio\LaravelBackpackImportOperation\Models\ImportLog::class 
]

导入行处理事件

每次成功处理一行时,都会触发此事件。

事件类
RedSquirrelStudio\LaravelBackpackImportOperation\Events\ImportRowProcessedEvent::class
负载
[
    //The Import being processed 
   'import_log' => RedSquirrelStudio\LaravelBackpackImportOperation\Models\ImportLog::class,
   //The data from the spreadsheet row
   'row_data' => array(),
   //The created/update model from the row
   'entry' => \Illuminate\Database\Eloquent\Model::class 
]

导入行跳过事件

当一行验证失败并被跳过时,会触发此事件。

事件类
RedSquirrelStudio\LaravelBackpackImportOperation\Events\ImportRowSkippedEvent::class
负载
[
    //The Import being processed 
   'import_log' => RedSquirrelStudio\LaravelBackpackImportOperation\Models\ImportLog::class,
   //The data from the spreadsheet row
   'row_data' => array(),
]

限制访问

与 Backpack 中的大多数操作一样,您可以使用以下代码行在 CRUD 控制器的设置函数中限制用户访问

    public function setup()
    {
        //...
        CRUD::denyAccess('import');
        //...
    }

致谢

许可

MIT。有关更多信息,请参阅 许可证文件