Create a publisher package

This guide will explain how publishers are created within Alumio. A publisher should be installed through composer before it is used in Alumio. Start by setting up the following files for the publisher package.

.
├── src
│ └── MyPublisher.php
├── magement
│ └── my-publisher.prototype.json
├── composer.json

These are all the files that are required to create a publisher package for Alumio. It is recommended to use as much mechanics that are built in Alumio when creating a publisher. For example if a publisher exports data to a file storage, then it is recommended to not use functions like file_put_contents. Alumio can already supply a Storage class to the publisher.

 

Composer

File: vendor/*/*/composer.json

The minimal composer.json file should look something like:

{
"name": "acme/my-publisher",
"description": "My Alumio Publisher.",
"type": "library",
"license": "proprietary",
"prefer-stable": true,
"minimum-stability": "stable",
"require": {
"php": "^7.3",
"magement/publisher-api": "^1.0@RC"
},
"autoload": {
"psr-4": {
"Acme\\MyPublisher\\Publisher\\": "src"
}
}
}

In this setup the required package magement/publisher-api is added, because this package contains the required interface (Magement\Publisher\PublisherInterface) for creating a publisher.

To quickly create a new composer project, run the command composer init to get an interactive setup.

Additional dependencies

This example requires 2 additional packages, namely:

{
"magement/entity-api": "^1.0",
"magement/storage": "^4.0"
}

The package magement/entity-api will provide interfaces and implementations to resolve entities their identifiers, which is needed for the current example. It is not an explicit requirement for every publisher.

The package magement/storage will provide interfaces and implementations for using storages.

 

Publisher implementation

File: vendor/*/*/src/MyPublisher.php

In the file MyPublisher.php, the actual publisher logic will be implemented. This file should contain a class which implements the Magement\Publisher\PublisherInterface.

This will add the method __invoke to the class with the parameter $entity with the type array. This array contains the data of a single entity, which needs to be published.

All the parameters from the __construct method of the publisher should be configured in the schema. If for example a Storage should be supplied to the class, then it will still be a string in the schema. However in the constructor it must have the type-hint of the StorageInterface in order for Alumio to detect that it needs to supply a Storage. This will be based on the supplied string identifier for the parameter.

Other classes can also be supplied to the publisher through dependency injection. It is common for a publisher to having to supply an identity to their endpoint. The entity can be retrieved from the entities by using the EntityIdentityResolverInterface. This class has the method __invoke which expects an entity. The resolver will then return the assigned identifier based on the schema.

In this example the class would look like this:

<?php
/**
* Copyright Alumio. All rights reserved.
* https://www.alumio.com
*/

namespace Acme\MyPublisher\Publisher;

use Magement\Publisher\PublisherInterface;
use Magement\Publisher\PublisherInputInterface;
use Magement\Storage\StorageInterface;
use Magement\Entity\IdentifierResolver\EntityIdentityResolverInterface;
use Magement\Entity\Entity;

class MyPublisher implements PublisherInterface
{
/** @var StorageInterface */
private $storage;

/** @var EntityIdentityResolverInterface */
private $entityIdentityResolver;

/** @var string */
private $entityType;

/**
* Constructor
*
* @param StorageInterface $storage
* @param EntityIdentityResolverInterface $entityIdentityResolver
* @param string $entityType
*/
public function __construct(
StorageInterface $storage,
EntityIdentityResolverInterface $entityIdentityResolver,
string $entityType
) {
$this->storage = $storage;
$this->entityIdentityResolver = $entityIdentityResolver;
$this->entityType = $entityType;
}

/**
* Publish an entity.
*
* @param array $entity
*
* @return void
*/
public function __invoke(array $entity): void
{
$this->storage->set(
$this->resolver->resolve(
new Entity(
$this->entityType,
$entity
)
),
$entity
);
}
}

 

Registering the publisher
File: vendor/*/*/magement/my-publisher.prototype.json

The registration file is used to tell Alumio that this package contains prototype for Alumio. This file will be read and cached. Prototype files are used to determine a framework for registrating configuration in DI. The registration file will look something like:

{
"$schema": "https://di.schema.mediact.com/register.prototype.json",
"type": "publisher",
"identifier": "my-publisher",
"name": "My publisher",
"object": {
"class": "Acme\\MyPublisher\\Publisher\\MyPublisher"
},
"schema": {
"type": "object",
"properties": {
"storage": {
"type": "string"
},
"entityType": {
"type": "string"
}
},
"required": [
"storage",
"entityType"
]
}
}

Only one prototype can be registered per file.

The $schema tag is used to determine not only against which schema it should be validated, but also determines the type of the registration file.

The type indicates where this prototype can be used in further configuration. The type that is declared in this example is an alias.

The identifier expects a unique identifier for the publisher.

In the object node a class is expected. This will be used to instantiate the correct object.

In the schema node the schema with expectations is created for the parameters for object instantiation.

 

Project
The publisher can be configured in the project in the magement folder.

File: magement/publisher/acme.publisher.json

{
"$schema": "https://di.schema.mediact.com/register.configuration.json",
"type": "outgoing-configuration",
"identifier": "acme-publisher",
"name": "ACME publisher",
"object": {
"parameters": {
"publisher": {
"type": "my-publisher",
"parameters": {
"storage": "acme-storage",
"entityType": "my-entity"
}
},
"entityType": "my-entity",
"remote": "acme-remote"
}
}
}

The $schema node expects the schema for registering a configuration.

The type node for this configuration should be outgoing-configuration, because an outgoing configuration is created, the publisher declaration itself, will be located in the object node.

The identifier node expects a unique identifier for the configuration. This identifier will be used later to trigger the publisher.

The name node will be shown in the dashboard when this publisher configuration is edited.

The object node will be contain the configuration of the publisher. Within the object node, a parameters node is expected, this will contain all the parameters required for the so called converter. In the publisher node inside the parameters the configuration for the previously created publisher is expected. This start by declaring the type of the publisher, which for this example is my-publisher. Then the parameters node is created. The contents of this node will be validated against the previously declared schema from the prototype configuration.

Next to the publisher configuration a entityType and remote need to be declared.

The converter is a translation layer for DI. This will convert the configuration to configuration DI can use to instantiate an object.

 

Executing a publisher

A publisher can be executed after it is installed in Alumio. This can be done in 2 ways. Through the API, or through a command.

The publisher would export the entities to a local file storage exactly as they are supplied, with their entity identity as keys within this file.