ivbre/data-import

从多种文件格式和媒体导入数据,并将数据导出到这些格式和媒体

0.19.2 2016-09-26 14:23 UTC

README

Build Status Scrutinizer Quality Score Code Coverage Latest Stable Version

简介

这个PHP库提供了一种从多种文件格式和媒体读取数据,并将数据写入这些格式和媒体的方法。此外,它还包括用于操作数据的工具。

特性

  • 读取和写入CSV文件、Excel文件、数据库等。
  • 实时在字符集、日期、字符串和对象之间进行转换。
  • 构建可重用和可扩展的导入工作流程。
  • 独立的组件,您可以单独使用,例如CSV和Excel读取器和写入器。
  • 经过良好测试的代码。

文档

安装

此库可在 Packagist 上获得。推荐安装方法是使用 Composer

$ composer require ddeboer/data-import:@stable

然后包含Composer的自动加载器

require_once 'vendor/autoload.php';

对于与Symfony2项目的集成,可使用 DdeboerDataImportBundle

用法

总的来说,您可以使用此库两种方式:

工作流程

每次数据导入都围绕工作流程进行,并遵循以下步骤:

  1. 构建一个读取器
  2. 构建一个工作流程并将读取器传递给它,可选地传递一个记录器作为第二个参数。将至少一个写入器添加到工作流程中。
  3. 可选地,将过滤器、项目转换器和值转换器添加到工作流程中。
  4. 处理工作流程。这将从读取器中读取数据,过滤和转换数据,并将输出写入每个写入器。处理方法还返回一个包含导入各种信息的Result对象。

换句话说,工作流程充当了读取器和一个或多个写入器、过滤器以及转换器之间的中介。

可选地,您可以在失败时跳过项目,例如这样 $workflow->setSkipItemOnFailure(true)。如果您在构造函数中向工作流程传递了记录器,错误将被记录。

示意图

use Ddeboer\DataImport\Workflow;
use Ddeboer\DataImport\Reader;
use Ddeboer\DataImport\Writer;
use Ddeboer\DataImport\Filter;

$reader = new Reader\...;
$workflow = new Workflow($reader, $logger);
$result = $workflow
    ->addWriter(new Writer\...())
    ->addWriter(new Writer\...())
    ->addFilter(new Filter\CallbackFilter(...))
    ->setSkipItemOnFailure(true)
    ->process()
;

工作流程结果

工作流程结果对象公开了各种方法,您可以使用这些方法在导入后决定做什么。结果将是一个 Ddeboer\DataImport\Result 实例。它由 Workflow 自动创建和填充,在调用 Workflow 上的 process() 方法后会返回给您。

Result 提供以下方法

//the name of the import - which is an optional 3rd parameter to
//the Workflow class. Returns null by default.
public function getName();

//DateTime instance created at the start of the import.
public function getStartTime();

//DateTime instance created at the end of the import.
public function getEndTime();

//DateInterval instance. Diff off the start + end times.
public function getElapsed();

//Count of exceptions which caught by the Workflow.
public function getErrorCount();

//Count of processed items minus the count of exceptions caught.
public function getSuccessCount();

//Count of items processed
//This will not include any filtered items or items which fail conversion.
public function getTotalProcessedCount();

//bool to indicate whether any exceptions were caught.
public function hasErrors();

//An array of exceptions caught by the Workflow.
public function getExceptions();

示例用例

  • 您想发送包含导入结果的电子邮件
  • 您想发送文本警报,如果某个文件失败
  • 如果发生错误,您想将导入文件移动到失败目录
  • 您想记录导入所需的时间

读取器

读取器通过迭代它来读取将要导入的数据。此库包含了一些读取器。此外,您可以轻松地实现自己的读取器

您可以使用读取器单独使用,或者从它们构建工作流程

$workflow = new Workflow($reader);

ArrayReader

读取数组。对于测试您的流程非常有用。

CsvReader

读取 CSV 文件,并优化以尽可能少地使用内存。

use Ddeboer\DataImport\Reader\CsvReader;

$file = new \SplFileObject('/path/to/csv_file.csv');
$reader = new CsvReader($file);

可选地使用不同的分隔符、封装符和/或转义字符进行构建

