kaliop/csv-parser

PHP/OOP CSV 解析器

v1.0.0 2019-05-27 12:06 UTC

This package is auto-updated.

Last update: 2024-08-27 23:57:12 UTC


README

此库允许您以面向对象的方式定义CSV解析,让您轻松过滤和测试导入。它已经在多个大型客户的多个复杂导入项目中投入使用已有很长时间。

主要优势包括

  • 面向对象风格:每个导入一个 Parser 类 = 对项目开发者有意义。
  • 可测试性:一个测试用的csv文件,您可以轻松为导入编写测试。
  • 完全可定制:每个解析结果也是一个PHP类,开发者可以添加自己的逻辑。
  • 松散耦合:此包仅依赖于Symfony的Validator。任何数据库/持久性内容都是可能的(请参阅以下示例)。

安装

使用composer安装此包

composer require kaliop/csv-parser

基本用法

您需要描述CSV列与实体属性之间的映射。为此,您应该首先创建一个 Parser,但首先,让我们看看我们的CSV

date;order_id;client_name;address;postal_code;country;amount
2019-04-15;678945;"Laurent Doe";"12 avenue PhpUnit";34000;France;12
2019-03-12;987564;"Ruh Doe";"15 rue du test";31001;France;50,53
2019-05-01;123456;"Julien Doe";"125 rue PHP";34440;France;69,12
2019-02-09;456123;"Gérard Doe";"15 blvd Bouchard";76000;France;789,10
2019-01-01;965478;"Jean-Luc Doe";"15 rue du test";34000;France;5,00
2019-05-01;126578;"Bernard Doe";"15 rue Symfony";75000;France;33,53
2019-05-01;216543;"Maël Doe";"Disneyland Paris";77000;France;1250,53
2019-05-01;987521;"Gros Doe";"15 rue de Behat";98520;France;50,98

我们的实体看起来像这样

<?php

namespace App\Entity;

class Order
{
    /**
     * @var int
     */
    public $id;

    /**
     * @var \DateTime
     */
    public $date;

    /**
     * @var string
     */
    public $clientName;

    /**
     * @var string
     */
    public $address;

    /**
     * @var int
     */
    public $postalCode;

    /**
     * @var string
     */
    public $country;

    /**
     * @var float
     */
    public $amount;
    
    /**
     * @var null|\DateTime
     */
    public $shipDate = null;
}

创建 Parser

<?php

namespace App\CSV;

use App\Entity\Order;
use Kaliop\CsvParser\Parser\AbstractParser;
use Kaliop\CsvParser\Parser\ParserInterface;
use Kaliop\CsvParser\ColumnHelper;

class OrderParser extends AbstractParser implements ParserInterface
{
    public function getMappingDefinition()
    {
        return [
            ColumnHelper::index('A') => [
                'property'  => 'entity.date',
                'filter'    => function($value) { return \DateTime::createFromFormat('Y-m-d', $value); }
            ],
            ColumnHelper::index('B') => [
                'property'  => 'entity.id',
                'filter'    => function($value) { return \intval($value); }
            ],
            ColumnHelper::index('C') => [
                'property'  => 'entity.clientName',
                'filter'    => function($value) { return \trim($value); }
            ],
            ColumnHelper::index('D') => [
                'property'  => 'entity.address',
                'filter'    => function($value) { return \trim($value); }
            ],
            ColumnHelper::index('E') => [
                'property'  => 'entity.postalCode',
                'filter'    => function($value) { return \intval($value); }
            ],
            ColumnHelper::index('F') => [
                'property'  => 'entity.country',
                'filter'    => function($value) { return \trim($value); }
            ],
            ColumnHelper::index('G') => [
                'property'  => 'entity.amount',
                'filter'    => function($value) { return \floatval($value); }
            ]
        ];
    }

    public function getEntityClassName()
    {
        return Order::class;
    }
}

现在进行魔法操作!在这个例子中,我们将导入的实体持久化到数据库中。

<?php

namespace App\Core;

use App\CSV\OrderParser;

class ImportOrdersFromCSV
{
    protected $em;
    
    public function __construct(EntityManagerInterface $em)
    {
        $this->em = $em;
    }
    
    public function import($csvFilePath)
    {
        $parser = new OrderParser($csvFilePath, ";");
        $results = $parser->execute();
        
        foreach ($results as $result) {
            if ($result->isValid()) {
                $this->em->persist($result->getEntity());
                continue;
            }
            
            // log or do something with invalid entities
        }
        
        $this->em->flush();
    }
}

高级用法

您可以决定更改默认的 ParserResult 类,在实体被解析后执行自己的逻辑。在下面的示例中,我们将添加一个 $shipDate,它将由我们的自定义结果类在 finalize() 方法中设置。

<?php

namespace App\CSV;

use Kaliop\CsvParser\Result\ParserResult;
use App\Entity\Order;

class OrderParserResult extends ParserResult
{
    public function finalize()
    {
        if (!$this->entity instanceof Order || !$this->entity->date) {
            // do nothing on invalid entities
            return;
        }

        $shipDate = clone $this->entity->date;
        $shipDate->modify('+3 days');

        $this->entity->shipDate = $shipDate;
    }
}

现在只需告诉您的Parser使用这个结果类即可

<?php
// ... ImportOrdersFromCSV

$parser->setResultClassName(App\CSV\OrderParserResult::class);

运行PHPUnit测试

./vendor/bin/phpunit