Products megamenu as a data-driven catalog with a Solr product type-ahead

- evo_megamenu_json stays project-neutral: new panel layout "catalog";
  for such entries the MenuBuilder dispatches the new PSR-14 event
  BuildCatalogEvent and emits whatever a listener sets as `catalog`
  (null without a listener). The entry's teaser cards serve as the
  featured tiles; the teaser inline field now also shows for "catalog",
  and the entry form reloads when the layout changes. README section
  "Layout catalog"
- VITEC listener ProvideProductCatalog fills it, modelled on the Ross
  Video products menu: main categories below the "Product" root, their
  subcategories as groups, products with a plain-text one-line teaser;
  same visibility rules as the product list, Product Finder links
  (/products?cat=&subcat=), empty categories and groups left out, three
  queries for the whole catalog
- Product type-ahead GET /_json/?type=7385&q= (USER_INT page type,
  ProductMenuSearchJsonRenderer): Solr restricted to products, last term
  completed as a prefix, up to six product cards plus their titles as
  autocomplete suggestions; endpoint announced in catalog.search
- Spec v1.23 (clause 7.16: product type-ahead)
This commit is contained in:
orasche committed 2026-10-09 13:40:23 +02:00
1 parent b5fcdb2b5a
commit 887caed2aa
8 files changed
+502 -6

No files matched your search

@@ -0,0 +1,52 @@
<?php
declare(strict_types=1);
namespace Evomedien\EvoMegamenuJson\Event;
/**
* Dispatched for every entry with the panel layout `catalog`.
*
* The extension stays project-neutral: it knows that a catalog panel exists,
* not where its data comes from. A site package listens to this event and
* supplies the data (categories, their groups and items, a search endpoint,
* ...) as a plain array; it is emitted verbatim as `catalog` on the entry.
* Without a listener the entry carries `catalog: null`.
*/
final class BuildCatalogEvent
{
/** @var array<string,mixed>|null */
private ?array $catalog = null;
/**
* @param array<string,mixed> $entry the raw tx_evomegamenujson_entry row
*/
public function __construct(
private readonly array $entry,
private readonly int $stage,
) {}
/** @return array<string,mixed> */
public function getEntry(): array
{
return $this->entry;
}
/** Content stage of the menu (1 structure, 2 + images/teasers, 3 + featured). */
public function getStage(): int
{
return $this->stage;
}
/** @return array<string,mixed>|null */
public function getCatalog(): ?array
{
return $this->catalog;
}
/** @param array<string,mixed> $catalog */
public function setCatalog(array $catalog): void
{
$this->catalog = $catalog;
}
}