$reader = new CsvReader($file, ';');

然后迭代 CSV 文件

foreach ($reader as $row) {
    // $row will be an array containing the comma-separated elements of the line:
    // array(
    //   0 => 'James',
    //   1 => 'Bond'
    //   etc...
    // )
}
列头

如果您的某一行包含列头,您可以读取它们以将行转换为关联数组

$reader->setHeaderRowNumber(0);

foreach ($reader as $row) {
    // $row will now be an associative array:
    // array(
    //   'firstName' => 'James',
    //   'lastName'  => 'Bond'
    //   etc...
    // )
}
严格模式

CSV 读取器默认在严格模式下运行。如果读取器遇到一行值的数量与列头数量不一致,将记录错误并跳过该行。使用 getErrors() 获取错误。

要在实例化读取器后禁用严格模式,请设置 $reader->setStrict(false)

禁用严格模式意味着

  1. 任何包含比列头少值的行将用空值填充。
  2. 任何包含比列头多值的行中的额外值将被忽略。

这种情况下的示例

  • Outlook 2010:省略尾随空值
  • Google Contacts:导出的值多于列头
重复的标题

有时 CSV 文件包含重复的列头,例如

默认情况下,如果在文件上调用 setHeaderRowNumber(0),将抛出 DuplicateHeadersException。您可以通过以下三种方式之一处理重复列

  • 调用 setColumnHeaders(['id', 'details', 'details_2']) 以指定自己的列头
  • 使用 CsvReader::DUPLICATE_HEADERS_INCREMENT 标志调用 setHeaderRowNumber 以生成递增的列头;在这种情况下:iddetailsdetails1
  • 使用 CsvReader::DUPLICATE_HEADERS_MERGE 标志调用 setHeaderRowNumber 以将重复的值合并到数组中;在这种情况下,第一行的值将变为:[ 'id' => 1, 'details' => [ 'bla', 'more bla' ] ]

DbalReader

通过 Doctrine 的 DBAL 读取数据。您的项目应包含 Doctrine DBAL 包

$ composer require doctrine/dbal
use Ddeboer\DataImport\Reader\DbalReader;

$reader = new DbalReader(
    $connection, // Instance of \Doctrine\DBAL\Connection
    'SELECT u.id, u.username, g.name FROM `user` u INNER JOIN groups g ON u.group_id = g.id'
);

DoctrineReader

通过 Doctrine ORM 读取数据

use Ddeboer\DataImport\Reader\DoctrineReader;

$reader = new DoctrineReader($entityManager, 'Your\Namespace\Entity\User');

ExcelReader

充当 PHPExcel 库 的适配器。请确保在项目中包含该库

$ composer require phpoffice/phpexcel

然后使用读取器打开 Excel 文件

use Ddeboer\DataImport\Reader\ExcelReader;

$file = new \SplFileObject('path/to/excel_file.xls');
$reader = new ExcelReader($file);

要设置读取列头的行号,请将数字作为第二个参数传递。

$reader = new ExcelReader($file, 2);

要读取特定的工作表

$reader = new ExcelReader($file, null, 3);

###OneToManyReader

允许合并两个数据源(使用现有的读取器),例如,您有一个包含订单的 CSV 文件和一个包含订单项目的 CSV 文件。

想象两个如下所示的 CSV 文件

OrderId,Price
1,30
2,15
OrderId,Name
1,"Super Cool Item 1"
1,"Super Cool Item 2"
2,"Super Cool Item 3"

您希望将项目关联到订单中。使用 OneToMany 读取器,我们可以使用 OneToManyReader 中指定的键将这些行嵌套在订单中。

代码可能看起来像这样

$orderFile = new \SplFileObject("orders.csv");
$orderReader = new CsvReader($file, $orderFile);
$orderReader->setHeaderRowNumber(0);

$orderItemFile = new \SplFileObject("order_items.csv");
$orderItemReader = new CsvReader($file, $orderFile);
$orderItemReader->setHeaderRowNumber(0);

$oneToManyReader = new OneToManyReader($orderReader, $orderItemReader, 'items', 'OrderId', 'OrderId');

