Shopware 6 Auslesen des CrossSellings über API

Hallo zusammen,

ich habe aktuell ein Problem beim Programmieren oder stehen ein wenig auf dem Schlauch. Ich benötige für meinen Shop die Daten aus aus dem Produkt und den dazugehörigen CrossSelling in einer separaten json Datei. Jetzt habe ich folgendes Problem ich bekomme für das CrossSelling immer nur ein leeres Array aus Ausgabe! Hat jemand eine Idee wo das Problem liegen könnte?

<?php
// chatbot-sync.php

header("Content-Type: text/plain");

// Admin-API URLs
$shopDomain    = '****';
$clientId      = '****';
$clientSecret  = '****';
$categoryId    = '****';
$outputFile    = __DIR__ . '/public/chatbot/chatbot-date.json';


function getAdminHeaders(string $token): array {
    return [
        "Authorization: Bearer {$token}",
        "Content-Type: application/json",
    ];
}

// === Fetch Admin API token ===
function fetchToken(string $shopDomain, string $clientId, string $clientSecret): ?string {
    $ch = curl_init("{$shopDomain}/api/oauth/token");
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POSTFIELDS     => http_build_query([
            'client_id'     => $clientId,
            'client_secret' => $clientSecret,
            'grant_type'    => 'client_credentials',
        ]),
        CURLOPT_SSL_VERIFYPEER => false,
        CURLOPT_SSL_VERIFYHOST => false,
    ]);
    $res = curl_exec($ch);
    curl_close($ch);
    $data = json_decode($res, true);
    return $data['access_token'] ?? null;
}

// === Helper: Resolve product name by ID ===
function getProductName(string $token, string $productId): ?string {
    global $shopDomain;
    $ch = curl_init("{$shopDomain}/api/product/{$productId}");
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER     => getAdminHeaders($token),
        CURLOPT_SSL_VERIFYPEER => false,
        CURLOPT_SSL_VERIFYHOST => false,
    ]);
    $res = curl_exec($ch);
    curl_close($ch);
    $data = json_decode($res, true);
    return $data['data']['attributes']['name'] ?? null;
}

// === Token holen (Admin API) ===
$token = fetchToken($shopDomain, $clientId, $clientSecret);
if (!$token) {
    die("❌ Token-Request failed\n");
}

// === Produkte aus Kategorie laden und Cross-Selling via associations einbinden ===
$devices = [];
$page    = 1;
$limit   = 100;

do {
    $payload = [
        'filter'       => [[
            'type'  => 'equals',
            'field' => 'categories.id',
            'value' => $categoryId,
        ]],
        'page'         => $page,
        'limit'        => $limit,
        'associations' => [
            'crossSellings' => new \stdClass(),
        ],
        'includes'     => [
            'product'              => ['id', 'name', 'productNumber', 'crossSellings'],
            'product_cross_selling'=> ['id', 'productId', 'name', 'position', 'type', 'active'],
        ],
    ];

    $ch = curl_init("{$shopDomain}/api/search/product");
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POSTFIELDS     => json_encode($payload),
        CURLOPT_HTTPHEADER     => getAdminHeaders($token),
        CURLOPT_SSL_VERIFYPEER => false,
        CURLOPT_SSL_VERIFYHOST => false,
    ]);
    $res   = curl_exec($ch);
    curl_close($ch);
    $json  = json_decode($res, true);
    $batch = $json['data'] ?? [];

    foreach ($batch as $p) {
        $id     = $p['id'];
        $attr   = $p['attributes'] ?? [];
        $name   = $attr['name'] ?? '';
        $num    = $attr['productNumber'] ?? '';
        $cs     = [];

        // Cross-Selling-Entries aus Produkt-Daten
        $assocCs = $p['associations']['crossSellings']['elements'] ?? [];
        foreach ($assocCs as $entry) {
            // product_cross_selling attributes
            $pid = $entry['productId'] ?? null;
            if ($pid && $n = getProductName($token, $pid)) {
                $cs[] = $n;
            }
        }

        $devices[] = [
            'id'            => $id,
            'name'          => $name,
            'productNumber' => $num,
            'crossSelling'  => array_values(array_unique($cs)),
        ];
    }

    $page++;
} while (count($batch) === $limit);

// === JSON schreiben ===
@mkdir(dirname($outputFile), 0755, true);
file_put_contents($outputFile, json_encode($devices, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));

echo "✅ " . count($devices) . " Geräte in chatbot-date.json geschrieben\n";

Und die Ausgabe:

[
    {
        "id": "*************",
        "name": "Name",
        "productNumber": "12355541",
        "crossSelling": []
    },
...

Sicher, das es “elements” für crossSellings gibt? Bei mir gibts das nicht, dazu muss ich productStream oder assignedProducts verarbeiten.