Skip to content

Instantly share code, notes, and snippets.

@weaverryan
Created March 21, 2016 15:20
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save weaverryan/e328037f1a45d7f85962 to your computer and use it in GitHub Desktop.
Save weaverryan/e328037f1a45d7f85962 to your computer and use it in GitHub Desktop.
KnpUniversity Symfony REST: Using @link with the PaginatedCollection (http://knpuniversity.com/screencast/symfony-rest3/evaluating-expression)
<?php
namespace AppBundle\Serializer;
use AppBundle\Annotation\Link;
use Doctrine\Common\Annotations\Reader;
use JMS\Serializer\EventDispatcher\EventSubscriberInterface;
use JMS\Serializer\EventDispatcher\ObjectEvent;
use JMS\Serializer\JsonSerializationVisitor;
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
use Symfony\Component\Routing\RouterInterface;
class LinkSerializationSubscriber implements EventSubscriberInterface
{
private $router;
private $annotationReader;
private $expressionLanguage;
public function __construct(RouterInterface $router, Reader $annotationReader)
{
$this->router = $router;
$this->annotationReader = $annotationReader;
$this->expressionLanguage = new ExpressionLanguage();
}
public function onPostSerialize(ObjectEvent $event)
{
/** @var JsonSerializationVisitor $visitor */
$visitor = $event->getVisitor();
$object = $event->getObject();
$annotations = $this->annotationReader
->getClassAnnotations(new \ReflectionObject($object));
$links = array();
foreach ($annotations as $annotation) {
if ($annotation instanceof Link) {
if ($annotation->url) {
$uri = $this->evaluate($annotation->url, $object);
} else {
$uri = $this->router->generate(
$annotation->route,
$this->resolveParams($annotation->params, $object)
);
}
// allow a blank URI to be an optional link
if ($uri) {
$links[$annotation->name] = $uri;
}
}
}
if ($links) {
$visitor->addData('_links', $links);
}
}
private function resolveParams(array $params, $object)
{
foreach ($params as $key => $param) {
$params[$key] = $this->evaluate($param, $object);
}
return $params;
}
private function evaluate($expression, $object)
{
return $this->expressionLanguage
->evaluate($expression, array('object' => $object));
}
public static function getSubscribedEvents()
{
return array(
array(
'event' => 'serializer.post_serialize',
'method' => 'onPostSerialize',
'format' => 'json',
)
);
}
}
<?php
namespace AppBundle\Pagination;
use AppBundle\Annotation\Link;
/**
* @Link(
* "self",
* url = "object.getUrl('self')"
* )
* @Link(
* "next",
* url = "object.getUrl('next')"
* )
* @Link(
* "prev",
* url = "object.getUrl('prev')"
* )
* @Link(
* "first",
* url = "object.getUrl('first')"
* )
* @Link(
* "last",
* url = "object.getUrl('last')"
* )
*/
class PaginatedCollection
{
private $items;
private $total;
private $count;
private $links = array();
public function __construct(array $items, $totalItems)
{
$this->items = $items;
$this->total = $totalItems;
$this->count = count($items);
}
public function addLink($ref, $url)
{
$this->links[$ref] = $url;
}
public function getUrl($ref)
{
return isset($this->links[$ref]) ? $this->links[$ref] : '';
}
}
@brunodplima
Copy link

brunodplima commented Oct 26, 2016

Hi, @weaverryan, i needed to add @Serializer\Exclude() in order no prevent duplication of _link as link.

This was my result without the Annotation:
screen shot 2016-10-26 at 18 38 23

Annotation I added:
screen shot 2016-10-26 at 18 40 45

Additionally, I removed the if verification on line 56 of LinkSerializationSubscriber.php as it's no longer needed.

https://gist.github.com/brunodplima/2f984535556c959327a6730f3e89e93c/revisions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment