shoppingfeed/php-feed-generator

ShoppingFeed Feed管理器

1.3.1 2024-09-11 15:13 UTC

README

这个库旨在简化符合ShoppingFeed服务的feed生成。如果我们想解开这个声明

  • 一个feed是一个包含产品(一系列参考、描述、价格、数量、图片链接等)的文件
  • 一个符合规范的feed默认情况下是一个符合这里定义的规则(关于此类文件可能的样子示例,您可以检查这个示例);我说默认情况下,因为我们可以有其他格式,但稍后我会详细介绍
  • 您可以在我们的网站上了解更多关于ShoppingFeed服务的信息这里

它允许您使用库中定义的一系列方法格式化、过滤、映射和验证您的产品。完成所有这些后,生成器输出一个文件:这是这个文件,ShoppingFeed解决方案将使用它来导入所有您的产品,以便它们可以被发送到不同的市场。

何时应该使用此feed生成器?

  • 如果您正在考虑使用ShoppingFeed解决方案
  • 并且您的feed(包含所有产品的文件)不是开箱即用的格式
  • 并且您希望有一个简单/快速设置
  • 或者如果您想为现有电子商务平台的新版本(如Magento、Prestashop等)提供开箱即用的格式
  • 或者如果您想避免自己生成和格式化feed

此库生成的feed默认情况下是标准XML ShoppingFeed格式。但此库还允许您

  • 选择不同的格式(目前我们除了默认的XML外还支持CSV)
  • 或者通过扩展ProductFeedWriterInterface编写自己的FormatWriter

需求

  • PHP版本5.5或更高
  • 使用XML输出时需要PHP XML扩展

安装

composer require shoppingfeed/php-feed-generator

概述

该组件作为管道,将任何数据集转换为符合XML输出的文件或其他目的地。

从用户的角度来看,它由将您的数据映射到ShoppingFeed\Feed\Product\Product对象组成。库负责其余工作:格式化数据和写入有效的XML。

入门

<?php
namespace ShoppingFeed\Feed;

# first create an instance of the generator
$generator = new ProductGenerator();

# then, you need to define at least one mapper 
$generator->addMapper(
    # more details below
);

# you also need your data / products at hand
$items = [
    [
        # product 1 
    ],
    [
        # product 2
    ],
    # ...
];

# finally, you can generate the feed
$generator->write($items);

这是一个骨架示例。在接下来的部分中,我们将详细说明每一步,指定不同的选项,并添加更多中间可选步骤。

必填字段

在生成的feed中,只有有效的产品将被写入。一个有效的最小产品项需要以下属性

  • 一个参考(也称为SKU)
  • 一个名称
  • 一个价格

您的数据源必须包含这些信息,或者您可以在feed生成期间硬编码其中一些信息。

推荐字段

即使它们不是必需的,以下字段也将确保您的产品不会被任何渠道拒绝

链接

返回您商店中的产品链接,对于shopbot(Google购物等)应存在

图片

至少一张产品图片可以防止您的产品被拒绝。

描述

推送简短描述。嵌入的HTML / JavaScript / CSS对于大多数渠道来说无关紧要。

数量

未设置时,数量设置为零。因此,请确保设置此字段并开始销售!

运费/运输时间

运输信息对于最终客户来说非常有用,并且对于有效的总购物车计算也是有效的。如果适用,您应提供这些信息。

属性

基本属性(当适用时)是颜色和尺寸,但通常始终为产品和它们的变体提供属性。

指定输出位置

默认情况下,XML被写入标准输出,但您可以指定一个URI,例如本地文件。

<?php
namespace ShoppingFeed\Feed; 

$generator = new ProductGenerator();
$generator->setUri('file://my-feed.xml');

压缩输出

根据我们的经验,在ShoppingFeed的导入过程中,数据上传/下载占用了大量时间。

由于XML可能被视为“重量级”格式,它对网络性能和成本的负面影响不可忽视:这就是为什么我们强烈建议在生产环境中生成数据源时进行压缩。

压缩由PHP流包装器原生支持,因此您需要做的就是指定文件URI中的压缩流(ShoppingFeed目前仅支持gzip压缩)。

<?php
namespace ShoppingFeed\Feed;
 
$generator = new ProductGenerator();
$generator->setUri('compress.zlib://my-feed.xml.gz');

这将最终将文件大小减少到大约9倍。Zlib压缩对处理器的占用非常小。

设置信息

生成器接受一些设置或有用信息,如生成数据源的平台或应用程序。我们建议始终指定此设置,因为这可以帮助我们调试并提供适当的支持。

