Installation
composer require dbp/relay-nexus-bundle
Add the bundle to config/bundles.php:
return [
// ...
DigitalBlueprint\RelayNexusBundle\DbpRelayNexusBundle::class => ['all' => true],
];
Configuration
Create config/packages/dbp_relay_nexus.yaml with a minimal setup:
dbp_relay_nexus:
topics:
- "https://your-app.org/topic.metadata.json"
typesense:
api_url: "%env(NEXUS_TYPESENSE_API_URL)%"
api_key: "%env(NEXUS_TYPESENSE_API_KEY)%"
First Use Case
TopicManager service to load topic metadata:
$topicManager = $this->container->get('dbp_relay_nexus.topic_manager');
$topics = $topicManager->getTopics();
TypesenseClient:
$typesense = $this->container->get('dbp_relay_nexus.typesense_client');
$results = $typesense->search('query', 'collection_name');
Topic Management
cache/ for performance:
dbp_relay_nexus:
topics:
- "https://app1.org/topic.metadata.json"
- "https://app2.org/topic.metadata.json"
cache_topics: true # Enable caching (default: false)
TopicValidator to enforce custom metadata schemas:
// src/Service/TopicValidator.php
class CustomTopicValidator extends TopicValidator {
public function validate(array $metadata): bool {
// Add custom rules
return parent::validate($metadata);
}
}
Register in services.yaml:
services:
dbp_relay_nexus.topic_validator: '@App\Service\CustomTopicValidator'
Typesense Integration
$results = $typesense->search('laravel', 'documents', [
'query_by' => 'title,content',
'per_page' => 10,
]);
$typesense->createCollection('new_collection', [
'name' => 'new_collection',
'fields' => [
['name' => 'title', 'type' => 'string'],
['name' => 'content', 'type' => 'string'],
],
]);
Authorization
AuthorizationManager:
// src/Service/AuthorizationManager.php
class CustomAuthorizationManager extends AuthorizationManager {
protected function resolveRole(string $role): bool {
// Custom logic (e.g., check DB, external API)
return $role === 'ROLE_ADMIN';
}
}
NexusAuthenticator:
// src/Kernel.php
protected $middlewareAliases = [
'nexus.auth' => \DigitalBlueprint\RelayNexusBundle\Middleware\NexusAuthenticator::class,
];
Event-Driven Architecture
// src/EventListener/TopicUpdateListener.php
class TopicUpdateListener {
public function onTopicUpdated(TopicUpdatedEvent $event) {
// React to changes (e.g., log, notify frontend)
}
}
Register in services.yaml:
services:
App\EventListener\TopicUpdateListener:
tags:
- { name: 'kernel.event_listener', event: 'dbp_relay_nexus.topic.updated' }
Frontend Sync
// Example: Poll for topic changes
setInterval(async () => {
const response = await fetch('/api/nexus/topics');
const topics = await response.json();
// Update UI
}, 30000);
Caching Strategies
# config/packages/cache.yaml
framework:
cache:
app: cache.adapter.redis
Wrap Typesense calls:
$cache = $this->container->get('cache.app');
$cacheKey = 'typesense:query:' . md5($query);
$results = $cache->get($cacheKey, function() use ($typesense, $query) {
return $typesense->search($query, 'collection');
});
Testing
TopicManager and TypesenseClient in PHPUnit:
$this->mockBuilder()
->getContainer()
->andReturnSelf()
->get('dbp_relay_nexus.topic_manager')
->andReturn($this->createMock(TopicManager::class));
Topic Metadata Format
topic.metadata.json to follow a strict schema. Validate locally before deploying:
php bin/console debug:container dbp_relay_nexus.topic_validator | grep -A5 "validate"
id or name fields.actions array structure (must include method and endpoint).Typesense Configuration
search, create, and delete permissions for collections.try {
$results = $typesense->search($query);
} catch (TypesenseException $e) {
if ($e->getCode() === 429) {
sleep(2 ** $attempt++);
retry();
}
throw $e;
}
Authorization Quirks
dbp_relay_nexus.yaml. Override AuthorizationManager::resolveRoles() to customize:
public function resolveRoles(UserInterface $user): array {
$roles = parent::resolveRoles($user);
// Add dynamic roles (e.g., from DB)
$roles[] = 'ROLE_' . strtoupper($user->getDepartment());
return array_unique($roles);
}
ROLE_USER depends on ROLE_DEVELOPER which depends on ROLE_USER).Performance
cache_topics: true and preload in a command:
// src/Command/PreloadTopicsCommand.php
class PreloadTopicsCommand extends Command {
protected function execute(InputInterface $input, OutputInterface $output) {
$topicManager = $this->getContainer()->get('dbp_relay_nexus.topic_manager');
$topicManager->preloadTopics();
$output->writeln('Topics preloaded!');
}
}
Register as a cron job:
* * * * * php bin/console app:preload-topics
Enable Debug Mode
Add to config/packages/dev/dbp_relay_nexus.yaml:
dbp_relay_nexus:
debug: true
var/log/dev.log.var/log/debug.log.Common Errors
| Error | Solution |
|---|---|
TopicNotFoundException |
Verify topic URLs in dbp_relay_nexus.yaml and network connectivity. |
TypesenseConnectionException |
Check NEXUS_TYPESENSE_API_URL and key permissions. |
AuthorizationException |
Debug role resolution with var_dump($this->get('security.token_storage')->getToken()->getRoles()). |
Extension Points
TopicSourceInterface for non-HTTP sources (e.g., database):
class DatabaseTopicSource implements TopicSourceInterface {
public function getTopics(): array {
return $this->
How can I help you explore Laravel packages today?