ddeboer/data-import

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

0.20.0 2016-06-23 06:26 UTC

README

Build Status Scrutinizer Quality Score Code Coverage Latest Stable Version

此库已被重命名为PortPHP,并将被弃用。请使用 PortPHP 代替。

简介

这个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文件

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

您想将项目关联到订单。使用OneToManyReader,我们可以使用您在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');

第三个参数是嵌套订单项目数据的键。这将是一个订单项目数组。第四和第五个参数是数据的“主键”和“外键”。OneToManyReader将尝试使用这些键匹配数据。例如,上面的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

您不必实现自己的写入器,可以直接使用 CallbackWriter 提供的快速解决方案。

use Ddeboer\DataImport\Writer\CallbackWriter;

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

AbstractStreamWriter

您不必从头开始实现自己的写入器,可以以 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

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

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

use Ddeboer\DataImport\Writer\StreamMergeWriter;

$writer = new StreamMergeWriter();

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

创建一个写入器

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

过滤器

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

CallbackFilter

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

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);

DateTimeThresholdFilter

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

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

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

ValidatorFilter

在将数据保存到数据库之前,验证数据是一个常见的用例。这正是 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](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

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'

ObjectConverter

将对象转换为标量值。要使用此转换器,您必须在项目中包含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'

StringToObjectConverter

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

use Ddeboer\DataImport\ValueConverter\StringToObjectConverter;

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

CallbackValueConverter

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

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"

MappingValueConverter

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

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();

这将创建一个CSV文件output.csv,其中首字母大写

first;last
James;Bond
Hugo;Drax

ArrayValueConverterMap

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文件。