<?php
namespace ShoppingFeed\Feed;

$generator = (new ProductGenerator)
    ->setUri('file://my-feed.xml')
    ->setPlatform('Magento', '2.2.1');

# Set any extra vendor attributes.
$generator    
    ->setAttribute('storeName', 'my great store')
    ->setAttribute('storeUrl', 'http://my-greate-store.com');

定义输出格式

目前,库支持以下格式

  • xml:默认,所有功能可用。
  • csv:不支持数据源属性、平台和元数据。运输和折扣仅限于1个物品。

格式可以定义为如下

<?php
namespace ShoppingFeed\Feed;
# constructor
$generator = new ProductGenerator('file://my-feed.csv', 'csv');
# Or with setter
$generator->setWriter('csv');

CSV特定选项

CSV输出写入器需要暂时存储数据。默认情况下,当内存达到2MB时,数据会被刷新到一个文件中。您可以禁用或增加内存使用,如下所示

<?php
namespace ShoppingFeed\Feed;
# Disable memory allocation
Csv\CsvProductFeedWriter::setDefaultMaxMemoryUsage(0);

# Allocate 100MB of memory (value is in bytes)
Csv\CsvProductFeedWriter::setDefaultMaxMemoryUsage(100^4);

# No memory limit
Csv\CsvProductFeedWriter::setDefaultMaxMemoryUsage(-1);

基本示例

一旦数据源实例被适当配置,您必须提供至少一个mapper和一个数据集以运行数据源生成。

<?php
namespace ShoppingFeed\Feed;

$generator = (new ProductGenerator)->setPlatform('Magento', '2.2.1');

# Mappers are responsible for converting your data format to populated product
$generator->addMapper(function(array $item, Product\Product $product) {
    $product
        ->setName($item['title'])
        ->setReference($item['sku'])
        ->setPrice($item['price'])
        ->setQuantity($item['quantity'])
	->setAttribute('custom1', $item['custom1'])
	->setAttribute('custom2', $item['custom2']);
});

# Data set fixtures
$items[0] = ['sku' => 1, 'title' => 'Product 1', 'price' => 5.99, 'quantity' => 3];
$items[1] = ['sku' => 2, 'title' => 'Product 2', 'price' => 12.99, 'quantity' => 6];

# now generates the feed with $items collection
$generator->write($items);

这就是全部!将此代码放入脚本中然后运行,XML应该出现在您的输出(浏览器或终端)中。

如果项目/产品数量足够大,以至于可能导致内存问题,您始终可以使用生成器

function getLotsOfProducts(): iterable
{
    while($batchOfProducts = getNextTenProductsFromTheDatabse()) {
        foreach ($batchOfProducts as $product) {
            yield $product;
        }
    }
}

$generator->write(getLotsOfProducts());

数据处理管道

此架构描述了生成器在为每个产品生成数据源时将应用的执行管道循环。

-> exec processors[] -> exec filters[] -> exec mappers[] -> validate -> write ->
|                                                                              |
<------------------------------------------------------------------------------

处理器

在某些情况下,您可能需要在映射之前预处理数据。

这也可以在mapper或您的数据集中完成,但有时需要分离,因此您可以注册在mapper之前执行的处理器,并在映射过程之前准备数据。

在此示例中,当没有提供描述时,我们硬编码描述。

<?php
namespace ShoppingFeed\Feed;

$generator = new ProductGenerator();

$generator->addProcessor(function(array $item) {
    if (! isset($item['description'])) {
        $item['description'] = 'Product description coming soon';
    }
    # modified data must be returned
    return $item;
});
 
$generator->addMapper(function(array $item, Product\Product $product) {
    $product->setDescription($item['description']);
});

您可以注册尽可能多的处理器,但处理器

  • 仅接受$item作为参数
  • 期望返回值
  • 返回值用于下一阶段(下一个处理器或下一个mapper)

过滤器

过滤器,如名称所示,旨在从数据源中丢弃一些项目,同时保留其他项目。

过滤器在处理器之后执行,因为项目必须在做出保留或丢弃的决定之前完全填写。

过滤器预期的返回值是一个布尔值,其中

  • TRUE:项目将被传递到管道中的下一个项目,即映射器
  • FALSE:项目将被丢弃
<?php
namespace ShoppingFeed\Feed;

$generator = new ProductGenerator();

# Ignore all items with undefined quantity
$generator->addFilter(function(array $item) {
   return isset($item['quantity']);
});

