Zum Hauptinhalt springen
Version: 2025.11

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

NameBeschreibung
getPackageName(): stringEindeutiger Package-Name, z.B. "product"
getTargetClassName(): stringZugehöriger Objekt-Klassenname z.B. "Product"
prepare($object): arrayHier erfolgt die inhaltsbezogene Aufbereitung der Daten, die für den Export vorgesehen sind
Optional
initialize(): voidFührt vorbereitende Prozesse aus, z. B. Ermittlung von Produktpositionen
getDependentAdapters(): arrayDefiniert die Verarbeitungsreihenfolge der abhängigen Adapter, siehe "Abhängigkeiten zwischen Export-Adaptern"
getThumbnailMapping(): arrayDefiniert 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' ]