Create a subscriber package

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

.
├── src
│ └── MySubscriber.php
├── magement
│ └── my-subscriber.prototype.json
├── composer.json

These are all the files that are required to create a subscriber package for Alumio. It is recommended to use as much mechanics that are built in Alumio when creating a subscriber. For example if a HTTP type subscriber is created, there is no need to create requests using cURL or other packages, Alumio can already supply a HttpClient to the subscriber.

Composer

File: vendor/*/*/composer.json

The minimal composer.json file should look something like:

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

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

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

Additional dependencies

This example requires 1 additional package, namely:

{
"magement/storage": "^4.0"
}

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

 

Subscriber implementation

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

In the file MySubscriber.php, the subscriber logic will be implemented.This file should contain a class which implements the Magement\Subscriber\SubscriberInterface.

This will add the method __invoke to the class with the parameter $output with the type Magement\Subscriber\SubscriberOutputInterface. This object is used in the subscriber to write the data which is consumed.

All the parameters from the __construct method of the subscriber should be configured in the schema. If for example a HttpClient 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 HttpClient in order for Alumio to detect that it needs to supply a HttpClient. This will be based on the supplied string identifier for the parameter.

In this example the class would look like this:

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

namespace Acme\MySubscriber\Subscriber;

use Magement\Subscriber\SubscriberInterface;
use Magement\Subscriber\SubscriberOutputInterface;

class MySubscriber implements SubscriberInterface
{
/** @var string */
private $firstName;

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

/** @var string[] */
private $address;

/**
* Constructor
* @param string $firstName
* @param string $lastName
* @param string[] $address
*/
public function __construct(
string $firstName,
string $lastName,
array $address
) {
$this->firstName = $firstName;
$this->lastName = $lastName;
$this->address = $address;
}

/**
* Execute the subscriber.
*
* @param SubscriberOutputInterface $output
*
* @return void
*/
public function __invoke(SubscriberOutputInterface $output): void
{
$output->write(
[
'firstname' => $this->firstName,
'lastname' => $this->lastName,
'address' => $this->address,
]
);
}
}

 

Registering the subscriber

File: vendor/*/*/magement/my-subscriber.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": "subscriber",
"identifier": "my-subscriber",
"name": "My subscriber",
"object": {
"class": "Acme\\MySubscriber\\Subscriber\\MySubscriber"
},
"schema": {
"type": "object",
"properties": {
"firstname": {
"type": "string"
},
"lastname": {
"type": "string"
},
"address": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"firstname",
"lastname",
"address"
]
}
}

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 subscriber.

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 subscriber can be configured in the project in the magement folder.

File: magement/subscriber/acme.subscriber.json

{
"$schema": "https://di.schema.mediact.com/register.configuration.json",
"type": "incoming-configuration",
"identifier": "acme-subscriber",
"name": "ACME subscriber",
"object": {
"parameters": {
"subscriber": {
"type": "my-subscriber",
"parameters": {
"firstname": "John",
"lastname": "Doe",
"address": [
"Doe street 12",
"11234ABC",
"Netherlands"
]
}
},
"entityType": "my-entity",
"remote": "acme-remote"
}
}
}

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

The type node for this configuration should be incoming-configuration, because an incoming configuration is created, the subscriber 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 subscriber.

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

The object node will be contain the configuration of the subscriber. Within the object node, a parameters node is expected, this will contain all the parameters required for the so called converter. In the subscriber node inside the parameters the configuration for the previously created subscriber is expected. This start by declaring the type of the subscriber, which for this example is my-subscriber. 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 subscriber 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.

The configuration can be performed in multiple ways. One is through project configuration and the other is through the API.

Executing a subscriber

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

API

To execute the subscriber from the API call the following endpoint:

GET /api/v1/consume/{subscriber}

Do not forget to replace {subscriber} with the identifier of the subscriber that needs to be executed.

CLI

To execute a subscriber through the CLI, run the following command from the root of your project:

vendor/bin/magement consume:subscriber {subscriber}

Do not forget to replace {subscriber} with the identifier of the subscriber that needs to be executed. In the case of this example it will result in:

vendor/bin/magement consume:subscriber my-subscriber

The subscriber will output the following entity when it is consumed:

{
"firstname": "John",
"lastname": "Doe",
"address": [
"Doe street 12",
"11234ABC",
"Netherlands"
]
}