triquanta/libizi

2.0.11 2016-04-15 06:47 UTC

This package is not auto-updated.

Last update: 2024-04-13 13:31:37 UTC


README

Build Status

This is a PHP library for communicating with the izi.TRAVEL API.

Requirements

All requirements are resolved through Composer. After installing composer, go to the project root and run composer install to install all dependencies.

Usage & features

Client

The library provides a client to communicate with the API. It handles all requests, errors, and converts all API output to classes PHP objects. Three preparatory steps must be taken before API calls can be made:

  1. Create a \GuzzleHttp\Client instance.
  2. Create a \Triquanta\IziTravel\Client\*RequestHandler instance and inject the Guzzle client from step 1 and an API key.
  3. Create a Triquanta\IziTravel\Client\Client instance and inject the request handler from step 2.

Now you can call any of the methods on the client from step 3 and get the API's output as (arrays of) classed PHP objects.

Data types

Because working with raw, untyped data in PHP is bad developer experience (DX), every data type in the API has corresponding interfaces and classes in this library. All classes come with factory methods (\Triquanta\IziTravel\DataType\FactoryInterface) to instantiate an object based on the API's raw JSON response.

Events

Symfony EventDispatcher is used for dispatching system events. Event names and classes are documented in \Triquanta\IziTravel\Event\IziTravelEvents.

Development

Versioning

All development takes places on the master branch. Versions are released based on Semantic Versioning.

Supporting a new API endpoint

Each API endpoint is represented by a request class in \Triquanta\IziTravel\Request and it must implement \Triquanta\IziTravel\Request\RequestInterface. It can optionally implement any of the other interfaces in the same namespace and use any of the traits to quickly build a configurable request. Any object data returned by an endpoint must be converted to classed objects before being returned by \Triquanta\IziTravel\Request\RequestInterface::execute() implementations. The existing data types in Triquanta\IziTravel\DataType can be re-used. \Triquanta\IziTravel\ClientInterface is a convenience layer for easily requesting data from different endpoints in the same code. When adding a new request class, a method for it must be added to this interface as well.

Example

A new endpoint foo was added for retrieving Foo content by UUID. Additionally the content can be returned in a specific language and format (full/compact). The first step is to create a class that implements the correct interface (which is inherited from RequestBase):

<?php
    
/**
 * @file Contains \Triquanta\IziTravel\Request\FooByUuid.
 */

namespace Triquanta\IziTravel\Request;

/**
 * Returns a Foo object by UUID.
 */
class FooByUuid extends RequestBase {

    /**
     * @return \Triquanta\IziTravel\DataType\FooInterface
     */
    public function execute() {
    }

}

Now we have the basis for any request. Because this endpoint supports forms and is multilingual, we can easily add support for this by implementing two interfaces and using two traits:

<?php

class FooByUuid extends RequestBase implements FormInterface, MultilingualInterface, UuidInterface {

    use FormTrait;
    use MultilingualTrait;
    use UuidTrait;

    /**
     * @return \Triquanta\IziTravel\DataType\FooInterface
     */
    public function execute() {
    }

}

The class will now feature additional methods and properties for setting and storing the form, language, and UUID of the content that should be returned by the API.

Now we are able to configure instances of this class, we need to use this configuration to execute the actual request and get the JSON from the response:

<?php

public function execute() {
    $json = $this->requestHandler->request('/foo', [
      'form' => $this->form,
      'languages' => $this->languageCodes,
      'uuid' => $this->limit,
    ]);
}

The request is made to the endpoint, and we pass along the values of the three endpoint parameters (form, language, UUID). As you can see, we use the traits' properties for this.

What remains is the conversion of this JSON to a classed object. We don't have to worry about NULL values, because the API returns HTTP error response in case the requested content is not available. That means by the time this code is executed, we can be sure the response is positive.

<?php

public function execute() {
    // ...
    
    return Foo::createFromJson($json, $this->form);
}

All data object classes implement FactoryInterface and must be instantiated by using the interface's methods. By calling ::createFromJson(), we also validate the JSON against the available schemas.

The request class in its entirety now looks like this:

<?php
    
/**
 * @file Contains \Triquanta\IziTravel\Request\FooByUuid.
 */

namespace Triquanta\IziTravel\Request;

/**
 * Returns a Foo object by UUID.
 */
class FooByUuid extends RequestBase implements FormInterface, MultilingualInterface, UuidInterface {

    use FormTrait;
    use MultilingualTrait;
    use UuidTrait;

    /**
     * @return \Triquanta\IziTravel\DataType\FooInterface
     */
    public function execute() {
        $json = $this->requestHandler->request('/foo', [
          'form' => $this->form,
          'languages' => $this->languageCodes,
          'uuid' => $this->limit,
        ]);

        return Foo::createFromJson($json, $this->form);
    }

}

For convenience we also add a factory method to ClientInterface. Because the language and UUID are the only required request parameters, they are also the only parameters to the factory method. Any remaining optional parameters can be configured using the setters on the returned request object.

<?php

namespace Triquanta\IziTravel\Client;

interface ClientInterface
{

    // ...

    /**
     * Gets a request to get a Foo object by its UUID.
     *
     * @param string[] $languageCodes
     *   An array of ISO 639-1 alpha-2 language codes.
     * @param string $uuid
     *
     * @return \Triquanta\IziTravel\Request\FooByUuid
     */
    public function getFooByUuid(array $languageCodes, $uuid);

}

The method's implementation in Client would look like this:

<?php

namespace Triquanta\IziTravel\Client;

use namespace Triquanta\IziTravel\Request\FooByUuid;

class Client implements ClientInterface
{

    // ...

    public function getFooByUuid(array $languageCodes, $uuid)
    {
        return FooByUuid::create($this->requestHandler)
          ->setLanguageCodes($languageCodes)
          ->setUuid($uuid);
    }

}

The newly supported endpoint can then be used:

<?php

use Triquanta\IziTravel\Client\Client;

$client = new Client(/* ... */);
/** @var \Triquanta\IziTravel\DataType\FooInterface $foo */
$foo = $client->getFooByUuid(['en'], 'de305d54-75b4-431b-adb2-eb6b9e546014')->setForm(FormInterface::FORM_COMPACT)->execute();

PSR-2

All code must be written according the PSR-2 guidelines.

PSR-4

Class and interface autoloading is done using PSR-4 using the following namespace mappings:

  • \Triquanta\IziTravel maps to ./src
  • \Triquanta\IziTravel\Tests maps to ./tests

Testing

The library comes with PHPUnit-based tests that can be run using ./phpunit.xml.dist. All tests are located in \Triquanta\IziTravel\Tests.

Some tests require configuration. Copy ./test_configuration.example.yml to ./test_configuration.local.yml and fill out the values.