LOM-CH Descriptions

A description is a piece of data following the LOM-CH standard. The LOM-CH standard is a superset of the international LOM standard. LOM stands for Learning Object Metadata. It is a standard for representing learning resources, be it books, videos, websites, games, etc. The dsb (Digitale Schulbibliothek) groups many of these descriptions in a large catalog, with an API for searching for descriptions, loading a full description, or even adding new ones.

All communication with the API regarding descriptions requires prior authentication. See Authentication for more information.

Searching descriptions

Adding facets

The API supports something called Faceted Search. Simply put, this allows a search engine to dynamically tell what kind of filtering would be possible for the returned results. This information is then usually used to display some sort of list of options (like checkboxes) which can be displayed on a search form to allow dynamic filtering of the results.

By default, no facets are active, but you can ask the API to compute facets for the current query:

use Educa\DSB\Client\ApiClient\ClientV2;
use Educa\DSB\Client\ApiClient\ClientAuthenticationException;
use Educa\DSB\Client\ApiClient\ClientRequestException;

$client = new ClientV2('https://dsb-api.educa.ch/v2', 'user@site.com', '/path/to/privatekey.pem', 'passphrase');

try {
    $searchResult = $client->authenticate()->search('Cookies', ['learningResourceType']);
} catch(ClientRequestException $e) {
    // The request failed.
} catch(ClientAuthenticationException $e) {
    // The authentication failed.
}

This will compute a list of resource types (text, image, website, etc) that are available for all found results. You may use this information to build a search form, and display these facets as checkboxes. The values of these checkboxes can then be used as filters (more below).

It is possible to pass more than one facet to the Client:

use Educa\DSB\Client\ApiClient\ClientV2;
use Educa\DSB\Client\ApiClient\ClientAuthenticationException;
use Educa\DSB\Client\ApiClient\ClientRequestException;

$client = new ClientV2('https://dsb-api.educa.ch/v2', 'user@site.com', '/path/to/privatekey.pem', 'passphrase');

try {
    $searchResult = $client->authenticate()->search('Cookies', ['learningResourceType', 'educaSchoolLevels']);
} catch(ClientRequestException $e) {
    // The request failed.
} catch(ClientAuthenticationException $e) {
    // The authentication failed.
}

A full list of available facets can be found here. A live-example of how these facets can be used can be found here.

Filtering results

It is possible to add filters to narrow the search down. This is often closely related to facets (see above). A filter is an object, where each property name is a filter name, and its value is an array of possible values. For example, imagine we only want descriptions in German:

use Educa\DSB\Client\ApiClient\ClientV2;
use Educa\DSB\Client\ApiClient\ClientAuthenticationException;
use Educa\DSB\Client\ApiClient\ClientRequestException;

$client = new ClientV2('https://dsb-api.educa.ch/v2', 'user@site.com', '/path/to/privatekey.pem', 'passphrase');

try {
    $searchResult = $client->authenticate()->search('Cookies', [], ['language' => ['de']]);
} catch(ClientRequestException $e) {
    // The request failed.
} catch(ClientAuthenticationException $e) {
    // The authentication failed.
}

This will filter all results and only show ones in German. Multi-value filters are possible as well. Multiple values are treated as OR, not AND:

use Educa\DSB\Client\ApiClient\ClientV2;
use Educa\DSB\Client\ApiClient\ClientAuthenticationException;
use Educa\DSB\Client\ApiClient\ClientRequestException;

$client = new ClientV2('https://dsb-api.educa.ch/v2', 'user@site.com', '/path/to/privatekey.pem', 'passphrase');

try {
    $searchResult = $client->authenticate()->search('Cookies', [], ['learningResourceType' => ['text', 'image']]);
} catch(ClientRequestException $e) {
    // The request failed.
} catch(ClientAuthenticationException $e) {
    // The authentication failed.
}

This will filter by descriptions that are either text-based or image-based (or both).

Additional fields

It is possible to add more fields to the search results. The 4th parameters passed to the client class when searching allows you to specify what more fields should be returned for each search result. For example, the following would add the language and version properties to the result:

use Educa\DSB\Client\ApiClient\ClientV2;
use Educa\DSB\Client\ApiClient\ClientAuthenticationException;
use Educa\DSB\Client\ApiClient\ClientRequestException;

$client = new ClientV2('https://dsb-api.educa.ch/v2', 'user@site.com', '/path/to/privatekey.pem', 'passphrase');

