dbp/relay-educationalcredentials-bundle
Installation:
composer require dbp/relay-educationalcredentials-bundle=dev-main
Ensure the repository is added to composer.json as shown in the README.
Bundle Registration:
Add to config/bundles.php:
Dbp\Relay\EducationalcredentialsBundle\DbpRelayEducationalcredentialsBundle::class => ['all' => true],
Configuration:
Create config/packages/dbp_relay_educationalcredentials.yaml with:
dbp_relay_educationalcredentials:
issuer: "did:ebsi:abc123" # Replace with your DID
urlIssuer: "http://localhost:13080/1.0/credentials/issue"
urlVerifier: "http://localhost:14080/1.0/credentials/verify"
First Use Case: Issue a credential for a user via the API:
use Dbp\Relay\EducationalcredentialsBundle\Service\CredentialService;
$credentialService = $this->container->get(CredentialService::class);
$credential = $credentialService->issueCredential(
userId: 1,
credentialType: 'Diploma',
data: ['degree' => 'BSc Computer Science', 'year' => 2023]
);
Issuing Credentials:
CredentialService to generate verifiable credentials (e.g., diplomas).degree, year).$credential = $credentialService->issueCredential(
userId: $user->id,
credentialType: 'Diploma',
data: ['institution' => 'University X', 'date' => '2023-05-15']
);
Verification:
CredentialService to verify credentials via the configured verifier endpoint:
$isValid = $credentialService->verifyCredential($credential->getId());
Integration with API Routes:
// src/Controller/CredentialController.php
use Dbp\Relay\EducationalcredentialsBundle\Service\CredentialService;
class CredentialController extends AbstractController {
public function issue(CredentialService $service, Request $request) {
$data = $request->request->all();
return $service->issueCredential($data['user_id'], $data['type'], $data['data']);
}
}
Event-Driven Workflows:
// src/EventListener/GraduationListener.php
use Dbp\Relay\EducationalcredentialsBundle\Service\CredentialService;
class GraduationListener {
public function __construct(private CredentialService $service) {}
public function onGraduation(GraduationEvent $event) {
$this->service->issueCredential(
$event->getUserId(),
'Diploma',
['degree' => $event->getDegree()]
);
}
}
Database Storage:
Store issued credentials in a credentials table with fields like id, user_id, type, data, and verifiable_credential (JSON).
Example migration:
Schema::create('credentials', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained();
$table->string('type');
$table->json('data');
$table->json('verifiable_credential');
$table->timestamps();
});
API Responses: Return issued credentials in a standardized format:
{
"id": "cred_123",
"type": "Diploma",
"data": { "degree": "BSc CS", "year": 2023 },
"verifiable_credential": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Testing:
Mock CredentialService in unit tests:
$mockService = $this->createMock(CredentialService::class);
$mockService->method('issueCredential')->willReturn($mockCredential);
$this->container->set(CredentialService::class, $mockService);
DID Configuration:
issuer (DID) in config/packages/dbp_relay_educationalcredentials.yaml is not recommended for production. Always use environment variables (%env(VC_ISSUER)%) to avoid exposing sensitive data in version control.did:ebsi:...) before issuing credentials to prevent runtime errors.Endpoint Dependencies:
urlIssuer, urlVerifier). Ensure these services are always available during credential operations. Implement retries or fallback logic for transient failures:
try {
$credential = $service->issueCredential(...);
} catch (ConnectException $e) {
$this->retryLater();
}
Credential Data Validation:
data passed to issueCredential. Sanitize inputs to prevent malformed credentials:
$validatedData = $request->validate([
'degree' => 'required|string|max:255',
'year' => 'required|integer|min:1900|max:' . (date('Y') + 1),
]);
Caching:
urlVerifier may be rate-limited. Cache verification results (e.g., in Redis) to avoid redundant calls:
$cacheKey = "vc_verification:{$credentialId}";
if ($cached = cache()->get($cacheKey)) {
return $cached;
}
$result = $service->verifyCredential($credentialId);
cache()->put($cacheKey, $result, now()->addHours(1));
return $result;
Logging:
Enable debug logging for the bundle by adding to config/packages/monolog.yaml:
handlers:
relay_educationalcredentials:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.relay_credentials.log"
level: debug
Then configure the bundle to use this channel in its services.
Common Errors:
config/packages/dbp_relay_educationalcredentials.yaml for missing or invalid issuer/urlIssuer values.urlVerifier endpoint is reachable and returns valid JSON. Test with curl:
curl -X POST http://localhost:14080/1.0/credentials/verify -H "Content-Type: application/json" -d '{"credential": "..."}'
Custom Credential Types: Extend the bundle to support additional credential types (e.g., "Certificate") by creating a custom service:
class CustomCredentialService extends AbstractCredentialService {
protected function getCredentialType(): string {
return 'Certificate';
}
}
Register it as a service alias in services.yaml:
services:
App\Service\CustomCredentialService:
tags: ['dbp.relay.educationalcredentials.service']
Pre/Post-Issue Hooks: Use Symfony events to intercept credential issuance:
// config/services.yaml
services:
App\EventSubscriber\CredentialSubscriber:
tags:
- { name: kernel.event_subscriber }
// src/EventSubscriber/CredentialSubscriber.php
class CredentialSubscriber implements EventSubscriberInterface {
public static function getSubscribedEvents() {
return [
CredentialIssuedEvent::class => 'onCredentialIssued',
];
}
public function onCredentialIssued(CredentialIssuedEvent $event) {
// Send email, log, or trigger other actions
}
}
Testing the Bundle:
Override the ConfigService in tests to mock external endpoints:
$this->container->set('dbp_relay_educationalcredentials.config_service', function () {
$config = new ConfigService();
$config->setIssuer('did:test:123');
$config->setUrlIssuer('http://test-issuer.com');
return $config;
});
How can I help you explore Laravel packages today?