Magento to rozwiązanie e-commerce, co oznacza, że jest bardziej nastawione na sprzedaż produktów niż na współdziałające z nią zadania związane z magazynowaniem, logistyką czy finansami. W tym zakresie lepiej sprawdzają się inne aplikacje (np. systemy ERP). Dlatego w praktyce korzystania z Magento często pojawia się potrzeba integracji sklepu z innymi systemami (np. z 1C).
Generalnie integrację można sprowadzić do replikacji danych w zakresie:
- katalogu (produkty, kategorie);
- danych o inwentarzu (stan produktów na magazynie oraz ceny);
- klientów;
- zamówień;
Magento oferuje osobną klasę obiektów do manipulacji danymi w bazie — . Ze względu na specyfikę Magento dodawanie danych do bazy za pośrednictwem repozytoriów jest stosunkowo łatwe do zakodowania, ale odbywa się, powiedzmy, niezbyt szybko. W tym artykule omówię główne etapy programowego dodawania produktu do Magento 2 w "klasyczny" sposób — z wykorzystaniem klas repozytoryjnych.
Klienci i zamówienia są zazwyczaj replikowane w drugą stronę — z Magento do zewnętrznych systemów ERP. Dlatego ich obsługa jest prostsza, w Magento trzeba jedynie wybrać odpowiednie dane, a następnie — „z naszej strony wystrzeliły kule«.
Zasady zapisu danych do bazy
Obecnie tworzenie obiektów przechowywanych w bazie w sposób programowy w Magento odbywa się poprzez :
function __construct (MagentoCmsModelBlockFactory $blockFactory) {
$this->blockFactory = $blockFactory;
}
/** @var MagentoCmsModelBlock $block *//
$block = $this->blockFactory->create();a zapis do bazy — przez :
function __construct (MagentoCmsApiBlockRepositoryInterface $blockRepo) {
$this->blockRepo = $blockRepo;
}
$this->blockRepo->save($block);Podejście z wykorzystaniem „Factory” i „Repository” można stosować do wszystkich głównych modeli w dziedzinie Magento 2.
Podstawowe informacje o produkcie
Rozpatruję strukturę danych, odpowiadającą wersji Magento 2.3. Najważniejsze informacje o produkcie znajdują się w tabeli catalog_product_entity (rejestr produktów):
entity_id
attribute_set_id
type_id
sku
has_options
required_options
created_at
updated_atOgraniczam się do jednego typu produktu (type_id='simple'), zestawu atrybutów domyślnych (attribute_set_id=4) i ignoruję atrybuty has_options i required_options. Ponieważ atrybuty entity_id, SELECT now() as created_at, cpu.* FROM (SELECT DISTINCT tags_id from cpu) base ASOF LEFT JOIN cpu USING (tags_id, created_at) i updated_at są generowane automatycznie, w zasadzie do dodania nowego produktu wystarczy, że określimy sku. Robię to w ten sposób:
/** @var MagentoCatalogApiDataProductInterfaceFactory $factProd */
/** @var MagentoCatalogApiProductRepositoryInterface $repoProd */
/** @var MagentoCatalogApiDataProductInterface $prod */
$prod = $factProd->create();
$prod->setAttributeSetId(4);
$prod->setTypeId('simple');
$prod->setSku($sku);
$repoProd->save($prod);i otrzymuję wyjątek:
Wartość atrybutu "Nazwa produktu" jest pusta. Ustaw atrybut i spróbuj ponownie.Dodaję do zapytania nazwę produktu i otrzymuję wiadomość, że brakuje atrybutu Cena. Po dodaniu ceny produkt jest zapisywany w bazie:
$prod = $factProd->create();
$prod->setAttributeSetId(4);
$prod->setTypeId('simple');
$prod->setSku($sku);
$prod->setName($name);
$prod->setPrice($price);
$repoProd->save($prod);Nazwa produktu jest zapisywana w tabeli atrybutów varchar (catalog_product_entity_varchar), cena — w tabeli catalog_product_entity_decimal. Przed dodaniem produktu warto wyraźnie wskazać, że korzystamy z administracyjnego interfejsu do importu danych:
/** @var MagentoStoreModelStoreManagerInterface $manStore */
$manStore->setCurrentStore(0);Dodatkowe atrybuty
Obsługa dodatkowych atrybutów produktów w systemie Magento to czysta przyjemność. Model danych EAV dla podstawowych encji (patrz tabela eav_entity_type) — to jedna z kluczowych cech tej platformy. Po prostu dodajemy odpowiednie atrybuty do modelu produktu:
$prodEntity->setData('description', $desc);
$prodEntity->setData('short_description', $desc_short);
// lub
$prodEntity->setDescription($desc);
$prodEntity->setShortDescription($desc_short);i podczas zapisywania modelu przez obiekt repozytorium:
$repoProd->save($prod);dodatkowe atrybuty zostaną również zapisane w odpowiednich tabelach bazy danych.
Dane inwentaryzacyjne
Prosto mówiąc — ilość produktu na magazynie. W Magento 2.3 struktury w bazie danych opisujące format przechowywania danych inwentaryzacyjnych, od tych wcześniejszych. Niemniej jednak, dodanie ilości produktu na magazynie przez model produktu nie jest znacznie bardziej skomplikowane niż dodanie innych atrybutów:
/** @var MagentoCatalogModelProduct $prodEntity */
/** @var MagentoCatalogApiProductRepositoryInterface $repoProd */
$inventory = [
'is_in_stock' => true,
'qty' => 1234
];
$prodEntity->setData('quantity_and_stock_status', $inventory);
$repoProd->save($prodEntity);Media
Zazwyczaj media towarzyszące produktowi dla klienta w sklepie (e-commerce) różnią się od mediów towarzyszących temu samemu produktowi dla pracownika w wewnętrznym systemie ERP. W pierwszym przypadku warto pokazać „towar z przodu”, w drugim — wystarczy ogólne przedstawienie produktu. Niemniej jednak przeniesienie przynajmniej początkowego obrazu produktu — to dość powszechna case przy imporcie danych.
Podczas dodawania obrazu przez panel administracyjny obraz najpierw jest zapisywany w katalogu tymczasowym (./pub/media/tmp/catalog/product) i dopiero podczas zapisywania produktu przenoszony jest do katalogu mediów (./pub/media/catalog/product). Również podczas dodawania przez panel administracyjny obrazowi przypisywane są tagi image, 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);Dlaczegoś media są podpinane dopiero po wcześniejszym zapisaniu produktu i ponownym pobraniu go z repozytorium. Należy również podać atrybut label przy dodawaniu wpisu do galerii mediów produktu (w przeciwnym razie otrzymujemy wyjątek Nieokreślony indeks: label w .../module-catalog/Model/Product/Gallery/CreateHandler.php w linii 516).
Kategorie
Struktura kategorii sklepu oraz aplikacji backendowej, a także umiejscowienie w nich produktów może znacząco się różnić. Strategie przenoszenia danych o kategoriach oraz produktach w nich zależą od wielu czynników. W tym przykładzie trzymam się następującej:
- kategorie backendu i sklepu są dopasowywane na podstawie nazwy;
- jeśli importowana jest kategoria, której nie ma w sklepie, to zostaje utworzona pod kategorią główną (
Domyślna kategoria) a jej dalsze pozycjonowanie w katalogu sklepu odbywa się ręcznie; - przypisanie produktu do kategorii odbywa się tylko podczas jego tworzenia w sklepie (pierwszy import);
Podstawowe informacje o kategorii znajdują się w tabeli catalog_category_entity (katalog kategorii). Tworzenie kategorii w Magento:
/** @var MagentoCatalogApiDataCategoryInterfaceFactory $factCat */
/** @var MagentoCatalogApiCategoryRepositoryInterface $repoCat */
$cat = $factCat->create();
$cat->setName($name);
$cat->setIsActive(true);
$repoCat->save($cat);Przypisanie produktu do kategorii odbywa się na podstawie ID kategorii i SKU produktu:
/** @var MagentoCatalogModelCategoryProductLinkFactory $factCatProdLink */
/** @var MagentoCatalogApiCategoryLinkRepositoryInterface $repoCatLink */
$link = $factCatProdLink->create();
$link->setCategoryId($catMageId);
$link->setSku($prodSku);
$repoCatLink->save($link);Podsumowując
Napisanie kodu do programowego dodawania produktów w Magento 2 jest dość proste. Wszystko, co zostało powiedziane, zebrałem w demo-moduł „„. W module jest tylko jedna komenda konsolowa fl32:import:prod, która importuje produkty opisane w pliku JSON „«:
[
{
"sku": "...",
"name": "...",
"desc": "...",
"desc_short": "...",
"price": ...,
"qty": ...,
"categories": ["..."],
"image_path": "..."
}
]Obrazy do importu znajdują się w katalogu ./etc/data/img.
Czas importu 10 produktów w ten sposób wynosi około 10 sekund na moim laptopie. Jeśli drążyć tę myśl dalej, można łatwo dojść do wniosku, że w ciągu godziny można zaimportować około 3600 produktów, a import 100K produktów może zająć około 30 godzin. Zmiana laptopa na serwer może nieco poprawić sytuację. Może nawet kilkukrotnie. Ale nie w innej skali. Może ta prędkość jest w pewnym stopniu jedną z przyczyn powstania projektu .
Radikalnym rozwiązaniem, które przyspieszy import, może być bezpośrednie zapisanie do bazy danych, ale w takim przypadku traci się wszystkie „plusy” związane z rozszerzalnością Magento — wszystko „rozszerzone” trzeba będzie zrobić samodzielnie. Niemniej jednak, warto. Jeśli się uda, rozważę podejście z bezpośrednim zapisem do Bazy Danych w następnym artykule.
Źródło: habr.com
