ittweb/accelasearch-product-mapper

允许轻松集成AccelaSearch的产品管理。

v3.22 2021-08-30 14:59 UTC

This package is auto-updated.

Last update: 2024-09-29 05:22:21 UTC


README

PHP产品数据映射器,用于轻松集成AccelaSearch。

概述

AccelaSearch部署了一个中间SQL类似数据库,称为collector,用于存储产品信息,然后用于配置和填充搜索引擎和结果。必须以适当的格式存储项目信息(有关详细信息,请参阅AccelaSearch - 自定义集成文档)。AccelaSearch - 产品映射器是一个PHP库,它公开了一个抽象数据类型(ADT),用于表示AccelaSearch支持的所有不同类型的产品,以及一组方便的数据映射器,用于将数据从/到不同格式转换,包括JSON、PHP字典和中间SQL格式。

AccelaSearch - 产品映射器允许以抽象、语法友好方式定义产品数据,并从/向收集器数据库发送/检索信息,以简化与第三方系统或CMS的集成,而无需了解底层收集器数据库模式。请注意,然而,产品映射器将操作整个、原子实体上的产品,并且不会意识到CMS指定的行为,这些行为可能会加快同步过程(请参阅限制部分以获取示例)。

要求

AccelaSearch - 产品映射器是自包含的,它需要一个最新的PHP版本来运行。

提供的单元测试可以使用PHPUnit 运行,并且可以使用PHPDocmentor 生成代码文档。

安装

建议通过Composer 进行安装

composer require ittweb/accelasearch-product-mapper

可以通过克隆或下载此存储库手动安装

git clone https://github.com/ittweb/accelasearch-product-mapper.git
wget https://github.com/ittweb/accelasearch-product-mapper/archive/master.zip

概述

在注册AccelaSearch后,系统将发布一个API密钥,例如my-api-key,应保密并安全存储。API密钥可以用于实例化一个DataMapper\Api\Client对象,该对象允许检索有关支持的CMS和收集器的信息。前者应用于创建一个Shop实例,而后者应用于建立与收集器的SQL连接,该连接可用于存储有关商店和产品的信息。为了方便这些操作,AccelaSearch - 产品映射器提供了一些实用工具和外观,这些工具和外观是交互与收集器的首选方式。

检索信息

基本信息,例如支持的CMS列表和收集器凭据,可以通过使用DataMapper\Api\Client以及相关数据映射器通过AccelaSearch的API系统访问。

use \AccelaSearch\ProductMapper\DataMapper\Api\Client;
use \AccelaSearch\ProductMapper\DataMapper\Api\Cms as CmsMapper;
use \AccelaSearch\ProductMapper\DataMapper\Api\Collector as CollectorMapper;

$client = Client::fromApiKey("my-api-key");
$cms_mapper = new CmsMapper($client);
$collector_mapper = new CollectorMapper($client);

$cms_list = $cms_mapper->search();
$collector = $collector_mapper->read();

连接到收集器

一旦获得收集器对象(这很可能是通过DataMapper\Api\Collector完成的),就可以使用它来建立与收集器数据库的连接

use \PDO;

$dbh = new PDO(
    'mysql:host=' . $collector->getHostName() . ';dbname=' . $collector->getDatabaseName(),
    $collector->getUsername(),
    $collector->getPassword(),
    [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
    ]
);

管理商店

可以使用SQL连接实例化一个商店数据映射器,该映射器可以进一步用于将Shop实例插入到收集器中

use \AccelaSearch\ProductMapper\Shop;
use \AccelaSearch\ProductMapper\DataMapper\Sql\Shop as ShopMapper;

// $cms_list = ...
// $dbh = ...
$shop_mapper = ShopMapper::fromConnection($dbh);
$shop = new Shop("http://www.shop.com", "en", $cms_list[0]);
$shop_mapper->create($shop);

插入时将创建一个唯一的商店标识符,并将其分配给$shop。此标识符可用于从数据库检索商店并更新其信息或软删除它

// Shop has identifier 2
$shop = $shop_mapper->read(2);
$shop->setUrl("http://www.new-url.com");
$shop_mapper->update($shop);

