0

I want to present a set of selectable icons to choose one from for each page. When selected, the icon should be available in navigation context data, e.g. via Sulu\HeadlessBundle:

{
    "_embedded": {
        "items": [
            {
                "id": "ffffffff-ffff-ffff-ffff-fffffffffff",
                "uuid": "ffffffff-ffff-ffff-ffff-fffffffffff",
                "nodeType": 1,
                "changed": "2000-01-01T12:00:00",
                "changer": 1,
                "created": "2022-01-01T12:00:01",
                "publishedState": true,
                "published": "2000-01-01T12:00:01",
                "creator": 1,
                "title": "Foo",
                "locale": "de",
                "webspaceKey": "bar",
                "template": "default",
                "parent": "eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee",
                "url": "/foo",
                "urls": {
                    "de": "/foo"
                },
                "author": "1",
                "authored": "2000-01-01T12:00:00",
                "order": 20,
                "children": [],
                "nav_icon": {} // Either a Media entity from a system collection, or just a filename to reference the icon with
            }
        ]
    }
}

I am aware of the possibility of storing icons as Media data and then applying them via the page excerpt data, but I don't want my users to arbitrarily upload and pick icons. Guessing from my own research I also cannot limit a single_media_selection to a system collection, let alone the icons selection in the excerpt tab.

Is there an approach to my task? I tried adding UI tabs to the page editing form, but I can't seem to extend the actual structure data so that the icon information is serialized.

Leon Willens
  • 356
  • 1
  • 16

1 Answers1

0

I devised a solution that utilizes the Symfony kernel listeners. Since I only need the top-level navigation items to display an icon, I hooked into the kernel.response of the HeadlessBundle's navigations API route and iterated through the response content, fetching document information for each top-level page and extracting the relevant extension data that I already constructed with the Sulu cookbook.

<?php declare(strict_types=1);

namespace App\EventListener;

use Sulu\Component\DocumentManager\DocumentManagerInterface;
use Sulu\Component\DocumentManager\Exception\DocumentManagerException;
use Symfony\Component\HttpKernel\Event\ResponseEvent;

class NavigationListener
{
    public function __construct(private DocumentManagerInterface $documentManager)
    {
    }

    public function onKernelResponse(ResponseEvent $event): void
    {
        $request = $event->getRequest();
        if ($request->attributes->get('_route') !== 'sulu_headless.api.navigation') {
            return;
        }
        $responseObj = json_decode($event->getResponse()->getContent(), true);
        foreach ($responseObj['_embedded']['items'] as &$item) {
            $uuid = $item['uuid'];
            $doc = $this->documentManager->find($uuid);
            $documentExtension = $doc->getExtensionsData()->toArray();
            if (isset($documentExtension['navigation'])) {
                $item['navigationIcon'] = $documentExtension['navigation']['icon'];
            }
        }
        $event->getResponse()->setContent(json_encode($responseObj, JSON_PRETTY_PRINT));
    }
}

In the long term, it would be interesting to pass extension loading information to the HeadlessBundle.

Leon Willens
  • 356
  • 1
  • 16