Magento е решение за електронна търговия, т.е. повече е ориентирано към продажба на продукти, отколкото на съпътстващ счетоводство за складове, логистика или финанси. За съпътстващите е по-подходящо да се използват други приложения (например, ERP системи). Затова често в практиката на използване на Magento възниква необходимост от интеграция на магазина с тези системи (например, с 1С).
В общи линии интеграцията може да се сведе до репликация на данни по:
- каталога (продукти, категории);
- инвентарни данни (остатъци на продукти в складовете и цени);
- клиенти;
- поръчки;
Magento предлага отделен клас обекти за манипулация с данни в базата — . Поради спецификата на Magento добавянето на данни в базата през репозитории е лесно за кодиране, но се случва, да речем, не много бързо. В тази публикация разглеждам основните етапи за софтуерно добавяне на продукт в Magento 2 по "класически" начин — с помощта на репо-класове.
Клиентите и поръчките обикновено се репликират в друга посока — от Magento към външните ERP системи. Затова с тях е по-лесно, от страна на Magento просто се избира съответните данни, а след това — "от наша страна куршумите излязоха«.
Принципи за запис на данни в базата
В момента създаването на обекти, които се запазват в базата, по програмния метод в Magento става чрез :
function __construct (MagentoCmsModelBlockFactory $blockFactory) {
$this->blockFactory = $blockFactory;
}
/** @var MagentoCmsModelBlock $block *///
$block = $this->blockFactory->create();а записът в базата — чрез :
function __construct (MagentoCmsApiBlockRepositoryInterface $blockRepo) {
$this->blockRepo = $blockRepo;
}
$this->blockRepo->save($block);Подходът с използване на "Factory" и "Repository" може да се използва за всички основни модели в предметната област на Magento 2.
Основна информация за продукта
Разглеждам структурата на данните, съответстваща на версия Magento 2.3. Най-основната информация за продукта се намира в таблицата catalog_product_entity (регистър на продуктите):
entity_id
attribute_set_id
type_id
sku
has_options
required_options
created_at
updated_atОграничавам се до един тип продукт (type_id='simple'), набор от атрибути по подразбиране (attribute_set_id=4) и игнорирам атрибутите has_options и required_options. Понеже атрибутите entity_id, created_at и updated_at се генерират автоматично, то по същество, за да добавим нов продукт, е достатъчно да зададем sku. Правя това:
/** @var MagentoCatalogApiDataProductInterfaceFactory $factProd */
/** @var MagentoCatalogApiProductRepositoryInterface $repoProd */
/** @var MagentoCatalogApiDataProductInterface $prod */
$prod = $factProd->create();
$prod->setAttributeSetId(4);
$prod->setTypeId('simple');
$prod->setSku($sku);
$repoProd->save($prod);и получавам изключение:
Стойността на атрибута "Име на продукта" е празна. Задайте атрибута и опитайте отново.Добавям името на продукта в заявката и получавам съобщение, че липсва атрибут Цена. След добавяне на цената продуктът се записва в базата данни:
$prod = $factProd->create();
$prod->setAttributeSetId(4);
$prod->setTypeId('simple');
$prod->setSku($sku);
$prod->setName($name);
$prod->setPrice($price);
$repoProd->save($prod);Името на продукта се запазва в таблицата с varchar-атрибутите на продукта (catalog_product_entity_varchar), цената — в таблицата catalog_product_entity_decimal. Преди да добавите продукта, е желателно изрично да посочите, че използвате административната витрина за импортиране на данни:
/** @var MagentoStoreModelStoreManagerInterface $manStore */
$manStore->setCurrentStore(0);Допълнителни атрибути
Обработката на допълнителни атрибути на продуктите чрез Magento е истинско удоволствие. EAV моделът на данните за основните единици (вж. таблицата eav_entity_type) е една от ключовите характеристики на тази платформа. Просто добавяме съответните атрибути към модела на продукта:
$prodEntity->setData('description', $desc);
$prodEntity->setData('short_description', $desc_short);
// или
$prodEntity->setDescription($desc);
$prodEntity->setShortDescription($desc_short);и при запазване на модела чрез репо-обекта:
$repoProd->save($prod);допълнителните атрибути ще бъдат също запазени в съответните таблици на БД.
Инвентарни данни
Просто казано — количеството на продукта на склада. В Magento 2.3 структурите в БД, описващи формата на съхранение на инвентарни данни, от предишните версии. Въпреки това, добавянето на количеството на продукта на склада чрез модела на продукта не е значително по-сложно от добавянето на други атрибути:
/** @var MagentoCatalogModelProduct $prodEntity */
/** @var MagentoCatalogApiProductRepositoryInterface $repoProd */
$inventory = [
'is_in_stock' => true,
'qty' => 1234
];
$prodEntity->setData('quantity_and_stock_status', $inventory);
$repoProd->save($prodEntity);Медиа
Обикновено медийната поддръжка на продукта за клиента в магазина (e-commerce) е различна от медийната поддръжка на същия продукт за служителя във вътрешната система за отчитане (ERP). В първия случай е желателно да покажете "продукта открито", докато във втория — е достатъчно да предоставите обща представа за продукта. Въпреки това, прехвърлянето на поне основното изображение на продукта е доста разпространено случай при импортиране на данни.
При добавяне на изображение през админ панела, картинката първо се записва в времевия каталог (./pub/media/tmp/catalog/product) и само при запазване на продукта се премества в медийната директория (./pub/media/catalog/product). Освен това, при добавянето през админ панела, на изображението се задават тагове изображение, small_image, thumbnail, swatch_image.
/** @var MagentoCatalogApiProductRepositoryInterface $repoProd */
/** @var MagentoCatalogModelProductGalleryCreateHandler $hndlGalleryCreate */
/* $imagePath = '/path/to/file.png'; $imagePathRelative = '/f/i/file.png' */
$imagePathRelative = $this->imagePlaceToTmpMedia($imagePath);
/* reload product with gallery data */
$product = $repoProd->get($sku);
/* add image to product's gallery */
$gallery['images'][] = [
'file' => $imagePathRelative,
'media_type' => 'image'
'label' => ''
];
$product->setData('media_gallery', $gallery);
/* set usage areas */
$product->setData('image', $imagePathRelative);
$product->setData('small_image', $imagePathRelative);
$product->setData('thumbnail', $imagePathRelative);
$product->setData('swatch_image', $imagePathRelative);
/* create product's gallery */
$hndlGalleryCreate->execute($product);Защо медията се свързва само след предварително запазване на продукта и неговото извлечение от репозитория отново? И трябва да се посочи атрибутът label при добавяне на запис в медийната галерия на продукта (в противен случай получаваме изключение Неопределен индекс: label в .../module-catalog/Model/Product/Gallery/CreateHandler.php на ред 516).
Категории
Често структурата на категориите в магазина и backend приложението или разположението на продуктите в тях може значително да се различава. Стратегиите за пренос на данни за категориите и продуктите в тях зависят от множество фактори. В този пример се ръководя от следното:
- категориите на backend и магазина се сопоставят по име;
- ако се импортира категория, която няма в магазина, тя се създава под коренова категория (
Основна категория) и нейното по-нататъшно позициониране в каталога на магазина се предвижда ръчно; - привързването на продукта към категорията става само при неговото създаване в магазина (първия импорт);
Основната информация за категорията се намира в таблицата catalog_category_entity (каталог на категориите). Създаването на категория в Magento:
/** @var MagentoCatalogApiDataCategoryInterfaceFactory $factCat */
/** @var MagentoCatalogApiCategoryRepositoryInterface $repoCat */
$cat = $factCat->create();
$cat->setName($name);
$cat->setIsActive(true);
$repoCat->save($cat);Привързването на продукт към категория става по ID на категорията и SKU на продукта:
/** @var MagentoCatalogModelCategoryProductLinkFactory $factCatProdLink */
/** @var MagentoCatalogApiCategoryLinkRepositoryInterface $repoCatLink */
$link = $factCatProdLink->create();
$link->setCategoryId($catMageId);
$link->setSku($prodSku);
$repoCatLink->save($link);Итого
Да напиша код за добавяне на продукт в Magento 2 по програмен път не е много сложно. Всичко изложено по-горе обобщих в демо модул ««. В модула има само една конзолна команда fl32:import:prod, която импортира продукти, описани в JSON файл ««:
[
{
"sku": "...",
"name": "...",
"desc": "...",
"desc_short": "...",
"price": ...,
"qty": ...,
"categories": ["..."],
"image_path": "..."
}
]Снимките за импорт се намират в каталога ./etc/data/img.
Времето за импорт на 10 продукта по този начин е около 10 секунди на моя лаптоп. Ако развия тази идея по-надалеч, не е трудно да се стигне до извода, че за един час могат да се импортират около 3600 продукта, а за импорта на 100К продукта може да са необходими около 30 часа. Заменянето на лаптопа със сървър позволява да се смекчи ситуацията. Може би дори в пъти. Но не в порядъци. Вероятно тази скорост на бавност в известна степен е една от причините за появата на проекта .
Радикалното решение за увеличаване скоростта на импорта може да бъде директна запис в базата, но в този случай губим всичките „плюшки“, свързани с разширяемостта на Magento — ще се наложи всичко „разширено“ да го направим сами. Въпреки това, то си струва. Ако успея, ще разгледам подхода с директна запис в БД в следващата статия.
Източник: habr.com
