Skip to content

Commit

Permalink
Format to JSONAPI
Browse files Browse the repository at this point in the history
  • Loading branch information
BigZ committed Jul 16, 2018
1 parent 1669e5c commit cb2b979
Show file tree
Hide file tree
Showing 6 changed files with 214 additions and 2 deletions.
84 changes: 84 additions & 0 deletions EventListener/ResponseListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?php

namespace Bigz\HalapiBundle\EventListener;

use App\Transformer\EntityTransformer;
use League\Fractal\Resource\Collection;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpFoundation\Request;

use League\Fractal\Manager;
use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;

/**
* Class ResponseListener
* Exeprimental... waiting for some feedbacks.
* @package App\EventListener
*/
class ResponseListener
{
/**
* @param FilterResponseEvent $event
*/
public function onKernelResponse(FilterResponseEvent $event)
{
if (200 !== $event->getResponse()->getStatusCode()
|| 'application/vnd.api+json' !== $event->getRequest()->headers->get('Content-Type')
) {
return;
}

$content = json_decode($event->getResponse()->getContent(), 1);

$fractal = new Manager();
$includes = [];
$inclusion = $event->getRequest()->get('include');

if ($inclusion) {
$fractal->parseIncludes($inclusion);
$includes = explode(',', $inclusion);
}

$fractal->setSerializer(new JsonApiSerializer(''));
$resource = $this->getResource($content, $includes, $this->guessType($event->getRequest()));
$data = $fractal->createData($resource)->toArray();

if ($resource instanceof Collection) {
$data['links'] = $content['_links'];
}

$event->getResponse()->setContent(json_encode($data));
}

/**
* @param $content
* @param $includes
* @param $type
* @return Collection|Item
*/
private function getResource($content, $includes, $type)
{
if (isset($content['id'])) {
return new Item($content, new EntityTransformer($includes), $type);
}

return new Collection($content['_embedded'], new EntityTransformer($includes), $type);
}

/**
* Guess an entityType from the route path.
* Doesn't seem very reliable... (subresources & stuff like that)
*
* @param Request $request
* @return bool|string
*/
private function guessType(Request $request)
{
$path = $request->getPathInfo();

$enPosition = strpos($path,'/', 1);

return substr($path, 1, $enPosition ? $enPosition - 2 : strlen($path) - 2);
}
}
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ new Bigz\HalapiBundle\BigzHalapiBundle(),

# Usage
It will hook in JmsSerializer and add HATEOAS data before serialization.
*Experimental* If the header Content-Type: application/vnd.api+json is specified, it will transform the output to JSONApi

# Further Documentation
Have a look at http://github.com/Bigz/Halapi
Expand Down
5 changes: 5 additions & 0 deletions Resources/config/services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,8 @@ services:
arguments: ["@bigz_halapi.relation_factory"]
tags:
- { name: jms_serializer.event_subscriber }

bigz_halapi.jsonapi_transformer:
class: Bigz\HalapiBundle\EventListener\ResponseListener
tags:
- { name: kernel.event_listener, event: kernel.response }
57 changes: 57 additions & 0 deletions Transformer/EntityTransformer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

namespace Bigz\HalapiBundle\Transformer;

use League\Fractal\TransformerAbstract;

class EntityTransformer extends TransformerAbstract
{
public function __construct($includes)
{
$this->availableIncludes = $includes;
}

/**
* Turn this item object into a generic array
*
* @return array
*/
public function transform($toFormat)
{
$data = $toFormat;

if (isset($data['_links'])) {
$data['links'] = [];

if (isset($data['_links']['self'])) {
$data['links']['self'] = $data['_links']['self'];
}
if (isset($data['_links']['next'])) {
$data['links']['next'] = $data['_links']['next'];
}

unset($data['_links']);
}

unset($data['_embedded']);
return $data;
}

public function __call($name, $arguments)
{
if (strpos($name, 'include') === 0) {
$shortName = strtolower(substr($name, 7, strlen($name) - 7));
$relation = $arguments[0]['_embedded'][$shortName];
if (isset($relation['id'])) {
return $this->item($relation, new EntityTransformer($this->availableIncludes), $shortName);
}

return $this->collection(
$relation,
new EntityTransformer($this->availableIncludes),
substr($shortName, 0, strlen($shortName) - 1) // singular
);

}
}
}
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"bigz/halapi": "^0.2",
"symfony/psr-http-message-bridge": "^1.0",
"pagerfanta/pagerfanta": "^1.0",
"zendframework/zend-diactoros": "^1.8"
"zendframework/zend-diactoros": "^1.8",
"league/fractal": "^0.17.0"
},
"require-dev": {
"symfony/expression-language": "~2.4 || ~3.0",
Expand Down
66 changes: 65 additions & 1 deletion composer.lock

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

0 comments on commit cb2b979

Please sign in to comment.