mirror of
https://github.com/flarum/framework.git
synced 2024-11-27 11:03:37 +08:00
Wire up new error handling stack
This commit is contained in:
parent
3417f5a77e
commit
cfbaa84fbc
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Foundation\ErrorHandling\ExceptionHandler;
|
||||
|
||||
use Flarum\Foundation\ErrorHandling\HandledError;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class IlluminateValidationExceptionHandler
|
||||
{
|
||||
public function handle(ValidationException $e): HandledError
|
||||
{
|
||||
return (new HandledError(
|
||||
$e, 'validation_error', 422
|
||||
))->withDetails($this->errorDetails($e));
|
||||
}
|
||||
|
||||
protected function errorDetails(ValidationException $e): array
|
||||
{
|
||||
$errors = $e->errors();
|
||||
|
||||
return array_map(function ($field, $messages) {
|
||||
return [
|
||||
'detail' => implode("\n", $messages),
|
||||
'source' => ['pointer' => "/data/attributes/$field"]
|
||||
];
|
||||
}, array_keys($errors), $errors);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Foundation\ErrorHandling\ExceptionHandler;
|
||||
|
||||
use Flarum\Foundation\ErrorHandling\HandledError;
|
||||
use Flarum\Foundation\ValidationException;
|
||||
|
||||
class ValidationExceptionHandler
|
||||
{
|
||||
public function handle(ValidationException $e)
|
||||
{
|
||||
return (new HandledError(
|
||||
$e, 'validation_error', 422
|
||||
))->withDetails(array_merge(
|
||||
$this->buildDetails($e->getAttributes(), '/data/attributes'),
|
||||
$this->buildDetails($e->getRelationships(), '/data/relationships')
|
||||
));
|
||||
}
|
||||
|
||||
private function buildDetails(array $messages, $pointer): array
|
||||
{
|
||||
return array_map(function ($path, $detail) use ($pointer) {
|
||||
return [
|
||||
'detail' => $detail,
|
||||
'source' => ['pointer' => $pointer.'/'.$path]
|
||||
];
|
||||
}, array_keys($messages), $messages);
|
||||
}
|
||||
}
|
76
src/Foundation/ErrorServiceProvider.php
Normal file
76
src/Foundation/ErrorServiceProvider.php
Normal file
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Foundation;
|
||||
|
||||
use Flarum\Foundation\ErrorHandling\ExceptionHandler;
|
||||
use Flarum\Foundation\ErrorHandling\LogReporter;
|
||||
use Flarum\Foundation\ErrorHandling\Registry;
|
||||
use Flarum\Foundation\ErrorHandling\Reporter;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use Illuminate\Validation\ValidationException as IlluminateValidationException;
|
||||
use Tobscure\JsonApi\Exception\InvalidParameterException;
|
||||
|
||||
class ErrorServiceProvider extends AbstractServiceProvider
|
||||
{
|
||||
public function register()
|
||||
{
|
||||
$this->app->singleton('flarum.error.statuses', function () {
|
||||
return [
|
||||
// 400 Bad Request
|
||||
'csrf_token_mismatch' => 400,
|
||||
'invalid_parameter' => 400,
|
||||
|
||||
// 401 Unauthorized
|
||||
'invalid_access_token' => 401,
|
||||
|
||||
// 403 Forbidden
|
||||
'forbidden' => 403,
|
||||
'invalid_confirmation_token' => 403,
|
||||
'permission_denied' => 403,
|
||||
|
||||
// 404 Not Found
|
||||
'model_not_found' => 404,
|
||||
'route_not_found' => 404,
|
||||
|
||||
// 405 Method Not Allowed
|
||||
'method_not_allowed' => 405,
|
||||
|
||||
// 429 Too Many Requests
|
||||
'too_many_requests' => 429,
|
||||
];
|
||||
});
|
||||
|
||||
$this->app->singleton('flarum.error.classes', function () {
|
||||
return [
|
||||
InvalidParameterException::class => 'invalid_parameter',
|
||||
ModelNotFoundException::class => 'model_not_found',
|
||||
];
|
||||
});
|
||||
|
||||
$this->app->singleton('flarum.error.handlers', function () {
|
||||
return [
|
||||
IlluminateValidationException::class => ExceptionHandler\IlluminateValidationExceptionHandler::class,
|
||||
ValidationException::class => ExceptionHandler\ValidationExceptionHandler::class,
|
||||
];
|
||||
});
|
||||
|
||||
$this->app->singleton(Registry::class, function () {
|
||||
return new Registry(
|
||||
$this->app->make('flarum.error.statuses'),
|
||||
$this->app->make('flarum.error.classes'),
|
||||
$this->app->make('flarum.error.handlers')
|
||||
);
|
||||
});
|
||||
|
||||
$this->app->singleton(Reporter::class, LogReporter::class);
|
||||
}
|
||||
}
|
|
@ -117,6 +117,7 @@ class InstalledSite implements SiteInterface
|
|||
$laravel->register(DatabaseServiceProvider::class);
|
||||
$laravel->register(DiscussionServiceProvider::class);
|
||||
$laravel->register(ExtensionServiceProvider::class);
|
||||
$laravel->register(ErrorServiceProvider::class);
|
||||
$laravel->register(FilesystemServiceProvider::class);
|
||||
$laravel->register(FormatterServiceProvider::class);
|
||||
$laravel->register(ForumServiceProvider::class);
|
||||
|
|
|
@ -69,6 +69,7 @@ class UninstalledSite implements SiteInterface
|
|||
|
||||
$this->registerLogger($laravel);
|
||||
|
||||
$laravel->register(ErrorServiceProvider::class);
|
||||
$laravel->register(LocaleServiceProvider::class);
|
||||
$laravel->register(FilesystemServiceProvider::class);
|
||||
$laravel->register(SessionServiceProvider::class);
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Tests\unit\Foundation\ErrorHandling\ExceptionHandler;
|
||||
|
||||
use Flarum\Foundation\ErrorHandling\ExceptionHandler\IlluminateValidationExceptionHandler;
|
||||
use Illuminate\Translation\ArrayLoader;
|
||||
use Illuminate\Translation\Translator;
|
||||
use Illuminate\Validation\Factory;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class IlluminateValidationExceptionHandlerTest extends TestCase
|
||||
{
|
||||
private $handler;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->handler = new IlluminateValidationExceptionHandler;
|
||||
}
|
||||
|
||||
public function test_it_creates_the_desired_output()
|
||||
{
|
||||
$exception = new ValidationException($this->makeValidator(['foo' => ''], ['foo' => 'required']));
|
||||
|
||||
$error = $this->handler->handle($exception);
|
||||
|
||||
$this->assertEquals(422, $error->getStatusCode());
|
||||
$this->assertEquals('validation_error', $error->getType());
|
||||
$this->assertEquals([
|
||||
[
|
||||
'detail' => 'validation.required',
|
||||
'source' => ['pointer' => '/data/attributes/foo']
|
||||
]
|
||||
], $error->getDetails());
|
||||
}
|
||||
|
||||
private function makeValidator($data = [], $rules = [])
|
||||
{
|
||||
$translator = new Translator(new ArrayLoader(), 'en');
|
||||
$factory = new Factory($translator);
|
||||
|
||||
return $factory->make($data, $rules);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Tests\unit\Foundation\ErrorHandling\ExceptionHandler;
|
||||
|
||||
use Flarum\Foundation\ErrorHandling\ExceptionHandler\ValidationExceptionHandler;
|
||||
use Flarum\Foundation\ValidationException;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ValidationExceptionHandlerTest extends TestCase
|
||||
{
|
||||
private $handler;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->handler = new ValidationExceptionHandler;
|
||||
}
|
||||
|
||||
public function test_managing_exceptions()
|
||||
{
|
||||
$error = $this->handler->handle(new ValidationException(
|
||||
['foo' => 'Attribute error'],
|
||||
['bar' => 'Relationship error']
|
||||
));
|
||||
|
||||
$this->assertEquals(422, $error->getStatusCode());
|
||||
$this->assertEquals('validation_error', $error->getType());
|
||||
$this->assertEquals([
|
||||
[
|
||||
'detail' => 'Attribute error',
|
||||
'source' => ['pointer' => '/data/attributes/foo']
|
||||
],
|
||||
[
|
||||
'detail' => 'Relationship error',
|
||||
'source' => ['pointer' => '/data/relationships/bar']
|
||||
]
|
||||
], $error->getDetails());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user