add shopware store-api

This commit is contained in:
team 1
2026-04-09 12:00:34 +02:00
parent 0ef3b43b30
commit 1aee32f1d8
13 changed files with 992 additions and 10 deletions

View File

@@ -0,0 +1,154 @@
<?php
declare(strict_types=1);
namespace App\Commerce;
use App\Commerce\Dto\ShopProductResult;
use App\Shopware\ShopwareCriteriaBuilder;
use App\Shopware\StoreApiClient;
final readonly class ShopSearchService
{
public function __construct(
private CommerceQueryParser $queryParser,
private ShopwareCriteriaBuilder $criteriaBuilder,
private StoreApiClient $storeApiClient,
private bool $enabled = true,
private int $maxResults = 25,
private string $baseUrl
)
{
}
/**
* @return ShopProductResult[]
*/
public function search(string $originalPrompt, string $commerceIntent): array
{
if (!$this->enabled) {
return [];
}
$query = $this->queryParser->parse($originalPrompt, $commerceIntent);
$criteria = $this->criteriaBuilder->build($query, $this->maxResults);
$response = $this->storeApiClient->searchProducts($criteria);
return $this->mapProducts($response);
}
/**
* @return ShopProductResult[]
*/
private function mapProducts(array $response): array
{
$elements = $response['elements'] ?? [];
if (!is_array($elements)) {
return [];
}
$results = [];
foreach ($elements as $row) {
if (!is_array($row)) {
continue;
}
$results[] = new ShopProductResult(
id: (string)($row['id'] ?? ''),
name: trim((string)($row['translated']['name'] ?? '')),
productNumber: isset($row['productNumber']) ? (string)$row['productNumber'] : null,
price: $this->extractPrice($row),
available: isset($row['available']) ? (bool)$row['available'] : null,
url: $this->baseUrl . $this->extractUrl($row),
highlights: $this->extractHighlights($row),
description: $this->cleanUpDescription($row),
);
}
return array_values(array_filter(
$results,
static fn(ShopProductResult $product): bool => $product->name !== ''
));
}
private function cleanUpDescription($description): string
{
if (isset($description['translated']['description'])) {
$newDesc = strip_tags((string)$description['translated']['description']);
$newDesc = preg_replace('/^[ \t]*\R/m', '', $newDesc); // leere Zeilen weg
$newDesc = preg_replace('/[ \t]{2,}/', ' ', $newDesc); // mehrere Spaces zu einem
$result = trim($newDesc);
return substr($result, 0, 500);
}
return '';
}
private function extractManufacturer(array $row): ?string
{
$manufacturer = $row['manufacturer'] ?? null;
if (is_array($manufacturer) && isset($manufacturer['name']) && is_string($manufacturer['name'])) {
return trim($manufacturer['name']) !== '' ? trim($manufacturer['name']) : null;
}
return null;
}
private function extractPrice(array $row): ?string
{
$calculatedPrice = $row['calculatedPrice'] ?? null;
if (!is_array($calculatedPrice)) {
return null;
}
$unitPrice = $calculatedPrice['unitPrice'] ?? $calculatedPrice['totalPrice'] ?? $calculatedPrice['referencePrice'] ?? $calculatedPrice['listPrice'] ?? $calculatedPrice['regulationPrice'] ?? 0;
if (!is_numeric($unitPrice)) {
return null;
}
return number_format((float)$unitPrice, 2, ',', '.') . ' €';
}
private function extractUrl(array $row): ?string
{
$seoUrls = $row['seoUrls'] ?? null;
if (!is_array($seoUrls) || $seoUrls === []) {
return null;
}
foreach ($seoUrls as $seoUrl) {
if (!is_array($seoUrl)) {
continue;
}
$path = $seoUrl['seoPathInfo'] ?? null;
if (is_string($path) && trim($path) !== '') {
return '/' . ltrim($path, '/');
}
}
return null;
}
/**
* @return string[]
*/
private function extractHighlights(array $row): array
{
$highlights = [];
if (isset($row['available'])) {
$highlights[] = ((bool)$row['available']) ? 'Verfügbar' : 'Nicht verfügbar';
}
if (isset($row['productNumber']) && is_string($row['productNumber']) && trim($row['productNumber']) !== '') {
$highlights[] = 'Produktnummer: ' . trim($row['productNumber']);
}
return array_values(array_unique($highlights));
}
}