gfg/hek

This package is abandoned and no longer maintained. No replacement package was suggested.

Hek plugin to provide integration between your webservices (service gateway pattern)

1.0.9 2016-10-21 17:26 UTC

README

Scrutinizer Code Quality Code Coverage Build Status Latest Stable Version Total Downloads License Forks Stars

INTRODUCTION

Communication between services is never an easy task. Aiming to facilitate and keep things consistent, Hek makes use of the context-oriented datawrapper library DTO-Context to ensure the data integrity and normalization, and still be flexible enough to be applied to any kind of service.

CONCEPT

The concept is pretty simple: create your data entities (dataWrappers); map the actions that your service does and create a context for each of them. After that you can let Hek take care to deliver the information to the responsible component.

Hek is a library that contains the base files to implement the thin communication layer that will use specific contexts. It's based on a Service Gateway Pattern and a good example of implementation is the Hek-Marketplace that uses DTO-Marketplace

STRUCTURE

Exceptions //All the exceptions used in the library
├─ InvalidInput.php //Malformed Json
├─ MethodNotAllowed.php //When a service method that doesn't exist is requested
├─ ResponseInteface.php //Interface that all Hek implementations exceptions must implement
└─ RetryMessage.php //Exception used by the ApiClient

Interfaces //All the interfaces needed to create a Hek implementation
├─ Configuration.php //Some configurations needed for Hek to work properly
├─ Context.php //What is expected for a context to be used by Hek
└─ ServiceFactory.php //Hek must know how to create your services

ApiClient.php //Client that handles HTTP requests
CommandBus.php //Proxies the commands to the responsible objects
Manager.php //Handle the dependencies

EXAMPLE OF USE

As mentioned above, the library is a base library to develop a layer of communication for a specific service (Service Gateway). We will use an example of service that creates a person, update the person's name and receive a creation confirmation. We will call it MyHek.

To do so we need to follow the steps below:

  1. Create the DataWrappers;
  2. The Contexts;
  3. The Service factory;
  4. The Services;
  5. The Context factory.

Example 1: Implementing directly (without separating it in a composable library)

Proposed Structure

MyHek
    Datawrappers
    └─ Person.php
    Contexts
    ├─ Person
       ├─ Create.php
       └─ UpdateName.php
       └─ ConfirmCreate.php
    └─Factory.php
    Services
    ├─ Configuration.php
    ├─ Manager.php    
    └─ Person.php
└─ Factory.php

1 DataWrapper

<?php

namespace MyHek\DataWrapper;

use GFG\DTOContext\DataWrapper\Base;

/**
 * @SuppressWarnings(PHPMD.UnusedPrivateField)
 * @method string getName()
 * @method integer getHeight()
 * @method integer getWeight()
 * @method integer getAge()
 * @method string getNationality()
 * @method \MyHek\DataWrapper\Person setName(string $name)
 * @method \MyHek\DataWrapper\Person setHeight(integer $height)
 * @method \MyHek\DataWrapper\Person setWeight(integer $weight)
 * @method \MyHek\DataWrapper\Person setAge(integer $age)
 * @method \MyHek\DataWrapper\Person setNationality(string $nationality)
 */
class Person extends Base
{
    private $name;
    private $height;
    private $weight;
    private $age;
    private $nationality;
}

2. Contexts

CreatePerson Context

<?php

namespace MyHek\Context\Person;

use GFG\Hek\Interfaces\Context as HekContext;
use GFG\DTOContext\Context\Base as BaseContext;

class Create extends BaseContext implements HekContext
{
    public function getHttpMethod()
    {
        return 'post';
    }

    public function getUrl()
    {
        return 'create-person';
    }

    /**
     * In this method, we'll use only the data that is needed for
     * this action
     */
    public function exportContextData()
    {
        $dataWrapper = $this->getDataWrapper();

        return $this->prepareExport([
            'name'        => $dataWrapper->getName(),
            'height'      => $dataWrapper->getHeight(),
            'weight'      => $dataWrapper->getWeight(),
            'age'         => $dataWrapper->getAge(),
            'nationality' => $dataWrapper->getNacionality()
        ]);
    }
}

UpdateName context

<?php

namespace MyHek\Context\Person;

use GFG\Hek\Interfaces\Context as HekContext;
use GFG\DTOContext\Context\Base as BaseContext;

class UpdateName extends BaseContext implements HekContext
{
    public function getHttpMethod()
    {
        return 'put';
    }

    public function getUrl()
    {
        return 'update-name';
    }

    public function exportContextData()
    {
        $dataWrapper = $this->getDataWrapper();

        return $this->prepareExport([
            'name' => $dataWrapper->getName()
        ]);
    }
}

ConfirmCreation

<?php

namespace MyHek\Context\Person;

use GFG\Hek\Interfaces\Context as HekContext;
use GFG\DTOContext\Context\Base as BaseContext;

class ConfirmCreate extends BaseContext implements HekContext
{
    public function getHttpMethod()
    {
        return 'put';
    }

    public function getUrl()
    {
        return 'confirm-create';
    }

    public function exportContextData()
    {
        $dataWrapper = $this->getDataWrapper();

        return $this->prepareExport([
            // ...
        ]);
    }
}

3. Service Factory

<?php

namespace MyHek;

class Factory implements GFG\Hek\Interfaces\ServiceFactory
{
    public function build(GFG\Hek\Interfaces\Context $context)
    {
        $parts = array_slice(explode('.', $context->getName()), -2, 1); // ['Person']
        $className = ucfirst(current($parts)); // Person
        $serviceName = "\MyHek\Services\{$className}";
        return new $serviceName;
    }
}

4. Services

Configuration

<?php

namespace MyHek\Services;

use GFG\Hek\Interfaces;

class Configuration implements Interfaces\Configuration
{
    public function isEnabled()
    {
        return true;
    }

    public function getUserKey()
    {
        return 'myUserKey';
    }

    public function getBaseUrl()
    {
        return 'http://person.service.com';
    }

    public function getAccessToken()
    {
        return 'access token';
    }

    public function getHttpUser() 
    {
        return 'user'; // or false
    }

    public function getHttpPass()
    {
        return 'password'; // or false
    }
}

5. Context Factory

<?php

namespace MyHek\Context;

use GFG\Hek\DTO-Context\Factory\Base as BaseFactory;

class Factory extends BaseFactory
{
    const PERSON_CREATE        = 'person.create'; 
    const PERSON_UPDATENAME    = 'person.updatename'; 
    const PERSON_CONFIRMCREATE = 'person.confirmcreate'; 

    protected static $mappedContext = [
        self::PERSON_CREATE        => 'MyHek\Context\Person\Create',
        self::PERSON_UPDATENAME    => 'MyHek\Context\Person\UpdateName',
        self::PERSON_CONFIRMCREATE => 'MyHek\Context\Person\ConfirmCreate'
    ];

    public function getMappingList()
    {
        return self::$mappedContext;
    }
}

Sending a request

<?php

use MyHek\Context\Factory;
use GFG\DTOContext\Manager;

$manager = (new Manager())->setFactory(new Factory());
$context = $manager->build(...);

Example 2: Implementing modularly, keeping the contexts and the hek implemention separate in composable libraries