cerpus/edlib-resource-kit

Create resource types for Edlib

v0.5.0 2022-12-08 14:03 UTC

This package is auto-updated.

Last update: 2024-04-26 14:18:24 UTC


README

codecov

Create custom content types for Edlib.

Requirements

  • PHP 8.2
  • A PSR-17 implementation, e.g. guzzlehttp/psr7
  • A PSR-18 compatible HTTP client, e.g. Guzzle 7
  • Network access to Edlib internal services
  • A RabbitMQ instance shared with Edlib (optional)

Installation

composer require cerpus/edlib-resource-kit guzzlehttp/guzzle:^7 guzzlehttp/psr7

Usage (Edlib 3)

Rather than communicating via bespoke APIs over private network connections, Edlib 3 is notified of new content via the LTI Content-Item Message standard. Edlib Resource Kit provides message objects, mappers, and serialisers for working with Content-Item messages.

Mapping

Map serialised Content-Item graphs to message objects:

use Cerpus\EdlibResourceKit\Lti\Lti11\Mapper\DeepLinking\ContentItemsMapper;

$mapper = new ContentItemsMapper();
$items = $mapper->map(<<<EOJSON
{
    "@context": "http://purl.imsglobal.org/ctx/lti/v1/ContentItem",
    "@graph": [
        {
            "@type": "LtiLinkItem",
            "mediaType": "application/vnd.ims.lti.v1.ltilink",
            "title": "My Cool LTI Content",
            "url": "https://example.com/my-lti-content"
        }
    ]
}
EOJSON);

echo count($items), "\n"; // 1
echo $items[0]->getTitle(), "\n"; // My Cool LTI Content

The JSON input must match the compacted JSON-LD representation, as can be seen in the LTI Deep Linking 1.0 specification. If the input does not match, a JSON-LD processor can be used to make the input compliant.

Serialisation

Convert Content-Item message objects to their serialised JSON representations:

use Cerpus\EdlibResourceKit\Lti\Message\DeepLinking\LtiLinkItem;
use Cerpus\EdlibResourceKit\Lti\Lti11\Serializer\DeepLinking\ContentItemsSerializer;

$items = [
    new LtiLinkItem(
        mediaType: 'application/vnd.ims.lti.v1.ltilink',
        title: 'My Cool LTI Content',
        url: 'https://example.com/my-lti-content',
    ),
];

$serializer = new ContentItemsSerializer();
$serialized = $serializer->serialize($items);

echo json_encode($serialized);

Output:

{
    "@context": "http://purl.imsglobal.org/ctx/lti/v1/ContentItem",
    "@graph": [
        {
            "@type": "LtiLinkItem",
            "mediaType": "application/vnd.ims.lti.v1.ltilink",
            "title": "My Cool LTI Content",
            "url": "https://example.com/my-lti-content"
        }
    ]
}

Usage (old Edlib)

Framework integration

We provide integration with Laravel that simplifies use of this package.

Configuration

There are two ways of making Edlib aware of new resources:

  • Using the message bus
  • Synchronous HTTP request

The HTTP approach is slower, but waits for the publishing of a resource to be completed, allowing for error handling.

When using the message bus approach, a RabbitMQ connection must be provided:

use Cerpus\EdlibResourceKit\ResourceKit;
use Cerpus\PubSub\Connection\ConnectionFactory;

$connectionFactory = new ConnectionFactory('localhost', 5672, 'guest', 'guest');
$resourceKit = new ResourceKit($connectionFactory);

For the HTTP approach, other than providing the synchronousResourceManager flag, there is no mandatory configuration:

use Cerpus\EdlibResourceKit\ResourceKit;

$resourceKit = new ResourceKit(synchronousResourceManager: true);

Once you have a ResourceKit instance, you can begin to access the various components of it:

$resourceManager = $resourceKit->getResourceManager();
$versionManager = $resourecKit->getResourceVersionManager();

Notifying Edlib of content updates

Given a model class representing an item of your custom content type (in this case an article):

namespace App\Models;

use Cerpus\EdlibResourceKit\Contract\EdlibResource;

class Article
{
    // Database-mapped article ID
    private string $id;

    public function toEdlibResource(): EdlibResource
    {
        return new ArticleEdlibResource($this->id, /* ... */);
    }
}

Create an accompanying EdlibResource class:

namespace App\DataObjects;

use Cerpus\EdlibResourceKit\Contract\EdlibResource;

class ArticleEdlibResource implements EdlibResource
{
    public function __construct(private string $systemId, /* ... */)
    {
    }

    public function getSystemName(): string
    {
        return 'my-unique-and-persistent-system-name';
    }

    public function getSystemId(): string
    {
        return $this->systemId;
    }

    public function getContentType(): string|null
    {
        return 'article';
    }

    // ... implement the remaining EdlibResource methods here
}

When the article is created or updated, a corresponding call to the resource manager must take place. The procedure will vary depending on your framework of choice, but here it is demonstrated using the observer pattern:

use Cerpus\EdlibResourceKit\Contract\EdlibResource;
use Cerpus\EdlibResourceKit\Resource\ResourceManagerInterface;

class ArticleObserver
{
    public function __construct(private ResourceManagerInterface $manager)
    {
    }

    public function onCreate(Article $article): void
    {
        $this->save($article->toEdlibResource());
    }

    public function onUpdate(Article $article): void
    {
        $this->save($article->toEdlibResource());
    }

    private function save(EdlibResource $resource): void
    {
        try {
            return $this->manager->save($resource);
        } catch (ResourceSaveFailedException $e) {
            // handle the failure somehow
        }
    }
}

If everything went well, the resource should now be accessible from within Edlib.

Advanced usage

Overriding the HTTP client & message factories

This library will look for and make use of any PSR-17 compatible message factories and PSR-18 compatible HTTP clients that are installed (via HTTPlug Discovery). You can override these with factories & clients of your choosing:

use App\Http\MyClient;
use App\Http\MyRequestFactory;
use App\Http\MyStreamFactory;
use Cerpus\EdlibResourceKit\ResourceKit;

$resourceKit = new ResourceKit(
    httpClient: new MyClient(),
    requestFactory: new MyRequestFactory(),
    streamFactory: new MyStreamFactory(),
    synchronousResourceManager: true,
);

By wiring up the HTTP client provided by your web framework, you may get better logging & debugging capabilities.

Adding extra data when publishing resources

It might be necessary to add extra data to a resource before publishing it. This can be done using a custom serializer:

use Cerpus\EdlibResourceKit\Contract\EdlibResource;
use Cerpus\EdlibResourceKit\ResourceKit;
use Cerpus\EdlibResourceKit\Serializer\ResourceSerializer;

class MySerializer extends ResourceSerializer
{
    public function serialize(EdlibResource $resource): array
    {
        $data = parent::serialize($resource);

        if ($resource instanceof MyEdlibResource) {
            $data['some_custom_key'] => $resource->getMyCustomData();
        }

        return $data;
    }
}

$resourceKit = new ResourceKit($pubSub, resourceSerializer: new MySerializer());

License

This package is released under the GNU General Public License 3.0. See the LICENSE file for more information.