# Ignore all items with prices above 10
$generator->addFilter(function(array $item) {
   return $item['price'] <= 10;
});

# only items that pass the previous filter conditions are considered by mappers
$generator->addMapper(function(array $item, Product\Product $product) {
    // do some stuff
});

映射器

如上所述,必须注册至少一个映射器,这是您填充Product实例的地方,该实例稍后由库转换为XML(或其他格式)。

addMapper方法接受任何可调用类型,如函数或可调用对象。

映射器将在对您在generate方法中提供的集合进行迭代时被调用,以下为调用参数

  • (mixed $item, ShoppingFeed\Feed\Product\Product $product)

其中

  • $item是您的数据
  • $product是用于填充$item数据的对象

请注意,您的回调没有期望的返回值

映射器如何被调用?

您可以提供任意多的映射器,它们将按照提供的顺序以FIFO(先进先出)模式执行 - 也就是说,按照提供的顺序。注册多个映射器的功能可以帮助您以所需的方式组织代码,注册多个映射器时没有特定的性能影响。

作为一个组织示例,您可以为处理主要产品注册一个映射器,并为它的变体注册一个映射器。

<?php
namespace ShoppingFeed\Feed;

$generator = new ProductGenerator();

# Populate product properties
$generator->addMapper(function(array $item, Product\Product $product) {
    $product
        ->setName($item['title'])
        ->setReference($item['sku'])
        ->setPrice($item['price'])
        ->setQuantity($item['quantity']);
});

# Populate product's variations. Product properties are already populated by the previous mapper
$generator->addMapper(function(array $item, Product\Product $product) {
    foreach ($item['variations'] as $item) {
        $variation = $product->createVariation();
        $variation
            ->setReference($item['sku'])
            ->setPrice($item['price'])
            ->setQuantity($item['quantity'])
	    ->setAttribute('custom1', $item['custom1'])
	    ->setAttribute('custom2', $item['custom2']);
    }
});

验证

默认情况下,生成器不会对产品进行验证。在开发过程中,您可能会遇到无效的产品并了解为什么它们是无效的。为此,您可以为生成器指定如何处理验证

<?php
namespace ShoppingFeed\Feed;

$generator = new ProductGenerator();

# Only exclude invalid products, with no error reporting.
$generator->setValidationFlags(ProductGenerator::VALIDATE_EXCLUDE);

# Or throw an exception once invalid product is met
$generator->setValidationFlags(ProductGenerator::VALIDATE_EXCEPTION);

验证要求您的产品至少包含

  • reference(SKU)
  • 价格
  • name(仅适用于父产品)

自定义输出

默认情况下,产品生成器使用XML编写器,但您可以通过注册自己的ShoppingFeed\Feed\ProductFeedWriterInterface实现来自定义输出。

注册新的编写器

编写器存储在类级别,因此您只需注册一次

<?php
ShoppingFeed\Feed\ProductGenerator::registerWriter('csv', 'App\CsvWriter');
  • csv:是一个任意的编写器标识符别名
  • App\CsvWriter:实现`ShoppingFeed\Feed\ProductFeedWriterInterface`的类

完成后,您可以将编写器别名指定为构造函数的第二个参数

<?php
$generator = new ShoppingFeed\Feed\ProductGenerator('file.csv', 'csv');

性能考虑

生成大型XML源可能是一个非常漫长的过程,因此我们建议

  • 从命令行/ cron离线运行源生成:在这种模式下将PHP的max_exection_time设置为0
  • 尝试在不同的机器上生成源,而不是用作您的Web服务器的机器,或在流量受限的机器上:源生成过程可能会通过阻塞线程影响访客的体验
  • 限制SQL请求的数量:避免在循环中运行请求
  • 在大型数据集上分页结果,这将限制每个请求的内存消耗和网络流量
  • 在写入文件时使用压缩:这将节省网络带宽,我们能够更快地导入您的源

内部,库使用XmlReader / XmlWriter来限制内存消耗。产品对象和生成的XML将在每次迭代后从内存中刷新。这保证了内存使用量不会随着要写入的产品数量而增加,而只会依赖于每个产品的“大小”。

执行测试命令

如果您只是想对库进行尝试,还没有自己的产品,可以使用以下命令生成“虚拟”产品,这样您就可以使用库进行操作,并了解其工作原理。

php tests/functional/<filename>.php <file> <number-of-products> <number-of-children-per-product>

# example:
php tests/functional/products-random.php feed.xml 1000 0