Search by

isy-thl / european-learning-model

isy-thl

Framework-independent European Learning Model document models and deterministic serializers.

Package info

github.com/ild-thl/php-european-learning-model

pkg:composer/isy-thl/european-learning-model

Statistics

Installs: 21

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.5.0 2026-10-30 22:35 UTC

This package is auto-updated.

Last update: 2026-10-30 22:36:54 UTC


README

isy-thl/european-learning-model is a framework-independent PHP package for building European Learning Model (ELM) documents and deterministic unsigned JSON-LD. It currently focuses on European Digital Credentials (EDC), with shared ELM entities and incremental Learning Opportunities and Qualifications (LOQ) support.

The package produces document bytes. An application owns persistence, QDR delivery, HTTP, logging, and signing.

Current scope

The package currently provides:

  • shared ELM values and graph entities under Core;
  • EDC credentials, subjects, claims, displays, issuers, and profile validation under Edc;
  • LOQ qualifications, learning opportunities, references, document roots, and profile preflight validation under Loq;
  • controlled concepts, localized values, identifiers, dates, and vocabulary provider contracts; and
  • deterministic JSON-LD serialization with typed validation failures.

The package does not provide:

  • Framework specific adapters or database integration.
  • QDR HTTP clients, upload, hosting, API keys, or publication workflows;
  • DSS, CSC, JAdES, certificates, private keys, signatures, or proofs; or
  • a verified LOQ XML serializer.

EDC output is unsigned JSON-LD suitable for an application to pass unchanged to a separate signing boundary such as isy-thl/dss-csc-signing.

Requirements

  • PHP 8.1 or newer
  • PHP mbstring extension
  • Composer

Development and vocabulary-provider tests may also require PHP DOM/XML extensions.

Installation

composer require isy-thl/european-learning-model

The package namespace is IsyThl\EuropeanLearningModel.

Build an EDC credential

The main output is deterministic unsigned JSON-LD. Required child objects are constructed explicitly, and Credential::toJson() performs document validation before returning bytes.

use DateTimeImmutable;
use IsyThl\EuropeanLearningModel\Core\Concept;
use IsyThl\EuropeanLearningModel\Core\ConceptScheme;
use IsyThl\EuropeanLearningModel\Core\ElmVocabularySchemes;
use IsyThl\EuropeanLearningModel\Core\LocalizedString;
use IsyThl\EuropeanLearningModel\Edc\Claim;
use IsyThl\EuropeanLearningModel\Edc\Credential;
use IsyThl\EuropeanLearningModel\Edc\CredentialSubject;
use IsyThl\EuropeanLearningModel\Edc\DisplayParameter;

$english = new Concept(
	'http://publications.europa.eu/resource/authority/language/ENG',
	new LocalizedString(['en' => 'English']),
	new ConceptScheme(ElmVocabularySchemes::LANGUAGE),
	'language',
);

$subject = new CredentialSubject(
	'subject-1',
	new LocalizedString(['en' => 'Ada']),
	new LocalizedString(['en' => 'Lovelace']),
	new LocalizedString(['en' => 'Ada Lovelace']),
	[new class ('claim-1') extends Claim {
		public function toArray(): array {
			return ['id' => $this->id, 'type' => 'Claim'];
		}
	}],
);

$credential = new Credential(
	'credential-1',
	$subject,
	new DisplayParameter(
		'display-1',
		$english,
		$english,
		new LocalizedString(['en' => 'European Digital Credential']),
	),
	new DateTimeImmutable('2026-01-01T00:00:00+00:00'),
);

$unsignedJsonLd = $credential->toJson();

Equivalent object state produces byte-for-byte identical output. Dates are normalized to UTC and emitted as Y-m-d\TH:i:s\Z; unset optional fields are omitted. JSON encoding uses explicit flags and JSON_THROW_ON_ERROR.

Profiles and validation

EDC and LOQ validation are separate profile concerns:

  • EdcProfile::GENERIC_NO_CV and EdcProfile::GENERIC_FULL identify the supported EDC profiles and their bundled RDF resources.
  • EdcDocumentValidator checks the EDC document root and selected profile. It can also invoke an injected StandardsValidatorInterface with the matching bundled profile resource, and rejects non-conforming results.
  • LoqProfileValidator checks LOQ-specific identifiers, publisher metadata, default language, learning outcomes, EQF, NQF, and ISCED-F requirements.
  • LoqDocumentValidator validates LOQ document aggregates before serialization.

The built-in EDC checks are structural preflight checks. Full RDF/JSON-LD/SHACL execution requires both a StandardsValidatorInterface implementation and a ProfileResourceRegistryInterface; pass both to EdcDocumentValidator to enable it. Credential::toJson() performs structural checks only and does not claim full SHACL conformance. The package does not currently ship a concrete SHACL execution engine.

The EDC generic profile targets every Person and requires at least one hasClaim, including people who are not the credential subject. The package can represent a person without claims, for example as a learning activity director, but that person will fail validation against the unmodified profile. Using an Agent instead avoids that constraint but does not identify the agent as a person. The package does not add claims or modify the official shapes.

Profile resources are bundled under resources/profile/ and are loaded by explicit local resource boundaries. Constructors, validators, and serializers do not retrieve profiles or vocabularies from the network.

LOQ documents

TODO

Controlled vocabularies

For small, trusted vocabularies, use InMemoryVocabularyProvider and a VocabularyScheme. For injected RDF or JSON resources, use RdfVocabularyProvider or JsonLdVocabularyProvider with an application-owned VocabularyResourceFetcher. For large schemes, use the bounded search providers under Vocabulary, including the ESCO search provider.

EuropassVocabularyProvider loads SNB vocabularies from the EU publications authority using an injected PSR-18 client and PSR-17 request factory. Configure the client with finite connection and request timeouts, streaming response bodies, and redirects disabled. The provider limits response sizes, enrichment requests, and the time budget for each scheme load. Applications own caching and HTTP client configuration; construction does not access the network.

Vocabulary access is explicit and injectable. See the working examples:

  • examples/vocabulary-selection.php
  • examples/vocabulary-providers.php
  • examples/esco-search.php

Development and testing

composer install
composer test
composer analyse
composer style
composer lint
composer validate --strict
git diff --check

The test suite is plain PHP and does not require Moodle, QDR, DSS, CSC, or network services. Optional live vocabulary qualification requires network access and can be run separately:

ELM_LIVE_VOCABULARY_TESTS=1 vendor/bin/phpunit tests/LiveVocabularyTest.php

License

GPL-3.0-or-later