第三个参数是嵌套订单项目数据下的键。这将是一个订单项目的数组。第四和第五个参数是数据的“主键”和“外键”。OneToMany 读取器将尝试使用这些键匹配数据。例如,对于上面给出的 CSV,您期望订单“1”具有前两个订单项目与之关联,因为这些订单项目的订单 ID 也是“1”。

注意:如果您省略最后一个参数,如果两个文件具有相同的字段,则可以省略。例如,如果参数 4 是 'OrderId' 而您未指定参数 5,则读取器将使用 'OrderId' 查找外键

生成的数据将如下所示

//Row 1
array(
    'OrderId' => 1,
    'Price' => 30,
    'items' => array(
        array(
            'OrderId' => 1,
            'Name' => 'Super Cool Item 1',
        ),
        array(
            'OrderId' => 1,
            'Name' => 'Super Cool Item 2',
        ),
    ),
);

//Row2
array(
    'OrderId' => 2,
    'Price' => 15,
    'items' => array(
        array(
            'OrderId' => 2,
            'Name' => 'Super Cool Item 1',
        ),
    )
);

创建读取器

您可以通过实现 Reader 接口 来创建自己的数据读取器。

写入器

ArrayWriter

类似于 ArrayReader。可能对测试工作流程最有用。

CsvWriter

写入 CSV 文件

use Ddeboer\DataImport\Writer\CsvWriter;

$writer = new CsvWriter();
$writer->setStream(fopen('output.csv', 'w'));

// Write column headers:
$writer->writeItem(array('first', 'last'));

$writer
    ->writeItem(array('James', 'Bond'))
    ->writeItem(array('Auric', 'Goldfinger'))
    ->finish();

DoctrineWriter

通过 Doctrine 写入数据

use Ddeboer\DataImport\Writer\DoctrineWriter;

$writer = new DoctrineWriter($entityManager, 'YourNamespace:Employee');
$writer
    ->prepare()
    ->writeItem(
        array(
            'first' => 'James',
            'last'  => 'Bond'
        )
    )
    ->finish();

默认情况下,DoctrineWriter 在运行工作流程之前将截断您的数据。如果不希望这样做,请调用 disableTruncate()

如果您没有截断数据,DoctrineWriter 将尝试找到具有其主键设置为项目第一列值的实体。如果找到,则更新该实体,否则插入。您可以通过向其构造函数传递第三个参数来告诉 DoctrineWriter 使用项目中的不同列来查找实体。

$writer = new DoctrineWriter($entityManager, 'YourNamespace:Employee', 'columnName');

或者

$writer = new DoctrineWriter($entityManager, 'YourNamespace:Employee', array('column1', 'column2', 'column3'));

DoctrineWriter 还会自动搜索关联并将其通过实体引用链接起来。例如,假设您有一个要导入的产品实体,它必须与一个类别相关联。如果导入文件中有一个名为 'Category' 的字段,其中包含一个 ID,则写入器将使用元数据来获取关联类并创建一个引用,以便可以正确关联。在已使用转换器检索关联的情况下,DoctrineWriter 将跳过任何已经是对象的关联字段。

PdoWriter

使用 PDO 写入器将数据导入到关系型数据库(如 MySQL、SQLite 或 MS SQL)而无需使用 Doctrine。

use Ddeboer\DataImport\Writer\PdoWriter;

$pdo = new \PDO('sqlite::memory:');
$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);

$writer = new PdoWriter($pdo, 'my_table');

ExcelWriter

将数据写入 Excel 文件。它需要 PHPExcel 包

$ composer require phpoffice/phpexcel
use Ddeboer\DataImport\Writer\ExcelWriter;

$file = new \SplFileObject('data.xlsx', 'w');
$writer = new ExcelWriter($file);

$writer
    ->prepare()
    ->writeItem(array('first', 'last'))
    ->writeItem(array('first' => 'James', 'last' => 'Bond'))
    ->finish();

您可以为要写入的电子表格指定名称

$writer = new ExcelWriter($file, 'My sheet');

您可以打开已存在的文件并向其中添加电子表格

$file = new \SplFileObject('data.xlsx', 'a');   // Open file with append mode
$writer = new ExcelWriter($file, 'New sheet');

如果您希望覆盖现有电子表格,则指定现有电子表格的名称

$writer = new ExcelWriter($file, 'Old sheet');