// Soft-deletion
$shop->setIsActive(false);
$shop_mapper->update($shop);

注意:不应手动硬删除商店,AccelaSearch将定期扫描收集器并采取适当措施,最终删除软删除的商店。

管理项目

处理项目数据的首选方式是通过 CollectorFacade,它可以自动处理 SQL 事务和回滚、关系特征的插入以及隐式处理插入与更新。CollectorFacade 需要一个 DataMapper\API\Client 实例和操作的商店标识符,它将自动检索所有必要的连接信息。

use \AccelaSearch\ProductMapper\DataMapper\Api\Client;
use \AccelaSearch\ProductMapper\CollectorFacade;

$client = Client::fromApiKey("my-api-key");
$collector = new CollectorFacade($client, 2);

CollectorFacade 提供了四种与产品交互的方法:loadsearchByExternalIdentifiersavedelete。后者将执行软删除,而 save 将根据收集器中是否存在该项目执行插入或更新。

// Retrieves item with identifier 42
$item = $collector->load(42);

// Retrieves item having external identifier "ITM0001"
$item = $collector->searchByExternalIdentifier("ITM0001");

// Updates item information
$item->setUrl("http://new-shop-url.com/ITM0001");
$collector->save($item);

// Soft deletion
$collector->delete($item);

项目层级

AccelaSearch 支持九种不同类型的物品

  • 横幅:带有 URL 和图片的横幅(桌面和移动端不同)
  • 页面:通用的网页
  • 分类页面:分类或收集器的网页
  • 标准:标准产品
  • 虚拟:Simple 的子类型,通常意味着无需发货
  • 可下载:Virtual 的子类型,可以下载的项目
  • 可配置:存在一组变体项的产品,例如不同颜色或尺寸的衬衫;变体通常表示为 Simple 项,尽管可以使用任何类型的项
  • 捆绑:捆绑销售的项目
  • 分组:类似于捆绑,用于区分的 CMS,如 Magento

每种类型的物品在主 \AccelaSearch\ProductMapper 下都由同名的类表示。每个类都实现了 ItemInterface,而 SimpleVirtualDownloadableConfigurableBundleGrouped 也实现了 ProductInterface,它增加了关于外部标识符、属于零个或多个分类、图像信息、自定义属性以及关于可用性和定价的信息(通过扩展 StockableInterfaceSellableInterface)。

尽管可以通过构造函数创建项目,但实现了 ProductInterface 的产品可以通过 ProductFactory 实例化。

use \AccelaSearch\ProductMapper\ProductFactory;

$factory = new ProductFactory();
$simple = $factory->createSimple("http://myshop.com/SIMPLE0001", "SIMPLE0001");
$virtual = $factory->createVirtual("http://myshop.com/VIRTUAL0001", "VIRTUAL0001");
$downloadable = $factory->createDownloadable("http://myshop.com/DOWNLOADABLE0001", "DOWNLOADABLE0001");
$configurable = $factory->createConfigurable("http://myshop.com/CONF0001", "CONF0001");
$bundle = $factory->createBundle("http://myshop.com/BUNDLE0001", "BUNDLE0001");
$grouped = $factory->createVirtual("http://myshop.com/GROUP0001", "GROUP0001");

每个方法都以其创建的产品类型命名,并接受产品的 URL 及其外部标识符。每个产品都创建为带有空可用性、定价和图像信息,并且没有分类。

添加标准属性

每个物品都允许通过访问器设置 SKU 和 URL,而产品还允许设置外部标识符、分类、图像信息、库存可用性、定价和自定义属性。前者可以通过以下方式访问:

// $item = ...
$item->setSku("ITM-003");
$item->setUrl("http://www.myshop.com/catalogue/itm-003");
echo $item->getSku() . " " . $item->getUrl();

// $product = ...
$product->setExternalIdentifier("56");
echo $product->getExternalIdentifier();

以下部分将展示如何处理更复杂的标准信息。

添加分类

在分配给产品之前必须创建(或从收集器读取)分类

use \AccelaSearch\ProductMapper\Category;

