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
<?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.