try {
    $searchResult = $client->authenticate()->search('Cookies', [], [], ['language', 'version']);
} catch(ClientRequestException $e) {
    // The request failed.
} catch(ClientAuthenticationException $e) {
    // The authentication failed.
}

Read the API documentation for more information.

Pagination and limiting the number of results

It is possible to offset the results, effectively giving applications a way to support pagination. The offset is the 5th parameter, and represents by how many items the results should be offset (usually a multiple of the 6th parameter, limit; more below). The following will show results 21 to 70 (50 being the default limit):

use Educa\DSB\Client\ApiClient\ClientV2;
use Educa\DSB\Client\ApiClient\ClientAuthenticationException;
use Educa\DSB\Client\ApiClient\ClientRequestException;

$client = new ClientV2('https://dsb-api.educa.ch/v2', 'user@site.com', '/path/to/privatekey.pem', 'passphrase');

try {
    $searchResult = $client->authenticate()->search('Cookies', [], [], [], 20);
} catch(ClientRequestException $e) {
    // The request failed.
} catch(ClientAuthenticationException $e) {
    // The authentication failed.
}

It is also possible to limit the number of results. The following will only show 20 results (instead of 50, the default):

use Educa\DSB\Client\ApiClient\ClientV2;
use Educa\DSB\Client\ApiClient\ClientAuthenticationException;
use Educa\DSB\Client\ApiClient\ClientRequestException;

$client = new ClientV2('https://dsb-api.educa.ch/v2', 'user@site.com', '/path/to/privatekey.pem', 'passphrase');

try {
    $searchResult = $client->authenticate()->search('Cookies', [], [], [], 0, 20);
} catch(ClientRequestException $e) {
    // The request failed.
} catch(ClientAuthenticationException $e) {
    // The authentication failed.
}

Manipulating results

Manipulating this search data might prove cumbersome. This is why there is a special class, called LomDescriptionSearchResult, which can greatly simplify displaying search results. Simply pass the JSON-decoded value to the constructor:

use Educa\DSB\Client\ApiClient\ClientV2;
use Educa\DSB\Client\ApiClient\ClientAuthenticationException;
use Educa\DSB\Client\ApiClient\ClientRequestException;
use Educa\DSB\Client\Lom\LomDescriptionSearchResult;

$client = new ClientV2('https://dsb-api.educa.ch/v2', 'user@site.com', '/path/to/privatekey.pem', 'passphrase');

try {
    $searchResult = $client->authenticate()->search('Cookies', [], [], ['language', 'version']);
} catch(ClientRequestException $e) {
    // The request failed.
} catch(ClientAuthenticationException $e) {
    // The authentication failed.
}

foreach($searchResult['result'] as $lomData) {
    $lomDescription = new LomDescriptionSearchResult($lomData);

    echo $lomDescription->getTitle();
    echo $lomDescription->getTeaser();
    echo $lomDescription->getLomId();
    echo $lomDescription->getPreviewImage();
}

For additional fields, like language and version in our example, you may use the method getField(). This method takes a field name as a parameter:

foreach($searchResult['result'] as $lomData) {
    $lomDescription = new LomDescriptionSearchResult($lomData);

    echo $lomDescription->getField('language');
    echo $lomDescription->getField('version');
}

Of course, this also works for the default fields:

foreach($searchResult['result'] as $lomData) {
    $lomDescription = new LomDescriptionSearchResult($lomData);

    echo $lomDescription->getField('title');
    echo $lomDescription->getField('teaser');
    echo $lomDescription->getField('lomId');
    echo $lomDescription->getField('previewImage');
}

Loading a description

It is possible to load the full data for a resource. This will contain all meta-data, as well as data from the Ontology server.

Ontology data

Ontology data provides human-readable strings for vocabulary entries. For example, a description can have several contributors. Each of these contributors has a role, like author, editor, etc. These are machine-readable names, and are always the same, regardless of which language the description is in. In order to keep the human-readable values, as well as translations, of these vocabulary entries centralized, one can query the Ontology Server. This can be done directly through the API. See Ontology data for more information. However, the API “injects” most if this data directly into the loaded descriptions, which saves us the hassle.

Multilingual descriptions

Because this is communicating with the Swiss national catalog (which has 4 official languages), many descriptions are multilingual. When loading a description, many fields, like title, keyword, etc, can have different values, one per language.

Loading a description

Loading a description requires knowing its LOM identifier. This is a UUID, or a MD5 hash prefixed with archibald### for older versions.

use Educa\DSB\Client\ApiClient\ClientV2;
use Educa\DSB\Client\ApiClient\ClientAuthenticationException;
use Educa\DSB\Client\ApiClient\ClientRequestException;

