add shopware store-api
This commit is contained in:
154
src/Commerce/ShopSearchService.php
Normal file
154
src/Commerce/ShopSearchService.php
Normal 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));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user