mirror of
https://github.com/shlinkio/shlink.git
synced 2024-12-23 07:33:58 -06:00
Merge branch 'feature/29' into develop
This commit is contained in:
commit
2b2c0b7c13
@ -23,6 +23,7 @@
|
||||
"zendframework/zend-i18n": "^2.7",
|
||||
"mtymek/expressive-config-manager": "^0.4",
|
||||
"acelaya/zsm-annotated-services": "^0.2.0",
|
||||
"acelaya/ze-content-based-error-handler": "^1.0",
|
||||
"doctrine/orm": "^2.5",
|
||||
"guzzlehttp/guzzle": "^6.2",
|
||||
"symfony/console": "^3.0",
|
||||
|
@ -1,5 +1,4 @@
|
||||
<?php
|
||||
use Shlinkio\Shlink\Common\ErrorHandler\ContentBasedErrorHandler;
|
||||
use Zend\Expressive;
|
||||
use Zend\Expressive\Container;
|
||||
use Zend\Expressive\Router;
|
||||
@ -17,7 +16,6 @@ return [
|
||||
],
|
||||
'aliases' => [
|
||||
Router\RouterInterface::class => Router\FastRouteRouter::class,
|
||||
'Zend\Expressive\FinalHandler' => ContentBasedErrorHandler::class,
|
||||
],
|
||||
],
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?php
|
||||
use Shlinkio\Shlink\Common\ErrorHandler\ContentBasedErrorHandler;
|
||||
use Acelaya\ExpressiveErrorHandler\ErrorHandler\ContentBasedErrorHandler;
|
||||
use Zend\Expressive\Container\WhoopsErrorHandlerFactory;
|
||||
|
||||
return [
|
||||
|
@ -1,4 +1,5 @@
|
||||
<?php
|
||||
use Acelaya\ExpressiveErrorHandler\ConfigProvider as ErrorHandlerProvider;
|
||||
use Shlinkio\Shlink\CLI;
|
||||
use Shlinkio\Shlink\Common;
|
||||
use Shlinkio\Shlink\Core;
|
||||
@ -16,6 +17,7 @@ use Zend\Expressive\ConfigManager\ZendConfigProvider;
|
||||
*/
|
||||
|
||||
return (new ConfigManager([
|
||||
ErrorHandlerProvider::class,
|
||||
Common\ConfigProvider::class,
|
||||
Core\ConfigProvider::class,
|
||||
CLI\ConfigProvider::class,
|
||||
|
@ -4,7 +4,6 @@ use Doctrine\Common\Cache\Cache;
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Monolog\Logger;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Shlinkio\Shlink\Common\ErrorHandler;
|
||||
use Shlinkio\Shlink\Common\Factory\CacheFactory;
|
||||
use Shlinkio\Shlink\Common\Factory\EntityManagerFactory;
|
||||
use Shlinkio\Shlink\Common\Factory\LoggerFactory;
|
||||
@ -22,7 +21,6 @@ return [
|
||||
EntityManager::class => EntityManagerFactory::class,
|
||||
GuzzleHttp\Client::class => InvokableFactory::class,
|
||||
Cache::class => CacheFactory::class,
|
||||
LoggerInterface::class => LoggerFactory::class,
|
||||
'Logger_Shlink' => LoggerFactory::class,
|
||||
|
||||
Translator::class => TranslatorFactory::class,
|
||||
@ -30,17 +28,15 @@ return [
|
||||
LocaleMiddleware::class => AnnotatedFactory::class,
|
||||
|
||||
IpLocationResolver::class => AnnotatedFactory::class,
|
||||
|
||||
ErrorHandler\ContentBasedErrorHandler::class => AnnotatedFactory::class,
|
||||
ErrorHandler\ErrorHandlerManager::class => ErrorHandler\ErrorHandlerManagerFactory::class,
|
||||
],
|
||||
'aliases' => [
|
||||
'em' => EntityManager::class,
|
||||
'httpClient' => GuzzleHttp\Client::class,
|
||||
'translator' => Translator::class,
|
||||
'logger' => LoggerInterface::class,
|
||||
Logger::class => LoggerInterface::class,
|
||||
AnnotatedFactory::CACHE_SERVICE => Cache::class,
|
||||
Logger::class => 'Logger_Shlink',
|
||||
LoggerInterface::class => 'Logger_Shlink',
|
||||
],
|
||||
],
|
||||
|
||||
|
@ -1,22 +0,0 @@
|
||||
<?php
|
||||
use Shlinkio\Shlink\Common\ErrorHandler\ContentBasedErrorHandler;
|
||||
use Zend\Expressive\Container\TemplatedErrorHandlerFactory;
|
||||
use Zend\Stratigility\FinalHandler;
|
||||
|
||||
return [
|
||||
|
||||
'error_handler' => [
|
||||
'plugins' => [
|
||||
'invokables' => [
|
||||
'text/plain' => FinalHandler::class,
|
||||
],
|
||||
'factories' => [
|
||||
ContentBasedErrorHandler::DEFAULT_CONTENT => TemplatedErrorHandlerFactory::class,
|
||||
],
|
||||
'aliases' => [
|
||||
'application/xhtml+xml' => ContentBasedErrorHandler::DEFAULT_CONTENT,
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
];
|
@ -1,76 +0,0 @@
|
||||
<?php
|
||||
namespace Shlinkio\Shlink\Common\ErrorHandler;
|
||||
|
||||
use Acelaya\ZsmAnnotatedServices\Annotation\Inject;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Shlinkio\Shlink\Common\Exception\InvalidArgumentException;
|
||||
|
||||
class ContentBasedErrorHandler implements ErrorHandlerInterface
|
||||
{
|
||||
const DEFAULT_CONTENT = 'text/html';
|
||||
|
||||
/**
|
||||
* @var ErrorHandlerManagerInterface
|
||||
*/
|
||||
private $errorHandlerManager;
|
||||
|
||||
/**
|
||||
* ContentBasedErrorHandler constructor.
|
||||
* @param ErrorHandlerManagerInterface|ErrorHandlerManager $errorHandlerManager
|
||||
*
|
||||
* @Inject({ErrorHandlerManager::class})
|
||||
*/
|
||||
public function __construct(ErrorHandlerManagerInterface $errorHandlerManager)
|
||||
{
|
||||
$this->errorHandlerManager = $errorHandlerManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Final handler for an application.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Response $response
|
||||
* @param null|mixed $err
|
||||
* @return Response
|
||||
*/
|
||||
public function __invoke(Request $request, Response $response, $err = null)
|
||||
{
|
||||
// Try to get an error handler for provided request accepted type
|
||||
$errorHandler = $this->resolveErrorHandlerFromAcceptHeader($request);
|
||||
return $errorHandler($request, $response, $err);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to resolve
|
||||
*
|
||||
* @param Request $request
|
||||
* @return callable
|
||||
*/
|
||||
protected function resolveErrorHandlerFromAcceptHeader(Request $request)
|
||||
{
|
||||
// Try to find an error handler for one of the accepted content types
|
||||
$accepts = $request->hasHeader('Accept') ? $request->getHeaderLine('Accept') : self::DEFAULT_CONTENT;
|
||||
$accepts = explode(',', $accepts);
|
||||
foreach ($accepts as $accept) {
|
||||
if (! $this->errorHandlerManager->has($accept)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return $this->errorHandlerManager->get($accept);
|
||||
}
|
||||
|
||||
// If it wasn't possible to find an error handler for accepted content type, use default one if registered
|
||||
if ($this->errorHandlerManager->has(self::DEFAULT_CONTENT)) {
|
||||
return $this->errorHandlerManager->get(self::DEFAULT_CONTENT);
|
||||
}
|
||||
|
||||
// It wasn't possible to find an error handler
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'It wasn\'t possible to find an error handler for ["%s"] content types. '
|
||||
. 'Make sure you have registered at least the default "%s" content type',
|
||||
implode('", "', $accepts),
|
||||
self::DEFAULT_CONTENT
|
||||
));
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
<?php
|
||||
namespace Shlinkio\Shlink\Common\ErrorHandler;
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
|
||||
interface ErrorHandlerInterface
|
||||
{
|
||||
/**
|
||||
* Final handler for an application.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Response $response
|
||||
* @param null|mixed $err
|
||||
* @return Response
|
||||
*/
|
||||
public function __invoke(Request $request, Response $response, $err = null);
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
<?php
|
||||
namespace Shlinkio\Shlink\Common\ErrorHandler;
|
||||
|
||||
use Zend\ServiceManager\AbstractPluginManager;
|
||||
use Zend\ServiceManager\Exception\InvalidServiceException;
|
||||
|
||||
class ErrorHandlerManager extends AbstractPluginManager implements ErrorHandlerManagerInterface
|
||||
{
|
||||
public function validate($instance)
|
||||
{
|
||||
if (is_callable($instance)) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw new InvalidServiceException(sprintf(
|
||||
'Only callables are valid plugins for "%s". "%s" provided',
|
||||
__CLASS__,
|
||||
is_object($instance) ? get_class($instance) : gettype($instance)
|
||||
));
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
<?php
|
||||
namespace Shlinkio\Shlink\Common\ErrorHandler;
|
||||
|
||||
use Interop\Container\ContainerInterface;
|
||||
use Interop\Container\Exception\ContainerException;
|
||||
use Zend\ServiceManager\Exception\ServiceNotCreatedException;
|
||||
use Zend\ServiceManager\Exception\ServiceNotFoundException;
|
||||
use Zend\ServiceManager\Factory\FactoryInterface;
|
||||
|
||||
class ErrorHandlerManagerFactory implements FactoryInterface
|
||||
{
|
||||
/**
|
||||
* Create an object
|
||||
*
|
||||
* @param ContainerInterface $container
|
||||
* @param string $requestedName
|
||||
* @param null|array $options
|
||||
* @return object
|
||||
* @throws ServiceNotFoundException if unable to resolve the service.
|
||||
* @throws ServiceNotCreatedException if an exception is raised when
|
||||
* creating a service.
|
||||
* @throws ContainerException if any other error occurs
|
||||
*/
|
||||
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
|
||||
{
|
||||
$config = $container->get('config')['error_handler'];
|
||||
$plugins = isset($config['plugins']) ? $config['plugins'] : [];
|
||||
return new ErrorHandlerManager($container, $plugins);
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
<?php
|
||||
namespace Shlinkio\Shlink\Common\ErrorHandler;
|
||||
|
||||
use Interop\Container\ContainerInterface;
|
||||
|
||||
interface ErrorHandlerManagerInterface extends ContainerInterface
|
||||
{
|
||||
|
||||
}
|
@ -23,7 +23,6 @@ class ConfigProviderTest extends TestCase
|
||||
{
|
||||
$config = $this->configProvider->__invoke();
|
||||
|
||||
$this->assertArrayHasKey('error_handler', $config);
|
||||
$this->assertArrayHasKey('middleware_pipeline', $config);
|
||||
$this->assertArrayHasKey('dependencies', $config);
|
||||
$this->assertArrayHasKey('twig', $config);
|
||||
|
@ -1,75 +0,0 @@
|
||||
<?php
|
||||
namespace ShlinkioTest\Shlink\Common\ErrorHandler;
|
||||
|
||||
use PHPUnit_Framework_TestCase as TestCase;
|
||||
use Shlinkio\Shlink\Common\ErrorHandler\ContentBasedErrorHandler;
|
||||
use Shlinkio\Shlink\Common\ErrorHandler\ErrorHandlerManager;
|
||||
use Zend\Diactoros\Response;
|
||||
use Zend\Diactoros\ServerRequestFactory;
|
||||
use Zend\ServiceManager\ServiceManager;
|
||||
|
||||
class ContentBasedErrorHandlerTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var ContentBasedErrorHandler
|
||||
*/
|
||||
protected $errorHandler;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->errorHandler = new ContentBasedErrorHandler(new ErrorHandlerManager(new ServiceManager(), [
|
||||
'factories' => [
|
||||
'text/html' => [$this, 'factory'],
|
||||
'application/json' => [$this, 'factory'],
|
||||
],
|
||||
]));
|
||||
}
|
||||
|
||||
public function factory($container, $name)
|
||||
{
|
||||
return function () use ($name) {
|
||||
return $name;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function correctAcceptHeaderValueInvokesErrorHandler()
|
||||
{
|
||||
$request = ServerRequestFactory::fromGlobals()->withHeader('Accept', 'foo/bar,application/json');
|
||||
$result = $this->errorHandler->__invoke($request, new Response());
|
||||
$this->assertEquals('application/json', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function defaultContentTypeIsUsedWhenNoAcceptHeaderisPresent()
|
||||
{
|
||||
$request = ServerRequestFactory::fromGlobals();
|
||||
$result = $this->errorHandler->__invoke($request, new Response());
|
||||
$this->assertEquals('text/html', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function defaultContentTypeIsUsedWhenAcceptedContentIsNotSupported()
|
||||
{
|
||||
$request = ServerRequestFactory::fromGlobals()->withHeader('Accept', 'foo/bar,text/xml');
|
||||
$result = $this->errorHandler->__invoke($request, new Response());
|
||||
$this->assertEquals('text/html', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @expectedException \Shlinkio\Shlink\Common\Exception\InvalidArgumentException
|
||||
*/
|
||||
public function ifNoErrorHandlerIsFoundAnExceptionIsThrown()
|
||||
{
|
||||
$this->errorHandler = new ContentBasedErrorHandler(new ErrorHandlerManager(new ServiceManager(), []));
|
||||
$request = ServerRequestFactory::fromGlobals()->withHeader('Accept', 'foo/bar,text/xml');
|
||||
$result = $this->errorHandler->__invoke($request, new Response());
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
<?php
|
||||
namespace ShlinkioTest\Shlink\Common\ErrorHandler;
|
||||
|
||||
use PHPUnit_Framework_TestCase as TestCase;
|
||||
use Shlinkio\Shlink\Common\ErrorHandler\ErrorHandlerManager;
|
||||
use Shlinkio\Shlink\Common\ErrorHandler\ErrorHandlerManagerFactory;
|
||||
use Zend\ServiceManager\ServiceManager;
|
||||
|
||||
class ErrorHandlerManagerFactoryTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var ErrorHandlerManagerFactory
|
||||
*/
|
||||
protected $factory;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->factory = new ErrorHandlerManagerFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function serviceIsCreated()
|
||||
{
|
||||
$instance = $this->factory->__invoke(new ServiceManager(['services' => [
|
||||
'config' => [
|
||||
'error_handler' => [
|
||||
'plugins' => [],
|
||||
],
|
||||
],
|
||||
]]), '');
|
||||
$this->assertInstanceOf(ErrorHandlerManager::class, $instance);
|
||||
}
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
<?php
|
||||
namespace ShlinkioTest\Shlink\Common\ErrorHandler;
|
||||
|
||||
use PHPUnit_Framework_TestCase as TestCase;
|
||||
use Shlinkio\Shlink\Common\ErrorHandler\ErrorHandlerManager;
|
||||
use Zend\ServiceManager\ServiceManager;
|
||||
|
||||
class ErrorHandlerManagerTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var ErrorHandlerManager
|
||||
*/
|
||||
protected $pluginManager;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->pluginManager = new ErrorHandlerManager(new ServiceManager(), [
|
||||
'services' => [
|
||||
'foo' => function () {
|
||||
},
|
||||
],
|
||||
'invokables' => [
|
||||
'invalid' => \stdClass::class,
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
*/
|
||||
public function callablesAreReturned()
|
||||
{
|
||||
$instance = $this->pluginManager->get('foo');
|
||||
$this->assertInstanceOf(\Closure::class, $instance);
|
||||
}
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @expectedException \Zend\ServiceManager\Exception\InvalidServiceException
|
||||
*/
|
||||
public function nonCallablesThrowException()
|
||||
{
|
||||
$this->pluginManager->get('invalid');
|
||||
}
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
<?php
|
||||
namespace Shlinkio\Shlink\Rest\ErrorHandler;
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Acelaya\ExpressiveErrorHandler\ErrorHandler\ErrorHandlerInterface;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Shlinkio\Shlink\Common\ErrorHandler\ErrorHandlerInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Zend\Diactoros\Response\JsonResponse;
|
||||
use Zend\Expressive\Router\RouteResult;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user