activpik/stomp-bundle
Symfony bundle integrating a STOMP client for message brokers. Configure multiple connections and named producers, enable sandbox mode for testing, create messages via a factory, and send them through the activpik_stomp service from your controllers.
Installation Add the bundle via Composer:
composer require activpik/stomp-bundle:dev-master
Register the bundle in app/AppKernel.php:
new Activpik\StompBundle\ActivpikStompBundle(),
Basic Configuration
Configure app/config/config.yml with a connection and producer:
activpik_stomp:
sandbox: true # Enable for testing (no real messages sent)
connections:
default_connection:
host: localhost
port: 61613
producers:
default_producer:
destination: "test/queue"
connection: default_connection
First Use Case: Sending a Message
Inject the StompClient and MessageFactory services into a controller or service:
use Symfony\Component\DependencyInjection\ContainerInterface;
class MyController extends Controller
{
public function sendMessageAction(ContainerInterface $container)
{
// Create a message
$message = $container->get('activpik_stomp_message_factory')->createMessage([
'id' => 123,
'data' => 'Hello, STOMP!'
]);
// Send via producer
$container->get('activpik_stomp')->send('default_producer', $message);
return new Response('Message sent!');
}
}
Service-Based Workflow
Prefer injecting Activpik\StompBundle\Service\StompClient and Activpik\StompBundle\Service\MessageFactory into services/controllers via constructor injection (Symfony 2.8+ style):
use Activpik\StompBundle\Service\StompClient;
use Activpik\StompBundle\Service\MessageFactory;
class MyService
{
private $stompClient;
private $messageFactory;
public function __construct(StompClient $stompClient, MessageFactory $messageFactory)
{
$this->stompClient = $stompClient;
$this->messageFactory = $messageFactory;
}
public function process()
{
$message = $this->messageFactory->createMessage(['key' => 'value']);
$this->stompClient->send('default_producer', $message);
}
}
Event-Driven Architecture
Use the bundle to decouple components by publishing messages to STOMP topics/queues, then consume them via Symfony’s EventDispatcher or a separate consumer service.
Activpik\StompBundle\Message\MessageInterface and binding your class to the container:
services:
app.custom_message:
class: AppBundle\Message\CustomMessage
tags: ['activpik_stomp.message']
config.yml and switch between them at runtime:
connections:
primary:
host: primary-broker.example.com
port: 61613
backup:
host: backup-broker.example.com
port: 61614
$this->stompClient->send('producer_for_backup', $message, 'backup');
send() calls in a retry mechanism for transient failures:
$attempts = 0;
$maxAttempts = 3;
while ($attempts < $maxAttempts) {
try {
$this->stompClient->send('default_producer', $message);
break;
} catch (\Exception $e) {
$attempts++;
if ($attempts === $maxAttempts) throw $e;
sleep(1);
}
}
Sandbox Mode
sandbox: true prevents actual messages from being sent (useful for testing). Remember to disable it in production:
activpik_stomp:
sandbox: "%kernel.environment% == 'dev'" # Toggle via environment
Connection Validation
The bundle does not validate connection parameters (host/port) on startup. Test connectivity manually or add a post_load listener to activpik_stomp.connection_manager:
$container->get('activpik_stomp.connection_manager')->getConnection('default_connection')->connect();
Logging
Enable Symfony’s profiler to inspect STOMP interactions. Add this to config.yml:
activpik_stomp:
logging: true # Logs messages to Symfony's logger
Common Exceptions
Activpik\StompBundle\Exception\ConnectionException: Broker unreachable.Activpik\StompBundle\Exception\SendException: Invalid producer/destination.
Fix: Verify config.yml keys match those used in send() calls.Message Batching
For high-throughput systems, batch messages and send them in a single call (if the broker supports it). Extend StompClient to add batching:
public function sendBatch(string $producer, array $messages): void
{
foreach ($messages as $message) {
$this->send($producer, $message);
}
}
Connection Pooling
Reuse connections instead of creating new ones for each message. The bundle manages this automatically, but avoid frequent connect()/disconnect() calls.
Custom Producers/Consumers Extend the bundle by creating your own producer/consumer services:
class AsyncProducer
{
private $stompClient;
public function __construct(StompClient $stompClient)
{
$this->stompClient = $stompClient;
}
public function sendAsync(string $producer, $message)
{
$this->stompClient->send($producer, $message);
// Add async logic (e.g., Guzzle HTTP callback)
}
}
Message Transformers
Add pre-send transformation logic by implementing Activpik\StompBundle\Message\MessageTransformerInterface and tagging it:
services:
app.message_transformer:
class: AppBundle\Message\MyTransformer
tags: ['activpik_stomp.message_transformer']
Authentication
The bundle lacks built-in auth. Secure your broker (e.g., ActiveMQ) with credentials and extend the Connection class:
$connection = $this->container->get('activpik_stomp.connection_manager')->getConnection('default_connection');
$connection->setLogin('user');
$connection->setPasscode('pass');
Message Validation
Sanitize message payloads to prevent injection (e.g., STOMP header abuse). Use Symfony’s Validator:
$validator = $this->container->get('validator');
$errors = $validator->validate($message->getBody());
if (count($errors) > 0) throw new \RuntimeException('Invalid message');
Mocking the Broker Use a mock STOMP broker (e.g., MockBroker) in PHPUnit:
$mockBroker = new MockBroker();
$container->get('activpik_stomp.connection_manager')->setMockBroker($mockBroker);
Note: The bundle doesn’t natively support mocking; you’ll need to extend Connection or use dependency injection overrides.
Sandbox Testing
Leverage sandbox: true for unit tests, then switch to a real broker in integration tests:
$this->container->get('activpik_stomp')->setSandbox(false); // Toggle programmatically
How can I help you explore Laravel packages today?