<?php declare(strict_types=1);
namespace CioSearchHeadline\Subscriber;
use Shopware\Core\Content\Product\Events\ProductSearchCriteriaEvent;
use Shopware\Core\Content\Product\Events\ProductSuggestCriteriaEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class SearchTermNormalizerSubscriber implements EventSubscriberInterface
{
/**
* Teilenummern-Pattern:
* - dashed: alphanumerische Segmente mit Bindestrichen (z. B. A-5000-7803, 626115-0800-075, TCM5S4010022-XYZ)
* - mixed: zusammenhängend, mind. 1 Buchstabe + 1 Ziffer (z. B. K651164)
*
* Hinweis: Es wird ausschließlich die Groß-/Kleinschreibung der Buchstaben normalisiert; Trennzeichen bleiben unverändert.
*/
private const PATTERN_DASHED = '/^[A-Za-z0-9]+(?:-[A-Za-z0-9]+)+$/';
private const PATTERN_MIXED = '/^(?=.*[A-Za-z])(?=.*\d)[A-Za-z0-9]{3,}$/';
public static function getSubscribedEvents(): array
{
return [
ProductSearchCriteriaEvent::class => 'onSearch',
ProductSuggestCriteriaEvent::class => 'onSearch',
];
}
/**
* Normalisiert passende Hersteller-/Teilenummern auf Uppercase,
* ohne Daten zu verändern – nur Query-Ebene (Request + Criteria).
*/
public function onSearch(object $event): void
{
// Beide Events erben von ProductListingCriteriaEvent und bieten getRequest()/getCriteria()
if (!\method_exists($event, 'getRequest') || !\method_exists($event, 'getCriteria')) {
return;
}
$request = $event->getRequest();
$criteria = $event->getCriteria();
if (!$request || !$criteria) {
return;
}
// 1) Term aus Request lesen
$term = (string) ($request->get('search') ?? '');
// 2) Fallback: ggf. aus Criteria
if ($term === '' && \method_exists($criteria, 'getTerm')) {
$term = (string) ($criteria->getTerm() ?? '');
}
$term = \trim($term);
if ($term === '') {
return;
}
// 3) Prüfen, ob der gesamte Term wie eine Teilenummer aussieht
$shouldNormalize =
\preg_match(self::PATTERN_DASHED, $term) === 1
|| \preg_match(self::PATTERN_MIXED, $term) === 1;
if ($shouldNormalize) {
// 4a) Uppercase-Normalisierung NUR auf Query-Ebene (kompletter Term)
$normalized = \mb_strtoupper($term, 'UTF-8');
// Request-Parameter aktualisieren (für Suggest/Weiterverarbeitung)
$request->query->set('search', $normalized);
// Criteria-Term aktualisieren
if (\method_exists($criteria, 'setTerm')) {
$criteria->setTerm($normalized);
}
return;
}
// 4b) Fallback: In Mehrwort-Suchen einzelne Token normalisieren
$parts = \preg_split('/\s+/', $term);
$changed = false;
foreach ($parts as &$p) {
if ($p === '') {
continue;
}
if (
\preg_match(self::PATTERN_DASHED, $p) === 1
|| \preg_match(self::PATTERN_MIXED, $p) === 1
) {
$upper = \mb_strtoupper($p, 'UTF-8');
if ($upper !== $p) {
$p = $upper;
$changed = true;
}
}
}
unset($p);
if ($changed) {
$normalized = \implode(' ', $parts);
$request->query->set('search', $normalized);
if (\method_exists($criteria, 'setTerm')) {
$criteria->setTerm($normalized);
}
}
}
}