Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

Custom Publications in Custom Operations

Custom Publications in Custom Operations

~14 Min. Lesezeit Zuletzt aktualisiert am August 8, 2026

mercure: true (chapter 68) publishes AUTOMATICALLY on the DEFAULT operations – the custom operation from chapter 61 (/projects/{id}/archive) needs an EXPLICIT publication.

Why custom operations don't publish automatically

API Platform's AUTOMATIC Mercure publishing is tied to the DEFAULT Doctrine persistence flow – ArchiveProjectProcessor (chapter 61) DOES call flush(), but NOT via the DEFAULT mechanism that AUTOMATICALLY triggers the publication.

Injecting the HubInterface publisher

api/src/State/ArchiveProjectProcessor.php
<?php

declare(strict_types=1);

namespace App\State;

use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface;
use App\Entity\Project;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Mercure\HubInterface;
use Symfony\Component\Mercure\Update;
use Symfony\Component\Serializer\SerializerInterface;

final class ArchiveProjectProcessor implements ProcessorInterface
{
    public function __construct(
        private readonly EntityManagerInterface $entityManager,
        private readonly HubInterface $hub,
        private readonly SerializerInterface $serializer,
    ) {
    }

    public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): Project
    {
        /** @var Project $data */
        $data->setArchived(true);
        $this->entityManager->flush();

        $topic = 'https://localhost/api/projects/' . $data->getId();
        $json = $this->serializer->serialize($data, 'jsonld', ['groups' => ['project:read']]);
        $this->hub->publish(new Update($topic, $json));

        return $data;
    }
}

HubInterface is EXACTLY the service API Platform uses INTERNALLY ITSELF for the AUTOMATIC publication from chapter 68 – NOW used EXPLICITLY, with FULL control over the topic and content.

Using the same serialization group

['groups' => ['project:read']] ENSURES that the PUBLISHED message has EXACTLY the same shape as a normal GET response (chapter 23) – a client can use the SAME deserialization logic for BOTH sources.

Testing the behavior

SET UP a subscription to /api/projects/1 (chapter 69), then call POST /api/projects/1/archive – the update with "archived": true appears IMMEDIATELY in the subscription, EXACTLY as with a DEFAULT PATCH.

Achtung: This MANUAL publication WORKS even if mercure: true were NOT set at the resource level AT ALL – the HubInterface service can be used INDEPENDENTLY of the #[ApiResource] metadata configuration.

Tipp: THIS pattern (a state processor that publishes an update IN ADDITION to the actual action) transfers to ANY custom operation – ANYWHERE an action changes the PUBLICLY visible state of a resource, an EXPLICIT publication makes sense.