dbp/relay-base-organization-connector-campusonline-bundle
Install the Bundle
composer require dbp/relay-base-organization-connector-campusonline-bundle
Register the Bundle
Add to config/bundles.php:
Dbp\Relay\BaseOrganizationBundle\DbpRelayBaseOrganizationBundle::class => ['all' => true],
Dbp\Relay\BaseOrganizationBundle\DbpRelayBaseOrganizationConnectorCampusonlineBundle::class => ['all' => true],
Configure Environment Variables
Define these in .env:
CAMPUS_ONLINE_API_TOKEN=your_api_token_here
CAMPUS_ONLINE_API_URL=https://api.campusonline.example
ORGANIZATION_ROOT_ID=123
Create Config File
Generate config/packages/dbp_relay_base_organization_connector_campusonline.yaml with:
dbp_relay_base_organization_connector_campusonline:
campus_online:
api_token: '%env(CAMPUS_ONLINE_API_TOKEN)%'
api_url: '%env(CAMPUS_ONLINE_API_URL)%'
org_root_id: '%env(ORGANIZATION_ROOT_ID)%'
Clear Cache
php bin/console cache:clear
Test API Integration Trigger a sync or query an organization endpoint to verify data flows from CampusOnline.
Use the OrganizationPostEvent to enrich organization data from CampusOnline:
// In a service or event subscriber
use Dbp\Relay\BaseOrganizationBundle\Event\OrganizationPostEvent;
public function onOrganizationPost(OrganizationPostEvent $event)
{
$organization = $event->getOrganization();
$campusData = $this->campusOnlineService->fetchOrganizationDetails($organization->getId());
$event->addLocalData([
'campusonline' => [
'name' => $campusData['name'],
'type' => $campusData['type'],
'external_id' => $campusData['id'],
]
]);
}
Event-Driven Enrichment
Subscribe to OrganizationPostEvent to inject CampusOnline-specific fields into the base Organization entity.
Example:
// src/EventListener/CampusOnlineOrganizationListener.php
class CampusOnlineOrganizationListener
{
public function __invoke(OrganizationPostEvent $event)
{
$event->addLocalData($this->fetchCampusOnlineData($event->getOrganization()));
}
}
Register in services.yaml:
services:
App\EventListener\CampusOnlineOrganizationListener:
tags:
- { name: kernel.event_listener, event: organization.post, method: __invoke }
Bulk Sync via API
Use the bundle’s CampusOnlineClient to fetch organizations in batches:
$client = $this->container->get('dbp_relay.base_organization_connector.campusonline.client');
$organizations = $client->fetchOrganizations($this->config['org_root_id']);
Caching Responses Cache API responses to avoid rate-limiting or redundant calls:
$cache = $this->container->get('cache.app');
$key = 'campusonline_org_' . $orgId;
$data = $cache->get($key) ?: $client->fetchOrganization($orgId);
$cache->set($key, $data, 3600); // Cache for 1 hour
Leverage Relay’s Base Entities
Extend \Dbp\Relay\BaseOrganizationBundle\Entity\Organization to include CampusOnline-specific fields:
#[ORM\Entity]
class Organization extends BaseOrganization
{
#[ORM\Column(nullable: true)]
private ?string $campusOnlineExternalId = null;
// Getters/setters...
}
Use DTOs for API Responses Transform CampusOnline API responses into Relay-compatible DTOs:
class CampusOnlineOrganizationDto
{
public function __construct(
public string $id,
public string $name,
public string $type,
public array $localData
) {}
}
Error Handling Centralize API error handling in a decorator or middleware:
class CampusOnlineClientDecorator implements CampusOnlineClientInterface
{
public function fetchOrganization(string $id): array
{
try {
return $this->client->fetchOrganization($id);
} catch (ApiException $e) {
$this->logger->error('CampusOnline API error', ['error' => $e->getMessage()]);
throw new \RuntimeException('Failed to fetch organization from CampusOnline');
}
}
}
Async Processing Use Symfony Messenger for background syncs:
$message = new SyncCampusOnlineOrganizationsMessage($rootId);
$this->messageBus->dispatch($message);
API Rate Limiting
GuzzleHttp\HandlerStack with a retry middleware.Data Mismatches
org_root_id and log discrepancies during sync.Event Ordering
OrganizationPostEvent fires after the entity is persisted. Avoid circular dependencies.OrganizationPrePersistEvent for pre-save logic if needed.Configuration Overrides
%env() in YAML and validate with ParameterBag.Enable API Logging
Add to config/packages/monolog.yaml:
handlers:
campusonline:
type: stream
path: "%kernel.logs_dir%/campusonline.log"
level: debug
channels: ["campusonline"]
Log API calls in the client:
$this->logger->debug('Fetching org', ['id' => $id, 'url' => $this->apiUrl]);
Validate API Responses Use a schema validator for CampusOnline responses:
use Symfony\Component\Validator\Constraints as Assert;
$response = $client->fetchOrganization($id);
$validator = $this->container->get('validator');
$errors = $validator->validate($response, new Assert\Collection([
'id' => new Assert\NotBlank(),
'name' => new Assert\NotBlank(),
]));
Test Locally with Mocks
Replace the CampusOnlineClient with a mock in tests:
$mockClient = $this->createMock(CampusOnlineClientInterface::class);
$mockClient->method('fetchOrganization')->willReturn(['id' => '123', 'name' => 'Test Org']);
$this->container->set('dbp_relay.base_organization_connector.campusonline.client', $mockClient);
Custom Sync Logic
Override the bundle’s SyncOrganizationsCommand:
class CustomSyncCommand extends SyncOrganizationsCommand
{
protected function configure(): void
{
$this->setName('app:sync-campusonline-orgs');
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
// Custom logic (e.g., filter organizations)
$filteredOrgs = $this->filterOrganizations($this->fetchAll());
return parent::execute($input, $output);
}
}
Add New API Endpoints
Extend the bundle’s CampusOnlineClient to support additional CampusOnline features:
class ExtendedCampusOnlineClient implements CampusOnlineClientInterface
{
public function fetchOrganizationMembers(string $orgId): array
{
return $this->httpClient->request('GET', "/orgs/{$orgId}/members");
}
}
Webhook Integration Listen for CampusOnline webhooks to trigger real-time syncs:
// src/EventListener/CampusOnlineWebhookListener.php
class CampusOnlineWebhookListener
{
public function __invoke(WebhookEvent $event)
{
if ($event->getType() === 'organization.updated') {
$this->syncOrganization($event->getData()['id']);
}
}
}
GraphQL Extensions Add CampusOnline-specific fields to Relay’s GraphQL schema:
type Organization {
campusOnlineExternalId
campusOnlineType
How can I help you explore Laravel packages today?