ConsoleTableWriter

此写入器在您从命令行启动工作流程时以调试目的将项目显示为控制台输出上的表格。它需要 Symfony 的 Console 组件 2.5 或更高版本

$ composer require symfony/console ~2.5
use Ddeboer\DataImport\Reader;
use Ddeboer\DataImport\Writer\ConsoleTableWriter;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Helper\Table;

$reader = new Reader\...;
$output = new ConsoleOutput(...);

$table = new Table($output);

// Make some manipulations, e.g. set table style
$table->setStyle('compact');

$workflow = new Workflow($reader);
$workflow->addWriter(new ConsoleTableWriter($output, $table));

ConsoleProgressWriter

此写入器在您从命令行启动工作流程时显示导入进度。它需要 Symfony 的 Console 组件

$ composer require symfony/console
use Ddeboer\DataImport\Writer\ConsoleProgressWriter;
use Symfony\Component\Console\Output\ConsoleOutput;

$output = new ConsoleOutput(...);
$progressWriter = new ConsoleProgressWriter($output, $reader);

// Most useful when added to a workflow
$workflow->addWriter($progressWriter);

您可以向 ConsoleProgressWriter 传递各种可选参数。这些包括输出格式和重绘频率。您可以在此处了解更多关于选项的信息 这里

您可能希望将重绘速率设置得高于默认值,因为它会在每条记录被 Workflow 处理后更新控制台文本,这可能会大大减慢导入/导出过程。

$output = new ConsoleOutput(...);
$progressWriter = new ConsoleProgressWriter($output, $reader, 'debug', 100);

如上所述,我们将输出格式设置为 'debug' 并将重绘速率设置为 100。这将仅在每处理 100 条记录后重绘控制台进度文本。

debug 格式是默认格式,因为它显示 ETA 和内存使用情况。如果您希望使用更简单的格式化程序,则可以使用它

$output = new ConsoleOutput(...);
$progressWriter = new ConsoleProgressWriter($output, $reader, 'normal', 100);

回调写入器

除了实现自己的写入器外,您还可以使用 CallbackWriter 提供的快速解决方案

use Ddeboer\DataImport\Writer\CallbackWriter;

$workflow->addWriter(new CallbackWriter(function ($row) use ($storage) {
    $storage->store($row);
}));

抽象写入器

不需要从头开始实现自己的写入器,您可以使用AbstractStreamWriter作为基础,实现writeItem方法,然后即可完成。

use Ddeboer\DataImport\Writer\AbstractStreamWriter;

class MyStreamWriter extends AbstractStreamWriter
{
    public function writeItem(array $item)
    {
        fputs($this->getStream(), implode(',', $item));
    }
}

$writer = new MyStreamWriter(fopen('php://temp', 'r+'));
$writer->setCloseStreamOnFinish(false);

$workflow->addWriter(new MyStreamWriter());
$workflow->process();

$stream = $writer->getStream();
rewind($stream);

echo stream_get_contents($stream);

流合并写入器

假设您有两个流写入器,根据其中一个字段的不同处理字段。然后您应使用StreamMergeWriter来调用适当的Writer。

默认字段名称是discr,但可以使用setDiscriminantField()方法进行更改。

use Ddeboer\DataImport\Writer\StreamMergeWriter;

$writer = new StreamMergeWriter();

$writer->addWriter('first writer', new MyStreamWriter());
$writer->addWriter('second writer', new MyStreamWriter());

创建写入器

通过实现Writer接口来构建自己的写入器。

过滤器

过滤器决定数据输入是否被接受到导入过程中。

回调过滤器

CallbackFilter封装了您的回调函数,该函数确定数据是否应被接受。只有当函数返回true时,数据输入才被接受。

use Ddeboer\DataImport\Filter\CallbackFilter;

// Don’t import The Beatles
$filter = new CallbackFilter(function ($data) {
    return ('The Beatles' != $data['name']);
});

$workflow->addFilter($filter);

偏移量过滤器

OffsetFilter允许您:

  • 跳过开始处的某些项
  • 仅处理指定数量的项(跳过其余项)

您可以将这两个参数组合起来处理数据的中间部分,例如处理CSV文件中间的5-7行,该文件共有十行。

