application/hal builder / formatter for PHP 5.4+

Related tags

API hal
Overview

Nocarrier\Hal

Build Status Scrutinizer Code Quality

This is a library for creating documents in the application/hal+json and application/hal+xml hypermedia formats

It requires PHP 5.4 or later.

<?php
require_once 'vendor/autoload.php';

use Nocarrier\Hal;

$hal = new Hal('/orders');
$hal->addLink('next', '/orders?page=2');
$hal->addLink('search', '/orders?id={order_id}');

$resource = new Hal(
    '/orders/123',
    array(
        'total' => 30.00,
        'currency' => 'USD',
    )
);

$resource->addLink('customer', '/customer/bob', array('title' => 'Bob Jones <[email protected]>'));
$hal->addResource('order', $resource);
echo $hal->asJson();
echo $hal->asXml();

Installation

The preferred method of installation is via packagist as this provides the PSR-0 autoloader functionality. The following command will download and install the latest version of the Hal library into your project.

php composer.phar require nocarrier/hal

Alternatively, clone the project and install into your project manually.

License

Nocarrier\Hal is licensed under the MIT license.

Usage

Creating Hal Resources

A Hal resource can be created with no values set:

$hal = new \Nocarrier\Hal();

with a URI for the resource:

$hal = new \Nocarrier\Hal('/orders');

and also with an array of data:

$hal = new \Nocarrier\Hal('/orders', ['customerId' => 'CUS1234']);

Hal resources can also be created from existing XML or JSON documents:

$hal = \Nocarrier\Hal::fromJson($jsonString);
$hal = \Nocarrier\Hal::fromXml($xmlString);
$hal = \Nocarrier\Hal::fromXml($simpleXMLElement);

The depth of embedded resources parsed with both these methods is controlled by a second argument, which defaults to 0:

$hal = \Nocarrier\Hal::fromJson($jsonString, 5);

Getting Representations

The Hal resource can be formatted as JSON or XML:

$hal = new \Nocarrier\Hal('/orders', ['customerId' => 'CUS1234']);
$hal->asJson();

which with a first argument of true for pretty printing:

$hal = new \Nocarrier\Hal('/orders', ['customerId' => 'CUS1234']);
$hal->asJson(true);

gives:

{
    "customerId": "CUS1234",
    "_links": {
        "self": {"href": "/orders"}
    }
}

and

$hal = new \Nocarrier\Hal('/orders', ['customerId' => 'CUS1234']);
$hal->asXml(true);

gives:

<?xml version="1.0"?>
<resource href="/orders">
    <customerId>CUS1234</customerId>
</resource>

Data

The data can be set through setData and read with getData:

$hal = new \Nocarrier\Hal('/orders');
$hal->setData(['customerId' => 'CUS1234']);
$hal->getData();

Using array keys in the data for the XML representation can be done by prefixing the key with @:

$hal = new \Nocarrier\Hal('/orders');
$hal->setData(['customerId' => ['CUS1234', '@type' => 'legacy']]);

gives:

<?xml version="1.0"?>
<resource href="/orders">
    <customerId value="CUS1234" type="legacy"/>
</resource>

The @ is ignored if JSON is rendered:

{
    "customerId": {
        "value": "CUS1234",
        "type":" legacy"
    },
    "_links": {
        "self": {"href": "/orders"}
    }
}

Links

Links can be added to the resource by providing the rel identifying them and a URI:

$hal = new \Nocarrier\Hal('/orders', ['customerId' => 'CUS1234']);
$hal->addLink('next', '/orders?page=2');
$hal->addLink('search', '/orders?id={order_id}');

gives:

{
    "customerId": "CUS1234",
    "_links": {
        "self": {
            "href": "/orders"
        },
        "next": {
            "href": "/orders?page=2"
        },
        "search": {
            "href": "/orders?id={order_id}"
        }
    }
}

If a Hal object has been created from a response returned from elsewhere it can be helpful to retrieve the links from it.

$json = '{
     "customerId": "CUS1234",
     "_links": {
         "self": {
             "href": "/orders"
         },
         "next": {
             "href": "/orders?page=2"
         },
         "search": {
             "href": "/orders?id={order_id}"
         }
     }
 }';

$hal = \Nocarrier\Hal::fromJson($json);

foreach($hal->getLinks() as $rel => $links) {
    echo $rel."\n";
    foreach($links as $link) {
        echo (string) $link."\n";
    }
}
next
/orders?page=2
search
/orders?id={order_id}

and

