Neuen Adapter aufbauen
Aufbau Adapter
info
Neue Adapter müssen von der folgenden abstrakten Klasse erben: Twocream\ShopwareConnectorBundle\Transformer\Adapter\ArrayAdapter\ArrayAdapterAbstract
<?php
use Twocream\ShopwareConnectorBundle\Transformer\Adapter\ArrayAdapter\ArrayAdapterAbstract;
class ExampleAdapter extends ArrayAdapterAbstract
{
public static function getPackageName(): string
{
return 'example';
}
public function getTargetClassName(): string
{
return 'ExampleClassName';
}
protected function prepare($object): array
{
return [
'id' => $object->getId(),
'uuid' => md5($object->getId()),
'active-websites' => $object->getActiveWebsites(),
'texts' => $this->translationHelper()->mapTranslations(
$object->getLocalizedfields(),
['downloadTitle', 'downloadDescription'],
[
'downloadTitle' => 'title',
'downloadDescription' => 'description'
]
),
'custom-fields' => [
'position' => $object->getPosition(),
]
];
}
}
Erklärung verschiedener Methoden
| Name | Beschreibung |
|---|---|
getPackageName(): string | Eindeutiger Package-Name, z.B. "product" |
getTargetClassName(): string | Zugehöriger Objekt-Klassenname z.B. "Product" |
prepare($object): array | Hier erfolgt die inhaltsbezogene Aufbereitung der Daten, die für den Export vorgesehen sind |
| Optional | |
initialize(): void | Führt vorbereitende Prozesse aus, z. B. Ermittlung von Produktpositionen |
getDependentAdapters(): array | Definiert die Verarbeitungsreihenfolge der abhängigen Adapter, siehe "Abhängigkeiten zwischen Export-Adaptern" |
getThumbnailMapping(): array | Definiert adapterrelevante Thumbnails, die bei der Bildübertragung berücksichtigt werden |
Beispiel: Umfangreichere Umsetzung
<?php
namespace App\Components\ShopwareConnector\Adapter\Product;
use Carbon\Carbon;
use Pimcore\Db;
use Pimcore\Model\DataObject\ExampleProduct;
use Pimcore\Model\DataObject;
use Pimcore\Tool;
use Twocream\ProductAttributeBundle\Components\Export\Service\ProductAttributeService;
use Twocream\ShopwareConnectorBundle\Service\AdapterConfigurationService;
use Twocream\ShopwareConnectorBundle\Service\ExportTargetService;
use Twocream\ShopwareConnectorBundle\Service\TranslationService;
use Twocream\ShopwareConnectorBundle\Transformer\Adapter\ArrayAdapter\ArrayAdapterAbstract;
use Twocream\ShopwareConnectorBundle\Transformer\Adapter\ArrayAdapter\ConditionManager;
use Pimcore\Model\DataObject\ExampleProductAttributeValue;
use App\Service\ExampleProductDataService;
class ProductAdapter extends ArrayAdapterAbstract
{
private ProductAttributeService $productAttributeService;
private ExampleProductDataService $productDataService;
private array $productSorting = [];
private const PRODUCT_IMAGE_THUMBNAILS = ['shopware_65x65', 'shopware_430x430', 'shopware_804x804', 'shopware_1000x1000',];
public function __construct(
TranslationService $translationService,
ExportTargetService $exportTargetService,
AdapterConfigurationService $adapterConfigurationService,
ConditionManager $manager,
ProductAttributeService $productAttributeService,
ExampleProductDataService $productDataService
) {
$this->productAttributeService = $productAttributeService;
$this->productDataService = $productDataService;
parent::__construct(
$translationService,
$exportTargetService,
$adapterConfigurationService,
$manager
);
}
protected function initialize(): void
{
$this->productSorting = Db::getConnection()->fetchFirstColumn(
'SELECT `id` FROM `objects` WHERE `className` = "ExampleProduct" ORDER BY CONCAT(`path`, `key`) ASC'
);
parent::initialize();
}
public static function getPackageName(): string
{
return 'products';
}
public function getTargetClassName(): string
{
return 'ExampleProduct';
}
public function getDependentAdapters(): array
{
return [
ProductAttributeAdapter::getPackageName(),
ProductAttributeValueAdapter::getPackageName(),
self::getPackageName(),
ProductCategoryAssignmentAdapter::getPackageName()
];
}
protected function prepare($object): array
{
if ($object->getHierarchyType() !== 'product') return [];
if (!in_array($object->getId(), array_values($this->productSorting))) return [];
$productData = $this->getProductData($object);
if (empty($productData)) return [];
$productData['variants'] = $this->getVariants($object);
return $productData;
}
// Produktvarianten sammeln
private function getVariants(ExampleProduct $product): array
{
$children = $product->getChildren();
$variants = [];
foreach ($children as $child) {
if (!$child instanceof ExampleProduct) {
continue;
}
$variants[] = $this->getProductData($child, true);
}
return $variants;
}
// Funktion zum Sammeln diverser Produktdaten
private function getProductData(ExampleProduct $product, bool $isVariant = false): array
{
$texts = [];
$beforeInheritedValues = DataObject\AbstractObject::getGetInheritedValues();
\Pimcore\Model\DataObject\AbstractObject::setGetInheritedValues(true);
if (!empty($product->getProductTypeDesc())) {
$texts = $this->translationHelper()->mapTranslations(
$product->getProductTypeDesc()->getLocalizedfields(),
['description']
);
}
$articleNames = [];
$articleNames = $this->translationHelper()->mapTranslations(
$product->getLocalizedfields(),
['websiteArticleName', 'articleNameSeo', 'metaDescription', 'instructionsForUse'],
[
'websiteArticleName' => 'name',
'articleNameSeo' => 'meta-title',
'metaDescription' => 'meta-description',
'instructionsForUse' => 'instructions-for-use'
]
);
$activeLanguages = [];
foreach (Tool::getValidLanguages() as $language) {
$shopwareLanguage = $this->translationHelper()->getShopwareExportLanguage($language);
$activeLanguages[
strtoupper(
($position = strrpos($shopwareLanguage, '_')) === false
? $shopwareLanguage
: substr($shopwareLanguage, $position + 1)
)
]['website'] = (int) $product->getWebsite($language);
}
foreach ($articleNames as $language => $articleName) {
$languagePimcore = $this->translationHelper()->getPimcoreLanguage($language);
if (empty($articleName['name'])) {
$fallbackName = $product->getArticleName($languagePimcore);
if (empty($fallbackName)) $fallbackName = $product->getArticleNumber();
$articleNames[$language]['name'] = $fallbackName;
}
}
if (!empty($texts) && !empty($articleNames)) {
foreach ($texts as $language => $text) {
if (key_exists($language, $articleNames) && key_exists($language, $texts)) {
$texts[$language] = array_merge($text, $articleNames[$language]);
}
}
} elseif (empty($texts)) {
$texts = $articleNames;
}
$objectMetadataLocations = $product->getLocation();
$visibilitiesSalesChannel = [];
// Sales-Channel Sichtbarkeit setzen
foreach ($objectMetadataLocations as $objectMetadataLocation) {
if (!empty($objectMetadataLocation->getLocation())) {
continue;
}
$locationObject = $objectMetadataLocation->getObject();
$locationExportCountries = $locationObject->getLocationExportCountry();
foreach ($locationExportCountries ?? [] as $locationExportCountry) {
$visibilitiesSalesChannel[$locationExportCountry] = true;
}
}
$minPurchase = '';
if (!empty($product->getOrderAmountMin()) && !empty($product->getOrderAmountMin()->getValue())) {
$minPurchase = $product->getOrderAmountMin()->getValue();
}
$purchaseUnit = '';
$purchaseUnitValue = 1;
if (
!empty($product->getWorkListPriceBase())
&& !empty($product->getWorkListPriceBase()->getUnit())
) {
$purchaseUnit = $product->getWorkListPriceBase()->getUnit()->getAbbreviation();
if (!empty($product->getWorkListPriceBase()->getValue())) {
$purchaseUnitValue = $product->getWorkListPriceBase()->getValue();
}
}
$priceGross = 99999.0;
$priceNet = 99999.0;
$position = 999999;
if (in_array($product->getId(), array_values($this->productSorting))) {
foreach ($this->productSorting as $index => $productId) {
if ($productId === $product->getId()) {
$position = $index;
break;
}
}
} elseif ($isVariant && in_array($product->getParentId(), array_values($this->productSorting))) {
foreach ($this->productSorting as $index => $productId) {
if ($productId === $product->getParentId()) {
$position = $index;
break;
}
}
}
$weight = 0;
$width = 0;
$length = 0;
$height = 0;
if (!empty($product?->getNetWeight()?->getValue())) $weight = $product->getNetWeight()->getValue();
if (!empty($product->getDimensionsClassificationStore())) {
list($width, $length, $height) = $this->productDataService->prepareClassificationStoreDimensions($product->getDimensionsClassificationStore());
}
$manufacturer = [];
if (!empty($product->getProductGroup())) {
$manufacturer = $this->productDataService->getManufaturerInfo($product->getProductGroup());
}
$productTypeTranslations = [];
\Pimcore\Model\DataObject\AbstractObject::setGetInheritedValues(true);
$exampleProductType = $product->getProductType();
if (!empty($exampleProductType)) {
$productTypeTranslations = $this->translationHelper()->mapTranslations(
$exampleProductType->getLocalizedfields(),
['productType']
);
}
$typeSeriesMedia = $product->getTypeSeriesMedia();
$typeSeriesCertificates = $product->getTypeSeriesCertificates();
$fieldsOfApplicationValues = [];
foreach (Tool::getValidLanguages() as $language) {
$fieldsOfApplicationValues[$language] = [
'fieldsOfApplicationData' => $this->productDataService->getFieldsOfApplicationValues(
$typeSeriesMedia,
$typeSeriesCertificates,
$product,
$language
)
];
}
\Pimcore\Model\DataObject\AbstractObject::setGetInheritedValues($beforeInheritedValues);
$productData = [
'id' => $product->getId(),
'uuid' => md5($product->getId()),
'product-number' => $product->getArticleNumber(),
'tax' => 19,
'price' => ['gross' => $priceGross, 'net' => $priceNet,],
'manufacturer' => !empty($manufacturer) ? $manufacturer : 'Example',
'release-date' => Carbon::createFromTimestamp($product->getCreationDate())->toIso8601String(),
'mark-as-topseller' => false,
'active' => $product->getWebsite() == 'Ja',
'ean' => $product->getGtin() ?? '',
'width' => $width,
'length' => $length,
'height' => $height,
'weight' => $weight,
'shipping-free' => false,
'purchase-unit' => $purchaseUnitValue,
'min-purchase' => ((int) $minPurchase <= 0) ? 1 : (int) $minPurchase,
'unit' => $purchaseUnit,
'translations' => $texts ?? [],
'properties' => $this->productAttributeService->getArticleAssignmentByProductId(
new ExampleProductAttributeValue\Listing(),
$product->getId()
),
'visibilities' => $visibilitiesSalesChannel ?? [],
'activeLanguages' => $activeLanguages,
'custom-fields' => [
'twocream-product-connector-position' => $position,
'twocream-product-connector-media' => $this->getImageThumbnails($product),
'twocream-product-connector-downloads' => $this->productDataService->getDownloads($product),
'twocream-product-connector-icons' => $this->productDataService->getIcons($product),
'twocream-product-connector-sets' => $this->productDataService->getSets($product),
'twocream-product-connector-videos' => $this->productDataService->getVideos($product),
'twocream-product-connector-instructions-for-use' => $this->translationHelper()->mapTranslations(
$product->getLocalizedfields(),
['instructionsForUse']
),
'twocream-product-connector-product-type' => $productTypeTranslations,
'twocream-product-connector-assembly-instructions' => $this->productDataService->getAssamblyInstructions($product),
'twocream-product-connector-fields-of-application' => $this->translationHelper()->mapLanguages($fieldsOfApplicationValues)
]
];
if (!$isVariant) {
$productData['cross-selling-checksum'] = $this->productDataService->calculateChecksum($this->productDataService->prepareCrossSelling($product));
}
return $productData;
}
private function getImageThumbnails(ExampleProduct $product): array
{
$beforeInheritedValues = DataObject\AbstractObject::getGetInheritedValues();
\Pimcore\Model\DataObject\AbstractObject::setGetInheritedValues(true);
$images = [];
if (!empty($product->getMainProductImage())) $images[] = $product->getMainProductImage()->getImage();
if (!empty($product->getMoreProductImages())) {
$imageGallery = $product->getMoreProductImages();
foreach ($imageGallery->getItems() as $image) {
$images[] = $image->getImage();
}
}
$imageThumbnails = [];
// Thumbnails mittels Asset Helper generieren
foreach ($images as $image) {
$imageThumbnail = $this->assetHelper()->copyAsset($image, self::PRODUCT_IMAGE_THUMBNAILS);
if (!empty($imageThumbnail)) {
$imageThumbnails[] = ['alt' => $image->getFilename(), 'filename' => $image->getFilename(), ...$imageThumbnail];
}
}
\Pimcore\Model\DataObject\AbstractObject::setGetInheritedValues($beforeInheritedValues);
return $imageThumbnails;
}
}
Registrierung des Adapters
Neue Adapter sind in einer Service-Konfigurationsdatei zu registrieren. Hierbei ist der Service-Tag twocream.shopware_connector.adapter zwingend zu verwenden.
Danach muss folgender Command per CLI twocream:shopware-connector:reload-permissions ausgeführt werden.
Best Practice
Zur strukturierten Konfiguration wird empfohlen, die Datei config/services/shopware_connector_adapter.yaml anzulegen.
Diese ist anschließend über einen Import in der zentralen services.yaml einzubinden.
services:
_defaults:
autowire: true
autoconfigure: true
public: false
twocream.shopware_connector.adapter_example:
public: true
class: App\Components\Export\Adapters\ExampleAdapter
tags: [ 'twocream.shopware_connector.adapter' ]