Managed error while generating URL previews by throwing an exception

This commit is contained in:
Alejandro Celaya 2016-08-18 11:16:56 +02:00
parent 277406c3b8
commit 60c68c914b
6 changed files with 48 additions and 4 deletions

View file

@ -2,9 +2,10 @@
return [ return [
'phpwkhtmltopdf' => [ 'phpwkhtmltopdf' => [
'files_location' => 'data/cache',
'images' => [ 'images' => [
'binary' => 'bin/wkhtmltoimage', 'binary' => 'bin/wkhtmltoimage',
'files_location' => 'data/cache/previews', 'type' => 'jpg',
], ],
], ],

View file

@ -0,0 +1,10 @@
<?php
namespace Shlinkio\Shlink\Common\Exception;
class PreviewGenerationException extends RuntimeException
{
public static function fromImageError($error)
{
return new self(sprintf('Error generating a preview image with error: %s', $error));
}
}

View file

@ -4,6 +4,7 @@ namespace Shlinkio\Shlink\Common\Service;
use Acelaya\ZsmAnnotatedServices\Annotation\Inject; use Acelaya\ZsmAnnotatedServices\Annotation\Inject;
use Doctrine\Common\Cache\Cache; use Doctrine\Common\Cache\Cache;
use mikehaertl\wkhtmlto\Image; use mikehaertl\wkhtmlto\Image;
use Shlinkio\Shlink\Common\Exception\PreviewGenerationException;
class PreviewGenerator implements PreviewGeneratorInterface class PreviewGenerator implements PreviewGeneratorInterface
{ {
@ -26,7 +27,7 @@ class PreviewGenerator implements PreviewGeneratorInterface
* @param Cache $cache * @param Cache $cache
* @param string $location * @param string $location
* *
* @Inject({Image::class, Cache::class, "config.phpwkhtmltopdf.images.files_location"}) * @Inject({Image::class, Cache::class, "config.phpwkhtmltopdf.files_location"})
*/ */
public function __construct(Image $image, Cache $cache, $location) public function __construct(Image $image, Cache $cache, $location)
{ {
@ -40,10 +41,11 @@ class PreviewGenerator implements PreviewGeneratorInterface
* *
* @param string $url * @param string $url
* @return string * @return string
* @throws PreviewGenerationException
*/ */
public function generatePreview($url) public function generatePreview($url)
{ {
$cacheId = sprintf('preview_%s.png', urlencode($url)); $cacheId = sprintf('preview_%s.%s', urlencode($url), $this->image->type);
if ($this->cache->contains($cacheId)) { if ($this->cache->contains($cacheId)) {
return $this->cache->fetch($cacheId); return $this->cache->fetch($cacheId);
} }
@ -51,8 +53,15 @@ class PreviewGenerator implements PreviewGeneratorInterface
$path = $this->location . '/' . $cacheId; $path = $this->location . '/' . $cacheId;
$this->image->setPage($url); $this->image->setPage($url);
$this->image->saveAs($path); $this->image->saveAs($path);
$this->cache->save($cacheId, $path);
// Check if an error occurred
$error = $this->image->getError();
if (! empty($error)) {
throw PreviewGenerationException::fromImageError($error);
}
// Cache the path and return it
$this->cache->save($cacheId, $path);
return $path; return $path;
} }
} }

View file

@ -1,6 +1,8 @@
<?php <?php
namespace Shlinkio\Shlink\Common\Service; namespace Shlinkio\Shlink\Common\Service;
use Shlinkio\Shlink\Common\Exception\PreviewGenerationException;
interface PreviewGeneratorInterface interface PreviewGeneratorInterface
{ {
/** /**
@ -8,6 +10,7 @@ interface PreviewGeneratorInterface
* *
* @param string $url * @param string $url
* @return string * @return string
* @throws PreviewGenerationException
*/ */
public function generatePreview($url); public function generatePreview($url);
} }

View file

@ -52,9 +52,27 @@ class PreviewGeneratorTest extends TestCase
$this->image->setPage($url)->shouldBeCalledTimes(1); $this->image->setPage($url)->shouldBeCalledTimes(1);
$this->image->saveAs($expectedPath)->shouldBeCalledTimes(1); $this->image->saveAs($expectedPath)->shouldBeCalledTimes(1);
$this->image->getError()->willReturn('')->shouldBeCalledTimes(1);
$this->assertFalse($this->cache->contains($cacheId)); $this->assertFalse($this->cache->contains($cacheId));
$this->assertEquals($expectedPath, $this->generator->generatePreview($url)); $this->assertEquals($expectedPath, $this->generator->generatePreview($url));
$this->assertTrue($this->cache->contains($cacheId)); $this->assertTrue($this->cache->contains($cacheId));
} }
/**
* @test
* @expectedException \Shlinkio\Shlink\Common\Exception\PreviewGenerationException
*/
public function errorWhileGeneratingPreviewThrowsException()
{
$url = 'http://foo.com';
$cacheId = sprintf('preview_%s.png', urlencode($url));
$expectedPath = 'dir/' . $cacheId;
$this->image->setPage($url)->shouldBeCalledTimes(1);
$this->image->saveAs($expectedPath)->shouldBeCalledTimes(1);
$this->image->getError()->willReturn('Error!!')->shouldBeCalledTimes(1);
$this->generator->generatePreview($url);
}
} }

View file

@ -4,6 +4,7 @@ namespace Shlinkio\Shlink\Core\Action;
use Acelaya\ZsmAnnotatedServices\Annotation\Inject; use Acelaya\ZsmAnnotatedServices\Annotation\Inject;
use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Http\Message\ServerRequestInterface as Request;
use Shlinkio\Shlink\Common\Exception\PreviewGenerationException;
use Shlinkio\Shlink\Common\Service\PreviewGenerator; use Shlinkio\Shlink\Common\Service\PreviewGenerator;
use Shlinkio\Shlink\Common\Service\PreviewGeneratorInterface; use Shlinkio\Shlink\Common\Service\PreviewGeneratorInterface;
use Shlinkio\Shlink\Common\Util\ResponseUtilsTrait; use Shlinkio\Shlink\Common\Util\ResponseUtilsTrait;
@ -77,6 +78,8 @@ class PreviewAction implements MiddlewareInterface
return $this->generateImageResponse($imagePath); return $this->generateImageResponse($imagePath);
} catch (InvalidShortCodeException $e) { } catch (InvalidShortCodeException $e) {
return $out($request, $response->withStatus(404), 'Not found'); return $out($request, $response->withStatus(404), 'Not found');
} catch (PreviewGenerationException $e) {
return $out($request, $response->withStatus(500), 'Preview generation error');
} }
} }
} }