$json = '{
     "customerId": "CUS1234",
     "_links": {
         "self": {
             "href": "/orders"
         },
         "next": {
             "href": "/orders?page=2"
         },
         "search": {
             "href": "/orders?id={order_id}"
         }
     }
 }';
$hal = \Nocarrier\Hal::fromJson($json);
foreach($hal->getLink('next') as $link) {
    echo (string) $link."\n";
}

outputs:

/orders?page=2

Embedded Resources

As well as linking to resources so that the client can fetch them they can be directly embedded in the resource.

$hal = new \Nocarrier\Hal('/orders', ['customerId' => 'CUS1234']);

$resource = new \Nocarrier\Hal(
    '/orders/123',
    array(
        'total' => 30.00,
        'currency' => 'USD',
    )
);

$resource->addLink('customer', '/customer/bob', array('title' => 'Bob Jones <[email protected]>'));
$hal->addResource('order', $resource);

outputs:

{
    "customerId": "CUS1234",
    "_links": {
        "self": {
            "href": "/orders"
        }
    },
    "_embedded": {
        "order": [
            {
                "total": 30,
                "currency": "USD",
                "_links": {
                    "self": {
                        "href": "/orders/123"
                    },
                    "customer": {
                        "href": "/customer/bob",
                        "title": "Bob Jones <[email protected]>"
                    }
                }
            }
        ]
    }
}
Comments
  • Allowing setting a single object as an embedded resource

    Allowing setting a single object as an embedded resource

    Unless I'm mistaken, there's no way to render the following?

    
    {
      "_links": {
        .. *snip* ..
      },
      "_embedded": {
        "manufacturer": {
          "_links": {
            "self": { "href": "/manufacturers/328764" },
            "homepage": { "href": "http://hoverdonkey.com" }
          },
          "name": "Manufacturer Inc."
        },
    
      .. *snip* ..
    }
    

    I'm not entirely sold on the API in this PR, as the setResource method is only really valid for those wanting to render json. I could spruce it up a bit to accept either a Hal or an array of Hals, in which case it would be relevant to both, i.e. you can add a collection in one call rather than several.

    Another option would be to allow some sort of notation on the addResource rel string, but I'm not really keen on that either.

    NB: I've not done anything with regards to deserialising yet, I'll do that when/if we agree on API for what I'm trying to achieve.

    opened by davedevelopment 12
  • Skip stripping attributes for HAL resources from JSON

    Skip stripping attributes for HAL resources from JSON

    If the HAL object wasn't created from XML there shouldn't be any attributes to strip. As we can't be sure that all resources have a source format set, we can only test that the format has been set and it's not XML.

    For large collections we see a not insignificant overhead when stripping attributes and this seemed the cleanest way to identify cases where there weren't attributes to strip.

    Existing tests cover that XML still attributes still get stripped where no source is set, so there should be no BC breaks.

    opened by nickpeirson 11
  • Any plans for unserialising?

    Any plans for unserialising?

    I've not a lot of time at the minute, but if nobody else has it on their roadmap, I'll try and start in the next month or so.

    I'd really like to do sub requests to get some of my embedded resources:

    
    $resource = new Resource();
    $resource->addResource($client->get("/some/sub/resource"));
    
    

    Where client goes off, does a request by whatever means and returns a Nocarrier\Hal.

    opened by davedevelopment 6
  • Nested resource cannot be json-ized

    Nested resource cannot be json-ized

    Nested resources which contain only one sub resource cannot be rendered as json.

    Testing with only ONE line uncommented:

    $hal = new \Nocarrier\Hal();
    // following options do NOT work
    // $hal->setResource(
    //     'foo',
    //     (new \Nocarrier\Hal())
    //         ->setResource('bar', new \Nocarrier\Hal())
    // );
    // $hal->setResource(
    //     'foo',
    //     (new \Nocarrier\Hal())
    //         ->addResource('bar', new \Nocarrier\Hal(), false)
    // );
    // $hal
    //     ->setResource('foo1', (new \Nocarrier\Hal())->setResource('bar', new \Nocarrier\Hal()))
    //     ->setResource('foo2', new \Nocarrier\Hal());
    // $hal->setResource(
    //     'foo',
    //     (new \Nocarrier\Hal())
    //         ->setResource('bar1', new \Nocarrier\Hal())
    //         ->setResource('bar2', new \Nocarrier\Hal())
    // );
    
    // following options DO work
    // $hal->setResource('foo', new \Nocarrier\Hal());
    // $hal
    //     ->setResource('foo1', new \Nocarrier\Hal())
    //     ->setResource('foo2', new \Nocarrier\Hal());
    // $hal->addResource(
    //     'foo',
    //     (new \Nocarrier\Hal())->setResource('bar', new \Nocarrier\Hal()),
    //     false
    // );
    // $hal->addResource(
    //     'foo',
    //     (new \Nocarrier\Hal())->addResource('bar', new \Nocarrier\Hal(), false),
    //     false
    // );
    
    echo ($hal->asJson(true));
    

    Non-working options throw: ErrorException in HalJsonRenderer.php line 164: Undefined offset: 0

    Seems to relate to the test count($embedded) === 1 in https://github.com/blongden/hal/blob/master/src/Nocarrier/HalJsonRenderer.php#L159

    I am using current version 0.9.11

    bug fixed 
    opened by Pittiplatsch 5
  • Added the ability to set attributes on a HalLink

    Added the ability to set attributes on a HalLink

    We had a use case where we needed to be able to set attributes on a link that was already added to a collection. This PR adds the ability to set attributes on a HalLink.

    opened by iainmckay 5
  • Throw a runtimeException if data passed to fromJson method isn't json

    Throw a runtimeException if data passed to fromJson method isn't json

    Avoids the error Fatal Error: 'Argument 2 passed to CG\Slim\Renderer\ResponseType\Hal::__construct() must be of the type array, null given, called in /var/www/app/current/vendor/nocarrier/hal/src/Nocarrier/Hal.php on line 116

    opened by dangerousdan 4
  • Adding setData and setUri

    Adding setData and setUri

    Hi,

    I am working on a rest builder framework and i am using you library.

    I thinks that can be interesting allow the deferred setting of the URI and the data. I my case for example i dont know the uri for the answer when i construct the Hal object.

    Regards and thanks for your job.

    opened by mcuadros 4
  • _embedded for empty collections

    _embedded for empty collections

    I am using the _embedded property to return a collection of things. This is done using addResource('mycollection', $hal).

    Sometimes, due to filtering or some other reason, the collection is empty. Even then, I would like to have an empty collection like this:

    "_embedded":{
       "collection": []
    }
    

    Is there a way for the library to do this? If now, can this be added to the library (perhaps it might be as simple as changing the signature of addResource() to addResource($rel, $hal = null)?

    opened by F21 4
  • setResource is broken when the resource contains only 1 data element

    setResource is broken when the resource contains only 1 data element

    $resource = new Nocarrier\Hal('/post/1',[/*some data here*/]);
    $author = new Nocarrier\Hal('/user/1', [
        'name' => 'John',
    ]);
    $resource->setResource('user', $author);
    
    $resource->asJson();
    

    Will fail with Notice: Undefined offset: 0 here:

    if (count($embedded) === 1 && !in_array($rel, $resource->getArrayResourceRels())) {
        $embedded = $embedded[0];
    }
    

    This fails because:

    • $author only contains 1 field, which triggers the condition count($embedded) === 1
    • setResource does not register refs in arrayResourceRels, which triggers the condition !in_array($rel, $resource->getArrayResourceRels())

    I don't fully understand the logic here, so I'm not sure what the solution is, but it was extremely confusing to find out that having a resource with a single field was not supported. I had to add a second (unnecessary) field to make it work.

    opened by arthens 3
  • Allow setting links by passing a link instance

    Allow setting links by passing a link instance

    This PR introduces the possibility to set a link directly by passing a HalLink instance.

    While I am not totally happy with the naming set in setLink() (setting usually implies replacing some something rather than adding), it anyhow conforms to the schema used with addResource() / setResource().

    Additional tests aren't necessary as the old method addLink() under the hood now uses the new setLink() method, which therefore is covered automatically.

    opened by Pittiplatsch 3
  • Unsetting

    Unsetting "title" attribute in JSON links

    When creating a HAL object using the JSON factory, it unsets the "title" attribute:

    https://github.com/blongden/hal/blob/develop/src/Nocarrier/JsonHalFactory.php#L62

    There's no indication why it does this, and from what I can see in the XML factory, it doesn't do the equivalent. Should a comment be added to clarify why?

    opened by acleon 3
Owner
Ben Longden
Ben Longden
Monorepo of the PoP project, including: a server-side component model in PHP, a GraphQL server, a GraphQL API plugin for WordPress, and a website builder

PoP PoP is a monorepo containing several projects. The GraphQL API for WordPress plugin GraphQL API for WordPress is a forward-looking and powerful Gr

Leonardo Losoviz 265 Jan 7, 2023
Monorepo of the PoP project, including: a server-side component model in PHP, a GraphQL server, a GraphQL API plugin for WordPress, and a website builder

PoP PoP is a monorepo containing several projects. The GraphQL API for WordPress plugin GraphQL API for WordPress is a forward-looking and powerful Gr

Leonardo Losoviz 265 Jan 7, 2023
PHP & MySQL Based Simple Application

Al Quran Technology Pages localhost/index.php Single Surah Page localhost/pages/single.php?no=1&name=আল%20ফাতিহা&ty=7 Data Source MySQL Database Local

Mejanur Rahman Mezan 3 Oct 19, 2022
Adds CORS (Cross-Origin Resource Sharing) headers support in your Laravel application

CORS Middleware for Laravel Implements https://github.com/asm89/stack-cors for Laravel About The laravel-cors package allows you to send Cross-Origin

Fruitcake 6.2k Jan 8, 2023
Zoho CRM API SDK is a wrapper to Zoho CRM APIs. By using this sdk, user can build the application with ease

Archival Notice: This SDK is archived. You can continue to use it, but no new features or support requests will be accepted. For the new version, refe

null 81 Nov 4, 2022
This API provides functionality for creating and maintaining users to control a simple To-Do-List application. The following shows the API structure for users and tasks resources.

PHP API TO-DO-LIST v.2.0 This API aims to present a brief to consume a API resources, mainly for students in the early years of Computer Science cours

Edson M. de Souza 6 Oct 13, 2022
Use middleware to decorate method calls within your application code.

Laravel Middlewarize ?? Chain of Responsibility Design Pattern In Laravel Apps ?? You can use middlewares to decorate any method calls on any object.

Iman 99 Jan 1, 2023
A Virtualmin API designed to run standalone or as part of a Laravel Application

Virtualmin API A Virtualmin API designed to run standalone or as part of a Laravel Application Requirements: PHP 8.0 A running Virtualmin server Featu

Fintech Systems 6 Jan 26, 2022
Easily integrate custom-made NPS (Net Promoter Score) into your application

Laravel NPS Easily integrate custom-made NPS (Net Promoter Score) to your application. Installation You can install the package via composer: composer

H-FARM Innovation 48 Oct 27, 2022
An SDK built to facilitate application development for Facebook Ads API.

Facebook Business SDK for PHP Introduction The Facebook Business SDK is a one-stop shop to help our partners better serve their businesses. Partners a

Meta 719 Dec 28, 2022
test listmonk & smtp application api

About Laravel Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experie

Iman Imen 0 Dec 26, 2021
The 1Password Connect PHP SDK provides your PHP applications access to the 1Password Connect API hosted on your infrastructure and leverage the power of 1Password Secrets Automation

1Password Connect PHP SDK The 1Password Connect PHP SDK provides your PHP applications access to the 1Password Connect API hosted on your infrastructu

Michelangelo van Dam 12 Dec 26, 2022
API for Symbiota using the Lumen PHP PHP Micro-Framework By Laravel

symbiota-api API for Symbiota using the Lumen PHP PHP Micro-Framework By Laravel Laravel Lumen Official Documentation Documentation for the Lumen fram

Biodiversity Knowledge Integration Center 2 Jan 3, 2022
Facebook SDK for PHP (v6) - allows you to access the Facebook Platform from your PHP app

Facebook SDK for PHP (v6) This repository contains the open source PHP SDK that allows you to access the Facebook Platform from your PHP app. Installa

null 0 Aug 10, 2022
Single file PHP script that adds a REST API to a SQL database

PHP-CRUD-API Single file PHP script that adds a REST API to a MySQL/MariaDB, PostgreSQL, SQL Server or SQLite database. NB: This is the TreeQL referen

Maurits van der Schee 3.2k Jan 8, 2023
Simple and effective multi-format Web API Server to host your PHP API as Pragmatic REST and / or RESTful API

Luracast Restler ![Gitter](https://badges.gitter.im/Join Chat.svg) Version 3.0 Release Candidate 5 Restler is a simple and effective multi-format Web

Luracast 1.4k Dec 14, 2022
Unofficial Firebase Admin SDK for PHP

Firebase Admin PHP SDK Table of Contents Overview Installation Documentation Support License Overview Firebase provides the tools and infrastructure y

kreait 1.9k Jan 3, 2023
Simple utility and class library for generating php classes from a wsdl file.

wsdl2phpgenerator Simple WSDL to PHP classes converter. Takes a WSDL file and outputs class files ready to use. Uses the MIT license. Announcement: We

null 802 Dec 10, 2022
Content Negotiation tools for PHP.

Negotiation Negotiation is a standalone library without any dependencies that allows you to implement content negotiation in your application, whateve

William Durand 1.3k Dec 22, 2022