OffsetFilter通过其构造函数进行配置:new OffsetFilter($offset = 0, $limit = null)。注意:$offset是一个基于0的索引。

use Ddeboer\DataImport\Filter\OffsetFilter;

// Default implementation is to start from the beginning without maximum count
$filter = new OffsetFilter(0, null);
$filter = new OffsetFilter(); // You can omit both parameters

// Start from the third item, process to the end
$filter = new OffsetFilter(2, null);
$filter = new OffsetFilter(2); // You can omit the second parameter

// Start from the first item, process max three items
$filter = new OffsetFilter(0, 3);

// Start from the third item, process max five items (items 3 - 7)
$filter = new OffsetFilter(2, 5);

日期时间阈值过滤器

如果想要进行增量导入,这个过滤器很有用。指定一个阈值DateTime实例,一个列名(默认为updated_at),以及一个用于将读取的过滤项的值转换的DateTimeValueConverter。严格大于阈值的项将被丢弃。

use Ddeboer\DataImport\Filter\DateTimeThresholdFilter;
use Ddeboer\DataImport\ValueConverter\DateTimeValueConverter;

new DateTimeThresholdFilter(
    new DateTimeValueConverter(),
    new \DateTime('yesterday')
);

验证器过滤器

在将数据保存到数据库之前验证数据是一个常见用例。这正是ValidatorFilter所做的。要使用它,请将Symfony的Validator组件包含到您的项目中。

$ compose require symfony/validator

ValidatorFilter的工作方式如下:

use Ddeboer\DataImport\Filter\ValidatorFilter;

$filter = new ValidatorFilter($validator);
$filter->add('email', new Assert\Email());
$filter->add('sku', new Assert\NotBlank());

验证器的默认行为是收集所有违规行为并跳过每个无效行。如果您想在第一行失败时停止,可以调用ValidatorFilter::throwExceptions(),它将抛出一个包含行号和违规列表的ValidationException

项目转换器

映射项目转换器

使用MappingItemConverter向工作流程添加映射。输入数据中的键将根据这些映射进行重命名。假设您有输入数据

$data = array(
    array(
        'foo' => 'bar',
        'baz' => array(
            'some' => 'value'
        )
    )
);

您可以将键foobaz映射如下:

use Ddeboer\DataImport\ItemConverter\MappingItemConverter;

$converter = new MappingItemConverter();
$converter
    ->addMapping('foo', 'fooloo')
    ->addMapping('baz', array('some' => 'else'));

$workflow->addItemConverter($converter)
    ->process();

您的输出数据现在将是

array(
    array(
        'fooloo' => 'bar',
        'baz'    => array(
            'else' => 'value'
        )
    )
);

NestedMappingItemConverter

使用NestedMappingItemConverter向工作流程添加映射,如果输入数据包含嵌套数组。输入数据中的键将根据这些映射进行重命名。假设您有输入数据

$data = array(
    'foo'   => 'bar',
    'baz' => array(
        array(
            'another' => 'thing'
        ),
        array(
            'another' => 'thing2'
        ),
    )
);

您可以将键another映射如下。

use Ddeboer\DataImport\ItemConverter\NestedMappingItemConverter;

$mappings = array(
    'foo'   => 'foobar',
    'baz' => array(
        'another' => 'different_thing'
    )
);

$converter = new NestedItemMappingConverter('baz');
$converter->addMapping($mappings);

$workflow->addItemConverter($converter)
    ->process();

您的输出数据现在将是

array(
    'foobar' => 'bar',
    'baz' => array(
        array(
            'different_thing' => 'thing'
        ),
        array(
            'different_thing' => 'thing2'
        ),
    )
);

创建项目转换器

实现ItemConverterInterface以创建您自己的项目转换器

use Ddeboer\DataImport\ItemConverter\ItemConverterInterface;

class MyItemConverter implements ItemConverterInterface
{
    public function convert($item)
    {
        // Do your conversion and return updated $item
        return $changedItem;
    }
}

回调项目转换器

您可以使用回调而不是实现自己的项目转换器

use Ddeboer\DataImport\ItemConverter\CallbackItemConverter;