$client = new ClientV2('https://dsb-api.educa.ch/v2', 'user@site.com', '/path/to/privatekey.pem', 'passphrase');

try {
    $descriptionData = $client->authenticate()->loadDescription('asd89iowqe-sadjqw98-asd87a9doiiuowqe');
} catch(ClientRequestException $e) {
    // The request failed.
} catch(ClientAuthenticationException $e) {
    // The authentication failed.
}

This loads the description data as an associative array into $descriptionData. Look at the API documentation for more information on this data structure.

Manipulating a description

This object can be pretty hard to manipulate. That is where LomDescription comes in. The LomDescription class can take a JSON-decoded LOM-CH data object and expose its properties in a much more convenient way:

use Educa\DSB\Client\ApiClient\ClientV2;
use Educa\DSB\Client\ApiClient\ClientAuthenticationException;
use Educa\DSB\Client\ApiClient\ClientRequestException;
use Educa\DSB\Client\Lom\LomDescription;

$client = new ClientV2('https://dsb-api.educa.ch/v2', 'user@site.com', '/path/to/privatekey.pem', 'passphrase');

$client = new ClientV2('https://dsb-api.educa.ch/v2', 'user@site.com', '/path/to/privatekey.pem', 'passphrase');

try {
    $descriptionData = $client->authenticate()->loadDescription('asd89iowqe-sadjqw98-asd87a9doiiuowqe');
} catch(ClientRequestException $e) {
    // The request failed.
} catch(ClientAuthenticationException $e) {
    // The authentication failed.
}

$lomDescription = new LomDescription($descriptionData);

echo $lomDescription->getTitle();
echo $lomDescription->getDescription();
echo $lomDescription->getLomId();
echo $lomDescription->getPreviewImage();

Fields that contain data in multiple languages can be instructed to return the information in one language only by specifying a language fallback array. The first language that matches will be returned. If no match is found, the field will be returned in “raw” format (meaning, multilingual fields will be returned as an associative array, with field values keyed by language).

// This will first look for a German title, then fallback to French and
// finally Italian.
echo $lomDescription->getTitle(['de', 'fr', 'it']);

// This will look for French first and fallback to English.
echo $lomDescription->getDescription(['fr', 'en']);

Not all fields have shortcut methods. For fields that the LomDescriptionInterface interface does not define shortcuts for, you can use the getField() method. For nested fields, use a dot (.) notation:

echo $lomDescription->getField('lomId');

// Use a dot (.) notation to fetch nested fields.
echo $lomDescription->getField('lifeCycle.version');

// Fields that are arrays can use numeric field names to get specific items.
echo $lomDescription->getField('technical.keyword.0');

// Fields that are multilingual can use a language fallback array as the
// second parameter.
echo $lomDescription->getField('general.title', ['de', 'fr']);

Creating a new description

todo

Updating a description

todo

Validating a description

It is possible to validate a description to check if no mandatory fields are missing, that they are well formed and respect the LOM-CH standard. Look at the API documentation for more information on this data structure.

Simple validation script:

$client = new ClientV2('https://dsb-api.educa.ch/v2', 'user@site.com', '/path/to/privatekey.pem', 'passphrase');

// Load a json file containing the LOM object
$f = 'lom_object.json';
try {
    $json = file_get_contents($f);
    $result = $client->authenticate()->validateDescription($json);
    echo "Using file $f\n";
    if (!empty($response['valid'])) {
        echo "\n> Description is valid.";
    } else {
        echo "\n> Description is invalid.\n";
        echo "\nServer response:\n";
        echo "==============================\n";
        print_r($response);
        echo "==============================\n";
    }
} catch(ClientRequestException $e) {
    // The request failed.
    print "The post request failed. (" . $e->getMessage() . ')';
} catch(ClientAuthenticationException $e) {
    // The authentication failed.
    print "The authentification failed. (" . $e->getMessage() . ')';
}
echo "\n";

Response syntax

The response will always contain a valid key, which is a boolean.

If the submitted LOM object is invalid, the errors key will be populated with a list of issues.

In case of an invalid LOM object, the API will return:

{"valid":false,"message":"Description is not complete or not compliant.","errors":{"general.identifier":"missing","general.description":"missing","general.language":"missing"}}

The client returns a JSON decoded array:

Array
(
    [valid] =>
    [message] => Description is not complete or not compliant.
    [errors] => Array
        (
            [general.identifier] => missing
            [general.description] => missing
            [general.language] => missing
        )

)