Akeneo direct aan Magento koppelen werkt — totdat je van PIM wisselt. Dan herbouw je alles. Een middleware-laag in Laravel voorkomt dat, en geeft je ook nog eens betere controle over data-transformaties.
PIM-koppeling zonder vendor lock-in: de middleware aanpak
Drie jaar geleden koppelde een klant Akeneo direct aan Magento. Vorige maand besloten ze naar Pimcore over te stappen. De directe koppeling betekende dat ze opnieuw moesten beginnen: nieuwe API-calls, nieuwe data-mapping, nieuwe synchronisatielogica. Acht weken werk.
Met een middleware-laag was dat twee weken geweest. Alleen de connector naar het PIM moest aangepast worden — de rest bleef.
Wat je leert in dit artikel
- Waarom directe PIM-integraties vendor lock-in creëren
- Hoe een middleware-architectuur dat oplost
- Concrete implementatie met Laravel als middleware-laag
- Data-transformatie en normalisatie patronen
- Akeneo vs Pimcore: waar je op let bij de keuze
Waarom directe PIM-koppelingen een probleem zijn
Een directe koppeling tussen Akeneo en Magento bestaat uit drie lagen: API-authenticatie, data-mapping en synchronisatielogica.
API-authenticatie is trivaal om te vervangen — elke PIM heeft OAuth of API-keys. Data-mapping is het echte probleem. Akeneo structureert productdata anders dan Pimcore, anders dan Contentserv, anders dan Plytix. Attribute groups, familie-structuren, categorielogica — alles verschilt. Als die mapping direct in Magento-code zit (in een connector-module), is vervanging een herbouw. Synchronisatielogica bevat de meeste business-kennis: welke attributen gaan naar welk kanaal, hoe worden eenheden omgezet, welke producten zijn zichtbaar in welke winkel. Dit is de code die je wilt behouden bij een PIM-wissel.De middleware-architectuur
Een middleware-laag in Laravel functioneert als adapter. Het heeft twee interfaces:
- PIM-interface: connectors per PIM-systeem die data omzetten naar een intern, genormaliseerd formaat
- Channel-interface: connectors per verkoopkanaal (Magento, Shopify, marketplaces) die het interne formaat omzetten naar het formaat van dat kanaal
Akeneo API ──► AkeneoConnector ──► [Intern Product Model] ──► MagentoConnector ──► Magento API
Pimcore API ──► PimcoreConnector ──► [Intern Product Model] ──► ShopifyConnector ──► Shopify API
Bij een PIM-wissel vervang je alleen de PIM-connector. De channel-connectors en alle synchronisatielogica blijven intact.
Het interne product model
Het interne model is de sleutel. Het definieert hoe jij productdata representeert, onafhankelijk van PIM of verkoopkanaal.
// Intern product model — platform-agnostisch
class ProductData
{
public function __construct(
public readonly string $sku,
public readonly string $naam,
public readonly ?string $beschrijving,
public readonly ProductStatus $status,
public readonly array $attributen,
public readonly array $categorieIds,
public readonly array $afbeeldingen,
public readonly array $kanaalbewerkingen, // Per-channel overrides
) {}
}
// Attribuut — generiek maar typed
class ProductAttribuut
{
public function __construct(
public readonly string $code,
public readonly string $type, // text, number, select, multiselect, boolean
public readonly mixed $waarde,
public readonly ?string $taalcode,
public readonly ?string $scoop, // global, website, storeview
) {}
}
Dit model is jouw interne standaard. Elke connector vertaalt naar en van dit model.
Akeneo connector
Akeneo's REST API is goed gedocumenteerd. De uitdaging is de mapping van Akeneo's attribute families naar jouw interne model.
class AkeneoConnector implements PimConnector
{
public function __construct(
private readonly AkeneoClient $client,
public readonly AttributeMappingRepository $mapping,
) {}
public function haalProductOp(string $sku): ProductData
{
$akeneoProduct = $this->client->getProduct($sku);
return new ProductData(
sku: $akeneoProduct['identifier'],
naam: $this->haalWaarde($akeneoProduct, 'name', 'nl_NL'),
beschrijving: $this->haalWaarde($akeneoProduct, 'description', 'nl_NL'),
status: $akeneoProduct['enabled'] ? ProductStatus::Actief : ProductStatus::Inactief,
attributen: $this->mapAttributen($akeneoProduct['values']),
categorieIds: $akeneoProduct['categories'],
afbeeldingen: $this->haalAfbeeldingen($akeneoProduct),
kanaalbewerkingen: [],
);
}
private function mapAttributen(array $akeneoWaarden): array
{
$attributen = [];
foreach ($akeneoWaarden as $code => $waarden) {
// Akeneo geeft waarden per locale en scope terug
foreach ($waarden as $waarde) {
$attributen[] = new ProductAttribuut(
code: $code,
type: $this->mapping->getType($code),
waarde: $waarde['data'],
taalcode: $waarde['locale'],
scoop: $waarde['scope'],
);
}
}
return $attributen;
}
private function haalWaarde(array $product, string $attribuut, string $locale): ?string
{
return $product['values'][$attribuut][0]['data'] ?? null;
}
}
Magento channel connector
De Magento-connector zet het interne model om naar Magento's REST API-formaat.
class MagentoConnector implements ChannelConnector
{
public function __construct(
private readonly MagentoClient $client,
private readonly AttributeTranslator $translator,
) {}
public function synchroniseerProduct(ProductData $product, string $storeCode = 'default'): void
{
$magentoProduct = [
'sku' => $product->sku,
'name' => $product->naam,
'status' => $product->status === ProductStatus::Actief ? 1 : 2,
'visibility' => 4, // Catalogus + zoeken
'type_id' => 'simple',
'attribute_set_id' => $this->translator->getAttributeSetId($product),
'custom_attributes' => $this->mapCustomAttributen($product->attributen),
];
// Controleer of product al bestaat
try {
$this->client->putProduct($product->sku, $magentoProduct, $storeCode);
} catch (ProductNotFoundException) {
$this->client->postProduct($magentoProduct);
}
// Afbeeldingen apart synchroniseren
$this->synchroniseerAfbeeldingen($product->sku, $product->afbeeldingen);
}
private function mapCustomAttributen(array $attributen): array
{
return collect($attributen)
->map(fn(ProductAttribuut $a) => [
'attribute_code' => $a->code,
'value' => $this->translator->formatWaarde($a),
])
->values()
->toArray();
}
}
Synchronisatie via Laravel queues
De synchronisatie loopt via Laravel-jobs. Dat geeft je automatische retry-logica, prioriteitsqueues en monitoring via Horizon.
class SynchroniseerProductJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public int $tries = 3;
public int $backoff = 60; // Wacht 60 seconden tussen pogingen
public function __construct(
private readonly string $sku,
private readonly string $pimConnector,
private readonly array $targetChannels,
) {}
public function handle(
ConnectorFactory $factory,
): void {
// Haal data op uit PIM via de correcte connector
$pim = $factory->makePim($this->pimConnector);
$product = $pim->haalProductOp($this->sku);
// Distribueer naar alle target channels
foreach ($this->targetChannels as $channel) {
$connector = $factory->makeChannel($channel);
$connector->synchroniseerProduct($product);
}
}
public function failed(Throwable $exception): void
{
// Log en eventueel alert versturen
Log::error("Product sync mislukt voor SKU {$this->sku}", [
'exception' => $exception->getMessage(),
'pim' => $this->pimConnector,
]);
}
}
Akeneo vs Pimcore: wat kies je?
De keuze voor een PIM is een apart artikel waard, maar hier zijn de praktische verschillen.
| Aspect | Akeneo | Pimcore |
|---|---|---|
| Licentiemodel | Community (beperkt) / Enterprise | Open source / Enterprise |
| Hosting | SaaS of self-hosted | Self-hosted |
| Gebruiksgemak | Uitstekend voor redacteuren | Functioneel maar steiler |
| API-kwaliteit | Uitstekend, goed gedocumenteerd | Goed, iets minder consistent |
| Digitale assets (DAM) | Beperkt in Community | Ingebouwd en uitgebreid |
| Geschikt voor | Pure PIM-behoefte | PIM + DAM + CMS gecombineerd |
| Instapprijs SaaS | ~€25.000/jaar | Self-hosted: serverkosten |
Wij zien Akeneo vaker bij retailers die een dedicated redactieteam hebben en een clean PIM-workflow willen. Pimcore kiezen klanten die ook assets en CMS-content willen beheren vanuit één systeem.
Met de middleware-architectuur maakt de keuze voor jouw integratie minder uit — de switch is altijd mogelijk.
Voordelen die je erbij krijgt
Een middleware-laag geeft meer dan alleen flexibiliteit bij PIM-wissels.
Data-validatie voor distributie. Je kunt producten valideren voordat ze naar verkoopkanalen gaan. Is de beschrijving lang genoeg? Zijn alle verplichte attributen ingevuld? Heeft het product afbeeldingen? Fouten vang je centraal af, niet verspreid over meerdere systemen. Transformaties en verrijking. Prijsberekeningen, eenheidsconversies, categorievertaling naar channel-specifieke structuren — dat doe je allemaal in de middleware, niet in elk channel apart. Audit trail. Elke synchronisatie-operatie log je centraal. Je weet exact wanneer welk product naar welk kanaal is gesynchroniseerd, met welke data en of het gelukt is. Meerdere channels tegelijk. Één PIM-update gaat naar Magento, Shopify en een marketplace tegelijk. Zonder middleware bouw je die fanout in elk systeem apart.Veelgemaakte fouten
1. Het interne model te dicht bij het PIM modelleren. Als je intern Akeneo's attribute-families direct overneemt, is de wissel later alsnog lastig. Modelleer intern op basis van jouw businessdomein. 2. Synchronisatie bidirectioneel maken zonder nadenken. Prijzen komen uit het ERP, niet het PIM. Voorraad komt uit het WMS. Maak duidelijk welk systeem de "source of truth" is per attribuut. 3. Geen delta-detectie. Elk uur alle 50.000 producten synchroniseren is onnodig. Gebruik webhooks vanuit het PIM voor realtime updates en een nachtelijke full-sync als fallback. 4. Foutafhandeling vergeten. Een API-call kan mislukken. Implementeer retry-logica met exponential backoff en sla gefaalde jobs op voor handmatige review.Conclusie
Een directe PIM-koppeling werkt totdat je van PIM wisselt, een nieuw verkoopkanaal toevoegt of je synchronisatielogica wilt aanpassen. Dan betaal je de prijs van vendor lock-in.
Een middleware-laag in Laravel kost initieel meer om op te zetten, maar geeft je flexibiliteit, centraliteit en controle die de investering over twee à drie jaar terugbetalen.
Lees meer over onze Laravel-aanpak of Magento-integraties. Voor complexere integratiescenario's met meerdere systemen, bekijk ook onze Alumio integratie-aanpak.
Wil je jouw PIM-koppeling toekomstbestendig maken? Neem contact op — we denken graag mee over de architectuur.
Veelgestelde vragen
Kan ik bestaande directe koppelingen migreren naar middleware?Ja, maar plan het zorgvuldig. De beste aanpak is het interne model eerst definiëren op basis van je huidige data, dan de middleware-laag bouwen die de bestaande directe koppeling repliceert, en vervolgens de directe koppeling uitschakelen. Stapsgewijs, niet in één grote migratie.
Welke PIM-systemen ondersteunen goede webhooks?Akeneo heeft webhooks beschikbaar vanaf de Growth Edition. Pimcore heeft een uitgebreid event-systeem. Akeneo's Community Edition heeft geen webhooks — dan is polling de enige optie.
Hoe ga ik om met grote catalogi (100.000+ SKUs)?Gebruik chunked processing via Laravel-jobs. Verwerk de full-sync in batches van 500 à 1.000 producten. Bij delta-synchronisatie houd je een checkpoint bij (timestamp of cursor) zodat je weet waar je gebleven was.
Is een middleware-laag ook zinvol als ik maar één verkoopkanaal heb?Bij één kanaal en één PIM is de ROI lager. De middleware-laag betaalt zich uit als je meerdere channels hebt, van PIM wilt kunnen wisselen of complexe transformatielogica hebt. Bij een eenvoudige setup kan een directe koppeling prima volstaan.
Welke hosting heb ik nodig voor de middleware?Een Laravel-applicatie met queue workers draait prima op een €20/maand VPS voor middelgrote catalogi. Bij grote volumes (100.000+ SKUs, frequente syncs) reken je op meerdere workers en mogelijk een dedicated database. DigitalOcean Managed Databases + App Platform of een Forge-gestuurde VPS zijn bewezen keuzes.

Geschreven door Ruthger Idema
15+ jaar ervaring in e-commerce development. Gespecialiseerd in Magento, Shopify en Laravel maatwerk.
Meer over ons team →