Added list short URLs endpoint to rest api

This commit is contained in:
Alejandro Celaya 2016-06-18 09:43:29 +02:00
parent 305df3a95b
commit 4129d35447
7 changed files with 190 additions and 1 deletions

View file

@ -25,6 +25,12 @@ return [
'middleware' => Rest\ResolveUrlMiddleware::class,
'allowed_methods' => ['GET'],
],
[
'name' => 'rest-list-shortened-url',
'path' => '/rest/short-codes',
'middleware' => Rest\ListShortcodesMiddleware::class,
'allowed_methods' => ['GET'],
],
[
'name' => 'rest-get-visits',
'path' => '/rest/visits/{shortCode}',

View file

@ -37,6 +37,7 @@ return [
GuzzleHttp\Client::class => InvokableFactory::class,
Service\UrlShortener::class => AnnotatedFactory::class,
Service\VisitsTracker::class => AnnotatedFactory::class,
Service\ShortUrlService::class => AnnotatedFactory::class,
Cache::class => CacheFactory::class,
// Cli commands
@ -47,6 +48,7 @@ return [
Middleware\Rest\CreateShortcodeMiddleware::class => AnnotatedFactory::class,
Middleware\Rest\ResolveUrlMiddleware::class => AnnotatedFactory::class,
Middleware\Rest\GetVisitsMiddleware::class => AnnotatedFactory::class,
Middleware\Rest\ListShortcodesMiddleware::class => AnnotatedFactory::class,
],
'aliases' => [
'em' => EntityManager::class,

View file

@ -13,7 +13,7 @@ use Doctrine\ORM\Mapping as ORM;
* @ORM\Entity
* @ORM\Table(name="short_urls")
*/
class ShortUrl extends AbstractEntity
class ShortUrl extends AbstractEntity implements \JsonSerializable
{
/**
* @var string
@ -117,4 +117,21 @@ class ShortUrl extends AbstractEntity
$this->visits = $visits;
return $this;
}
/**
* Specify data which should be serialized to JSON
* @link http://php.net/manual/en/jsonserializable.jsonserialize.php
* @return mixed data which can be serialized by <b>json_encode</b>,
* which is a value of any type other than a resource.
* @since 5.4.0
*/
public function jsonSerialize()
{
return [
'shortCode' => $this->shortCode,
'originalUrl' => $this->originalUrl,
'dateCreated' => isset($this->dateCreated) ? $this->dateCreated->format(\DateTime::ISO8601) : null,
'visitsCount' => count($this->visits),
];
}
}

View file

@ -0,0 +1,74 @@
<?php
namespace Acelaya\UrlShortener\Middleware\Rest;
use Acelaya\UrlShortener\Service\ShortUrlService;
use Acelaya\UrlShortener\Service\ShortUrlServiceInterface;
use Acelaya\UrlShortener\Util\RestUtils;
use Acelaya\ZsmAnnotatedServices\Annotation\Inject;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Zend\Diactoros\Response\JsonResponse;
use Zend\Stratigility\MiddlewareInterface;
class ListShortcodesMiddleware implements MiddlewareInterface
{
/**
* @var ShortUrlServiceInterface
*/
private $shortUrlService;
/**
* ListShortcodesMiddleware constructor.
* @param ShortUrlServiceInterface|ShortUrlService $shortUrlService
*
* @Inject({ShortUrlService::class})
*/
public function __construct(ShortUrlServiceInterface $shortUrlService)
{
$this->shortUrlService = $shortUrlService;
}
/**
* Process an incoming request and/or response.
*
* Accepts a server-side request and a response instance, and does
* something with them.
*
* If the response is not complete and/or further processing would not
* interfere with the work done in the middleware, or if the middleware
* wants to delegate to another process, it can use the `$out` callable
* if present.
*
* If the middleware does not return a value, execution of the current
* request is considered complete, and the response instance provided will
* be considered the response to return.
*
* Alternately, the middleware may return a response instance.
*
* Often, middleware will `return $out();`, with the assumption that a
* later middleware will return a response.
*
* @param Request $request
* @param Response $response
* @param null|callable $out
* @return null|Response
*/
public function __invoke(Request $request, Response $response, callable $out = null)
{
try {
$shortUrls = $this->shortUrlService->listShortUrls();
return new JsonResponse([
'shortUrls' => [
'data' => $shortUrls,
// 'pagination' => [],
]
]);
} catch (\Exception $e) {
return new JsonResponse([
'error' => RestUtils::UNKNOWN_ERROR,
'message' => 'Unexpected error occured',
], 500);
}
}
}

View file

@ -0,0 +1,33 @@
<?php
namespace Acelaya\UrlShortener\Service;
use Acelaya\UrlShortener\Entity\ShortUrl;
use Acelaya\ZsmAnnotatedServices\Annotation\Inject;
use Doctrine\ORM\EntityManagerInterface;
class ShortUrlService implements ShortUrlServiceInterface
{
/**
* @var EntityManagerInterface
*/
private $em;
/**
* ShortUrlService constructor.
* @param EntityManagerInterface $em
*
* @Inject({"em"})
*/
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
/**
* @return ShortUrl[]
*/
public function listShortUrls()
{
return $this->em->getRepository(ShortUrl::class)->findAll();
}
}

View file

@ -0,0 +1,12 @@
<?php
namespace Acelaya\UrlShortener\Service;
use Acelaya\UrlShortener\Entity\ShortUrl;
interface ShortUrlServiceInterface
{
/**
* @return ShortUrl[]
*/
public function listShortUrls();
}

View file

@ -0,0 +1,45 @@
<?php
namespace AcelayaTest\UrlShortener\Service;
use Acelaya\UrlShortener\Entity\ShortUrl;
use Acelaya\UrlShortener\Service\ShortUrlService;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use PHPUnit_Framework_TestCase as TestCase;
use Prophecy\Prophecy\ObjectProphecy;
class ShortUrlServiceTest extends TestCase
{
/**
* @var ShortUrlService
*/
protected $service;
/**
* @var ObjectProphecy|EntityManagerInterface
*/
protected $em;
public function setUp()
{
$this->em = $this->prophesize(EntityManagerInterface::class);
$this->service = new ShortUrlService($this->em->reveal());
}
/**
* @test
*/
public function listedUrlsAreReturnedFromEntityManager()
{
$repo = $this->prophesize(EntityRepository::class);
$repo->findAll()->willReturn([
new ShortUrl(),
new ShortUrl(),
new ShortUrl(),
new ShortUrl(),
])->shouldBeCalledTimes(1);
$this->em->getRepository(ShortUrl::class)->willReturn($repo->reveal());
$list = $this->service->listShortUrls();
$this->assertCount(4, $list);
}
}