// Use a fictional $translator service to translate each value
$converter = new CallbackItemConverter(function ($item) use ($translator) {
    foreach ($item as $key => $value) {
        $item[$key] = $translator->translate($value);
    }

    return $item;
});

值转换器

值转换器用于转换特定字段(例如,数据库中的列)。

DateTimeValueConverter

DateTimeValueConverter有两种用途

  1. 将您指定的格式的日期表示转换为DateTime对象。
  2. 将您指定的格式的日期表示转换为不同的格式。
将日期转换为DateTime对象。
use Ddeboer\DataImport\ValueConverter\DateTimeValueConverter;

$converter = new DateTimeValueConverter('d/m/Y H:i:s');
$workflow->addValueConverter('my_date_field', $converter);

如果您的日期字符串在以下位置指定的格式中:https://php.ac.cn/manual/en/datetime.formats.date.php,则可以省略格式参数。

use Ddeboer\DataImport\ValueConverter\DateTimeValueConverter;

$converter = new DateTimeValueConverter();
$workflow->addValueConverter('my_date_field', $converter);
将日期字符串转换为不同格式的日期字符串。
use Ddeboer\DataImport\ValueConverter\DateTimeValueConverter;

$converter = new DateTimeValueConverter('d/m/Y H:i:s', 'd-M-Y');
$workflow->addValueConverter('my_date_field', $converter);

如果您的日期格式与以下指定格式一致:https://php.ac.cn/manual/en/datetime.formats.date.php,您可以将null作为第一个参数传递。

use Ddeboer\DataImport\ValueConverter\DateTimeValueConverter;

$converter = new DateTimeValueConverter(null, 'd-M-Y');
$workflow->addValueConverter('my_date_field', $converter);

日期时间到字符串值转换器

DateTimeToStringValueConverter的主要用途是将DateTime对象转换为正确的格式的字符串表示。默认格式为'Y-m-d H:i:s';

use Ddeboer\DataImport\ValueConverter\DateTimeToStringValueConverter;

$converter = new DateTimeToStringValueConverter;
$converter->convert(\DateTime('2010-01-01 01:00:00'));  //will return string '2010-01-01 01:00:00'

对象转换器

将对象转换为标量值。要使用此转换器,您必须在项目中包含Symfony的PropertyAccess组件。

$ composer require symfony/property-access
使用__toString()

如果您的对象具有__toString()方法,将使用该值。

use Ddeboer\DataImport\ValueConverter\ObjectConverter;

class SecretAgent
{
    public function __toString()
    {
        return '007';
    }
}

$converter = new ObjectConverter();
$string = $converter->convert(new SecretAgent());   // $string will be '007'
使用对象访问器

如果您的对象没有__toString()方法,将调用其访问器。

class Villain
{
    public function getName()
    {
        return 'Bad Guy';
    }
}

class Organization
{
    public function getVillain()
    {
        return new Villain();
    }
}

use Ddeboer\DataImport\ValueConverter\ObjectConverter;

$converter = new ObjectConverter('villain.name');
$string = $converter->convert(new Organization());   // $string will be 'Bad Guy'

字符串到对象转换器

根据字符串值在数据库中查找对象

use Ddeboer\DataImport\ValueConverter\StringToObjectConverter;

$converter = new StringToObjectConverter($repository, 'name');
$workflow->addValueConverter('input_name', $converter);

回调值转换器

如果您想省去编写专用类的麻烦,请使用此功能。

use Ddeboer\DataImport\ValueConverter\CallbackValueConverter;

$callable = function ($item) {
    return implode(',', $item);
};

$converter = new CallbackValueConverter($callable);
$output = $converter->convert(array('foo', 'bar')); // $output will be "foo,bar"

映射值转换器

在构造函数提供的哈希中查找一个键

use Ddeboer\DataImport\ValueConverter\MappingValueConverter;

$converter = new MappingValueConverter(array(
    'source' => 'destination'
));

$converter->convert('source'); // destination
$converter->convert('unexpected value'); // throws an UnexpectedValueException

示例

导入CSV文件并写入数据库

此示例演示了如何从CSV文件中读取数据并将其写入数据库。

假设我们有一个以下CSV文件

event;beginDate;endDate
Christmas;20131225;20131226
New Year;20131231;20140101

我们想将此数据写入Doctrine实体