$parent_category = new Category("cat-0001", "Fashion", null);
$category = new Category("cat-00075", "Woman", $parent_category);
$category->setUrl("http://www.myshop/categories/75");
$item->addCategory($category);
$item->removeCategory($category);

分类不由 CollectorFacade 显式处理,它在需要时会透明地插入或读取数据。相反,可以通过使用 Repository\Sql\Category 存储库或更低级别的数据映射器 DataMapper\Sql\Category 进行原始操作来持久化分类。

添加图像信息

关于产品图片的信息由 Image 类处理,该类允许为每个图像指定一个标签、一个 URL 和一个位置

use \AccelaSearch\ProductMapper\Image;

$image_1 = new Image("main", "http://www.myshop.com/storage/images/001.jpeg", 1);
$image_2 = new Image("over", "http://www.myshop.com/storage/images/002.jpeg", 3);

可以通过 addImage 方法将图像添加到项目中

use \AccelaSearch\ProductMapper\ProductFactory;

$factory = new ProductFactory();
$item = $factory->createSimple("http://myshop.com/SIMPLE0001", "SIMPLE0001");
$item->addImage($image_1)->addImage($image_2);

添加可用性

可用性始终与仓库相关,可能是有限的或无限的。在使用之前必须创建(或从收集器读取)仓库,可以是虚拟的或物理的(其中已知纬度和经度)。通过 ProductFactory 创建产品时,将自动创建一个空的 Stock\Availability,并且可以通过其访问器方法访问它

use \AccelaSearch\ProductMapper\Stock\Warehouse\Virtual as VirtualWarehouse;
use \AccelaSearch\ProductMapper\Stock\Warehouse\Physical as PhysicalWarehouse;
use \AccelaSearch\ProductMapper\Stock\Quantity\Limited as LimitedQuantity;
use \AccelaSearch\ProductMapper\Stock\Quantity\Unlimited as UnlimitedQuantity;

$generic_warehouse = new VirtualWarehouse("warehouse-001");
$brick_warehouse = new PhysicalWarehouse("warehouse-002", 45.0, 13.5);
$five_in_stock = new LimitedQuantity(5);
$unlimited = new UnlimitedQuantity();

// $item = ...
$item->getAvailability()->add(new Stock($generic_warehouse, $five_in_stock))
    ->add(new Stock($brick_warehouse, $unlimited));

仓库和数量的任何组合都是允许的,每个组合都由Stock\Stock类进行中介。

添加定价

价格信息始终与客户组相关联,以便为不同用户组提供不同的价格系统。此外,价格可能因购买数量而异(即多级定价),支持多种货币,并允许指定与列表价格不同的销售价格。在使用之前,必须创建(或从收集器读取)客户组,而层、货币以及销售和列表价格是Price\Price类的标准属性。通过ProductFactory创建产品时,将自动实例化一个空的Price\Pricing,应通过其访问器方法访问。

use \AccelaSearch\ProductMapper\Price\CustomerGroup;
use \AccelaSearch\ProductMapper\Price\Price;

$group_1 = new CustomerGroup("standard-group");
$group_2 = new CustomerGroup("webpos-group");

// $item = ...
// Item normally sold for 19.99 USD, now selling for 15.99, no tiers, only for standard-group
$item->getPricing()->add(new Price(19.99, 15.99, "USD", 0, $group_1));
// Same item normally sold for 16.43 EUR, now selling at 13.14 EUR
$item->getPricing()->add(new Price(19.99, 15.99, "USD", 0, $group_1));

// Item selling at 19.99 USD for quantities between 0 and 9, selling at 9.99 if 100 or more units are bought
$item->getPricing()->add(new Price(19.99, 19.99, "USD", 0, $group_1))
    ->add(new Price(9.99, 9.99, "USD", 100, $group_1));

// Same item, but different prices for different customer group, second group gets a discount
$item->getPricing()->add(new Price(19.99, 19.99, "USD", 0, $group_1))
    ->add(new Price(25.99, 21.50, "USD", 0, $group_1));

相同的货币、最小数量和组组合不能插入多次,否则会发生未定义的行为。

添加自定义属性

