Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ A php library to describe resources and serve different hypermedia formats based

## how ?

- Declare your different resources:
Example integration with a symfony controller

```php
use Hippiemedia\Resource;
Expand All @@ -16,7 +16,6 @@ use Hippiemedia\Operation;
use Hippiemedia\Field;
use Hippiemedia\Format;
use Hippiemedia\Negotiate;
use Hippiemedia\UrlGenerator;

final class Hypermedia
{
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"require": {
"lstrojny/functional-php": "^1.0",
"willdurand/negotiation": "^2.0",
"symfony/routing": "^3.0 | ^4.0"
"docteurklein/json-chunks": "^1.0"
},
"autoload": {
"psr-4": {
Expand Down
115 changes: 37 additions & 78 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 19 additions & 0 deletions example/whatever.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php declare(strict_types=1);

// php -S 0:8080 -t example
// xdg-open http://0:8080/whatever.php

use Hippiemedia\Infra\Negotiate\WilldurandNegotiator;
use Hippiemedia\Format;
use Hippiemedia\Resource;

require(__DIR__.'/../vendor/autoload.php');

$contentType = array_change_key_case(getallheaders())['content-type'] ?? 'text/html';

$negotiate = new WilldurandNegotiator(new \Negotiation\Negotiator, 'text/html', new Format\Html, new Format\Siren, new Format\Hal);
$format = $negotiate($contentType);

header('Content-Type: '.$format->accepts());

echo implode("\n", iterator_to_array($format(Resource::whatever()), false));
20 changes: 20 additions & 0 deletions spec/Hippiemedia/Format/HtmlSpec.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace spec\Hippiemedia\Format;

use Hippiemedia\Format\Siren;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Hippiemedia\Resource;

class HtmlSpec extends ObjectBehavior
{
function it_formats_html()
{
$iterable = $this(Resource::whatever());

$html = implode("\n", iterator_to_array($iterable->getWrappedObject(), false));
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->loadHTML($html);
}
}
12 changes: 9 additions & 3 deletions src/Format/Hal.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Hippiemedia\Format;
use Hippiemedia\Resource;
use Hippiemedia\Link;
use DocteurKlein\JsonChunks\Encode;

final class Hal implements Format
{
Expand All @@ -15,6 +16,11 @@ public function accepts(): string
}

public function __invoke(Resource $resource): iterable
{
return Encode::from($this->normalize($resource));
}

private function normalize(Resource $resource): iterable
{
$linksByRel = array_merge(
f\group($resource->links, f\invoker('rel')),
Expand All @@ -40,7 +46,7 @@ public function __invoke(Resource $resource): iterable
}),
'_embedded' => array_merge(f\map($operationsByRel, function($operations) {
return f\map(array_values($operations), function($operation) {
return $this(new Resource($operation->url, [
return $this->normalize(new Resource($operation->url, [
'_templates' => [
'default' => [
'title' => $operation->title,
Expand All @@ -63,8 +69,8 @@ public function __invoke(Resource $resource): iterable
], array_merge([new Link(['self'], $operation->url, $operation->templated)], $operation->links), []));
});
}), f\map($resource->embedded, function($resources) {
return f\map($resources, $this);
}, $this))
return array_map([$this, 'normalize'], $resources);
}))
]);
}
}
65 changes: 65 additions & 0 deletions src/Format/Html.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php declare(strict_types=1);

namespace Hippiemedia\Format;

use Functional as f;
use Hippiemedia\Format;
use Hippiemedia\Resource;
use Hippiemedia\Operation;

final class Html implements Format
{
public function accepts(): string
{
return 'text/html';
}

public function __invoke(Resource $resource): iterable
{
$state = print_r($resource->state, true);
yield '<div>';
yield "<pre>{$state}</pre>";
yield from $this->links($resource);
yield from $this->operations($resource);
yield '</div>';
}

private function links(Resource $resource): iterable
{
yield '<ul>';
foreach ($resource->links as $link) {
yield <<<HTML
<li><a href="{$link->href}">{$link->title}</a></li>
HTML;
}
yield '</ul>';
}

private function operations(Resource $resource): iterable
{
foreach ($resource->operations as $operation) {
yield <<<HTML
<form action="{$operation->url}" method="{$operation->method}">
<fieldset>
<legend>{$operation->title}</legend>
HTML
;
yield from $this->fields($operation);

yield <<<HTML
</fieldset>
<input type="submit" />
</form>
HTML;
}
}

private function fields(Operation $operation): iterable
{
foreach ($operation->fields as $field) {
yield <<<HTML
<input name="{$field->name}" value="{$field->value}" />
HTML;
}
}
}
8 changes: 7 additions & 1 deletion src/Format/Siren.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Hippiemedia\Format;
use Hippiemedia\Resource;
use Hippiemedia\Link;
use DocteurKlein\JsonChunks\Encode;

final class Siren implements Format
{
Expand All @@ -15,6 +16,11 @@ public function accepts(): string
}

public function __invoke(Resource $resource): iterable
{
return Encode::from($this->normalize($resource));
}

private function normalize(Resource $resource): iterable
{
return [
'class' => [],
Expand All @@ -31,7 +37,7 @@ public function __invoke(Resource $resource): iterable
'entities' => array_reduce(array_keys($resource->embedded), function($acc, $rel) use($resource) {
$resources = $resource->embedded[$rel];
return array_merge($acc, f\map($resources, function($resource) use($rel) {
return array_merge($this($resource), ['rel' => [$rel]]);
return array_merge($this->normalize($resource), ['rel' => [$rel]]);
}));
}, []),
'actions' => f\map(array_values($resource->operations), function($operation) {
Expand Down
31 changes: 0 additions & 31 deletions src/Infra/UrlGenerator/SymfonyRouter.php

This file was deleted.

2 changes: 1 addition & 1 deletion src/Operation.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public static function whatever(array $data = [])
{
return new self(
$data['rel'] ?? 'rel',
$data['method'] ?? 'method',
$data['method'] ?? 'POST',
$data['url'] ?? 'url',
$data['templated'] ?? false,
$data['title'] ?? 'title',
Expand Down
2 changes: 1 addition & 1 deletion src/Resource.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public static function whatever(array $data = [])
$data['state'] ?? ['state'],
$data['links'] ?? [Link::whatever()],
$data['operations'] ?? [Operation::whatever()],
$data['embedded'] ?? ['rel' => [self::whatever(['embedded' => []])]],
$data['embedded'] ?? ['rel' => [self::whatever(['state' => ['SUB'], 'embedded' => []])]],
$data['is_deprecated'] ?? false
);
}
Expand Down