namespace MyApp;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 */
class Event
{
    /**
     * @ORM\Column()
     */
    protected $event;

    /**
     * @ORM\Column(type="datetime")
     */
    protected $beginDate;

    /**
     * @ORM\Column(type="datetime")
     */
    protected $endDate;

    public function setEvent($event)
    {
        $this->event = $event;
    }

    public function setBeginDate($date)
    {
        $this->beginDate = $date;
    }

    public function setEndDate($date)
    {
        $this->endDate = $date;
    }

    // And some getters
}

然后您可以通过以下方式导入CSV并将其保存为实体。

use Ddeboer\DataImport\Workflow;
use Ddeboer\DataImport\Reader\CsvReader;
use Ddeboer\DataImport\Writer\DoctrineWriter;
use Ddeboer\DataImport\ValueConverter\StringToDateTimeValueConverter;

// Create and configure the reader
$file = new \SplFileObject('input.csv');
$csvReader = new CsvReader($file);

// Tell the reader that the first row in the CSV file contains column headers
$csvReader->setHeaderRowNumber(0);

// Create the workflow from the reader
$workflow = new Workflow($csvReader);

// Create a writer: you need Doctrine’s EntityManager.
$doctrineWriter = new DoctrineWriter($entityManager, 'MyApp:Event');
$workflow->addWriter($doctrineWriter);

// Add a converter to the workflow that will convert `beginDate` and `endDate`
// to \DateTime objects
$dateTimeConverter = new StringToDateTimeValueConverter('Ymd');
$workflow
    ->addValueConverter('beginDate', $dateTimeConverter)
    ->addValueConverter('endDate', $dateTimeConverter);

// Process the workflow
$workflow->process();

导出到CSV文件

此示例演示了如何将数据导出到CSV文件。

use Ddeboer\DataImport\Workflow;
use Ddeboer\DataImport\Reader\ArrayReader;
use Ddeboer\DataImport\Writer\CsvWriter;
use Ddeboer\DataImport\ValueConverter\CallbackValueConverter;

// Your input data
$reader = new ArrayReader(array(
    array(
        'first',        // This is for the CSV header
        'last',
        array(
            'first' => 'james',
            'last'  => 'Bond'
        ),
        array(
            'first' => 'hugo',
            'last'  => 'Drax'
        )
    ))
);

// Create the workflow from the reader
$workflow = new Workflow($reader);

// Add the writer to the workflow
$file = new \SplFileObject('output.csv', 'w');
$writer = new CsvWriter($file);
$workflow->addWriter($writer);

// As you can see, the first names are not capitalized correctly. Let's fix
// that with a value converter:
$converter = new CallbackValueConverter(function ($input) {
    return ucfirst($input);
});
$workflow->addValueConverter('first', $converter);

// Process the workflow
$workflow->process();

这将写入一个名为output.csv的CSV文件,其中首字母将大写。

first;last
James;Bond
Hugo;Drax

数组值转换器映射

ArrayValueConverterMap用于过滤多级数组的值。

列表中定义的转换器应用于匹配定义的array_keys的每个数据项的值。

//...
$data = array(
    'products' => array(
        0 => array(
            'name' => 'some name',
            'price' => '€12,16',
        ),
        1 => array(
            'name' => 'some name',
            'price' => '€12,16',
        )
    )
);

// ...
// create the workflow and reader etc.
// ...

$workflow->addValueConverter(new ArrayValueConverterMap(array(
    'name' => array(new CharsetValueConverter('UTF-8', 'UTF-16')), // encode to UTF-8
    'price' => array(new CallbackValueConverter(function ($input) {
        return str_replace('', '', $input); // remove € char
    }),
)));

// ..
// after filtering data looks as follows
$data = array(
    'products' => array(
        0 => array(
            'name' => 'some name', // in UTF-8
            'price' => '12,16',
        ),
        1 => array(
            'name' => 'some name',
            'price' => '12,16',
        )
    )
);

运行测试

克隆此仓库

$ git clone https://github.com/ddeboer/data-import.git
$ cd data-import

安装开发依赖项

$ composer install --dev

并运行PHPUnit

$ phpunit

许可

DataImport在MIT许可下发布。有关详细信息,请参阅LICENSE文件。