除了明确处理的属性(URL、sku、价格、可用性等)之外,还可以插入自定义属性。每个自定义属性都有一个名称和一系列值,即每个属性都被视为多值。单值必须以多值属性的形式插入,并且只有一个值。应在将属性分配给产品之前创建属性。

use \AccelaSearch\ProductMapper\Attribute;

$name = new Attribute("name");
$name->addValue("T-Shirt");

$tags = new Attribute("tag");
$tags->addValue("fashion")->addValue("summer")->addValue("light");

// $item = ...
$item->addAttribute($name)
    ->addAttribute($tags);

一旦为产品定义了属性,就可以通过其名称(和可能修改其值列表)检索它。

$item->getAttribute("tag")->removeValue("light")->addValue("men");

属性名称应该是英文单词,全部小写,单数形式(当适用时),并且不得包含空格。我们建议使用连字符或下划线代替空格。

对于单值属性,有一个简写形式的工厂方法。

$item->addAttribute(Attribute::fromNameAndValue("name", "T-Shirt"));

对于属于可配置产品的产品,影响配置的属性必须通过将isConfigurable设置为true来标记为可配置

$color = new Attribute("color");
$color->addValue("red");
$color->setIsConfigurable(true);

// $configurable_item = ...
// $actual_item = ...
$actual_item->addAttribute($color);

这也有简写形式。

$actual_item->addAttribute(Attribute::fromNameAndValue("color", "red")->setIsConfigurable(true));

可配置产品

可配置产品是元产品,逻辑上将一组实际(通常是Simple)产品组合在一起,这些产品之间在细节上有所不同,例如颜色或尺寸。在处理可配置产品时,必须创建并分配一组子产品给父可配置产品。子产品的某些属性应标记为可配置,以便告诉AccelaSearch哪些属性构成配置,哪些属性不构成(如前所述)。

use \AccelaSearch\ProductMapper\ProductFactory;
use \AccelaSearch\ProductMapper\Attribute;

$factory = new ProductFactory();
$shirt = $factory->createConfigurable("http://www.myshop.com/shirt", "ID:42");
$shirt->setSku("CONF-001");

$blue_shirt = $factory->createSimple("http://www.myshop.com/shirt/blue", "ID:44");
$blue_shirt->setSku("CONF-001-b");
$blue_shirt->addAttribute(Attribute::fromNameAndValue("color", "blue")->setIsConfigurable(true));
$blue_shirt->addAttribute(Attribute::fromNameAndValue("name", "blue shirt"));

$red_shirt = $factory->createSimple("http://www.myshop.com/shirt/red", "ID:45");
$red_shirt->setSku("CONF-001-r");
$red_shirt->addAttribute(Attribute::fromNameAndValue("color", "red")->setIsConfigurable(true));
$red_shirt->addAttribute(Attribute::fromNameAndValue("name", "red shirt"));

$shirt->addVariant($red_shirt)->addVariant($blue_shirt);

尽管示例中没有显示,但建议为父产品和子产品设置定价、可用性和分类信息,因为前者不会从后者继承它们,反之亦然。

捆绑和分组产品

捆绑和分组是将一组实际(通常是Simple)产品组合在一起进行销售的产品。在处理捆绑或分组产品时,必须创建并分配一组子产品给父产品。产品可以作为同一父产品的子产品出现多次,例如,当一组两个相同的产品一起销售时。

use \AccelaSearch\ProductMapper\ProductFactory;
use \AccelaSearch\ProductMapper\Attribute;

$factory = new ProductFactory();
$group = $factory->createGrouped("http://www.myshop.com/group", "ID:48");
$group->setSku("GRP-009");

$bottle = $factory->createSimple("http://www.myshop.com/bottle", "ID:94");
$bottle->setSku("BTL-001");

$paper = $factory->createSimple("http://www.myshop.com/paper", "ID:105");
$bottle->setSku("PPR-001");

// Two bottles and one piece of paper
$group->addProduct($bottle)->addProduct($bottle)->addProduct($paper);

尽管示例中没有显示,但建议为父产品和子产品设置定价、可用性和分类信息,因为前者不会从后者继承它们,反之亦然。