Skip to content

Commit

Permalink
Use laravel's new accepts method
Browse files Browse the repository at this point in the history
  • Loading branch information
Graham Campbell committed May 28, 2015
1 parent b4693e5 commit 6fed80f
Show file tree
Hide file tree
Showing 9 changed files with 83 additions and 62 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ CHANGE LOG

## V3.0 (Upcoming)

* Drop support for laravel 5.0
* Improved the error info class
* Return empty body and no content type if we can't match a displayer
* Conformed to json api standards
* Use laravel's new accepts method


## V2.0.1 (26/05/2015)
Expand Down
8 changes: 4 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
],
"require": {
"php": ">=5.5.9",
"illuminate/contracts": "5.0.*|5.1.*",
"illuminate/support": "5.0.*|5.1.*",
"symfony/debug": "2.6.*|2.7.*",
"symfony/http-foundation": "2.6.*|2.7.*",
"illuminate/contracts": "5.1.*",
"illuminate/support": "5.1.*",
"symfony/debug": "2.7.*",
"symfony/http-foundation": "2.7.*",
"filp/whoops": "1.1.*",
"psr/log": "~1.0"
},
Expand Down
1 change: 1 addition & 0 deletions config/exceptions.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
'GrahamCampbell\Exceptions\Displayers\DebugDisplayer',
'GrahamCampbell\Exceptions\Displayers\HtmlDisplayer',
'GrahamCampbell\Exceptions\Displayers\JsonDisplayer',
'GrahamCampbell\Exceptions\Displayers\JsonApiDisplayer',
],

/*
Expand Down
2 changes: 1 addition & 1 deletion src/Displayers/HtmlDisplayer.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public function display(Exception $exception, $code, array $headers)
{
$info = $this->info->generate($exception, $code);

return new Response($this->render($info), $code, array_merge($headers, ['Content-Type' => 'text/html']));
return new Response($this->render($info), $code, array_merge($headers, ['Content-Type' => $this->contentType()]));
}

/**
Expand Down
30 changes: 30 additions & 0 deletions src/Displayers/JsonApiDisplayer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

/*
* This file is part of Laravel Exceptions.
*
* (c) Graham Campbell <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace GrahamCampbell\Exceptions\Displayers;

/**
* This is the json api displayer class.
*
* @author Graham Campbell <[email protected]>
*/
class JsonApiDisplayer extends JsonDisplayer implements DisplayerInterface
{
/**
* Get the supported content type.
*
* @return string
*/
public function contentType()
{
return 'application/vnd.api+json';
}
}
2 changes: 1 addition & 1 deletion src/Displayers/JsonDisplayer.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public function display(Exception $exception, $code, array $headers)

$error = ['status' => $info['code'], 'title' => $info['name'], 'detail' => $info['detail']];

return new JsonResponse(['errors' => [$error]], $code, array_merge($headers, ['Content-Type' => 'application/json']));
return new JsonResponse(['errors' => [$error]], $code, array_merge($headers, ['Content-Type' => $this->contentType()]));
}

/**
Expand Down
33 changes: 2 additions & 31 deletions src/Filters/ContentTypeFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
namespace GrahamCampbell\Exceptions\Filters;

use Exception;
use GrahamCampbell\Exceptions\Displayers\DisplayerInterface;
use Illuminate\Http\Request;

/**
Expand Down Expand Up @@ -51,40 +50,12 @@ public function __construct(Request $request)
*/
public function filter(array $displayers, Exception $exception)
{
$acceptable = $this->request->getAcceptableContentTypes();

foreach ($displayers as $index => $displayer) {
foreach ($this->getContentTypes($displayer) as $type) {
if (in_array($type, $acceptable)) {
continue 2;
}
}

$split = explode('/', $displayer->contentType());

foreach ($acceptable as $type) {
if (preg_match('/'.$split[0].'\/.+\+'.$split[1].'/', $type)) {
continue 2;
}
if (!$this->request->accepts($displayer->contentType())) {
unset($displayers[$index]);
}

unset($displayers[$index]);
}

return array_values($displayers);
}

/**
* Get the content types to match.
*
* @param \GrahamCampbell\Exceptions\Displayers\DisplayerInterface $displayer
*
* @return string[]
*/
protected function getContentTypes(DisplayerInterface $displayer)
{
$type = $displayer->contentType();

return ['*/*', $type, strtok($type, '/').'/*'];
}
}
65 changes: 41 additions & 24 deletions tests/Filters/ContentTypeFilterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use Exception;
use GrahamCampbell\Exceptions\Displayers\DebugDisplayer;
use GrahamCampbell\Exceptions\Displayers\HtmlDisplayer;
use GrahamCampbell\Exceptions\Displayers\JsonApiDisplayer;
use GrahamCampbell\Exceptions\Displayers\JsonDisplayer;
use GrahamCampbell\Exceptions\ExceptionInfo;
use GrahamCampbell\Exceptions\Filters\ContentTypeFilter;
Expand All @@ -33,8 +34,8 @@ public function testAcceptAll()
$html = new HtmlDisplayer(new ExceptionInfo('foo'), 'foo');
$json = new JsonDisplayer(new ExceptionInfo('foo'));

$request = Mockery::mock('Illuminate\Http\Request');
$request->shouldReceive('getAcceptableContentTypes')->once()->andReturn(['*/*']);
$request = Mockery::mock('Illuminate\Http\Request')->makePartial();
$request->shouldReceive('getAcceptableContentTypes')->andReturn(['*/*']);

$displayers = (new ContentTypeFilter($request))->filter([$debug, $html, $json], new Exception());

Expand All @@ -47,8 +48,8 @@ public function testAcceptHtmlAndAll()
$html = new HtmlDisplayer(new ExceptionInfo('foo'), 'foo');
$json = new JsonDisplayer(new ExceptionInfo('foo'));

$request = Mockery::mock('Illuminate\Http\Request');
$request->shouldReceive('getAcceptableContentTypes')->once()->andReturn(['text/html', '*/*']);
$request = Mockery::mock('Illuminate\Http\Request')->makePartial();
$request->shouldReceive('getAcceptableContentTypes')->andReturn(['text/html', '*/*']);

$displayers = (new ContentTypeFilter($request))->filter([$debug, $html, $json], new Exception());

Expand All @@ -61,8 +62,8 @@ public function testAcceptJustHtml()
$html = new HtmlDisplayer(new ExceptionInfo('foo'), 'foo');
$json = new JsonDisplayer(new ExceptionInfo('foo'));

$request = Mockery::mock('Illuminate\Http\Request');
$request->shouldReceive('getAcceptableContentTypes')->once()->andReturn(['text/html']);
$request = Mockery::mock('Illuminate\Http\Request')->makePartial();
$request->shouldReceive('getAcceptableContentTypes')->andReturn(['text/html']);

$displayers = (new ContentTypeFilter($request))->filter([$debug, $html, $json], new Exception());

Expand All @@ -75,8 +76,8 @@ public function testAcceptText()
$html = new HtmlDisplayer(new ExceptionInfo('foo'), 'foo');
$json = new JsonDisplayer(new ExceptionInfo('foo'));

$request = Mockery::mock('Illuminate\Http\Request');
$request->shouldReceive('getAcceptableContentTypes')->once()->andReturn(['text/*']);
$request = Mockery::mock('Illuminate\Http\Request')->makePartial();
$request->shouldReceive('getAcceptableContentTypes')->andReturn(['text/*']);

$displayers = (new ContentTypeFilter($request))->filter([$debug, $html, $json], new Exception());

Expand All @@ -89,8 +90,8 @@ public function testAcceptJsonAndAll()
$html = new HtmlDisplayer(new ExceptionInfo('foo'), 'foo');
$json = new JsonDisplayer(new ExceptionInfo('foo'));

$request = Mockery::mock('Illuminate\Http\Request');
$request->shouldReceive('getAcceptableContentTypes')->once()->andReturn(['application/json', '*/*']);
$request = Mockery::mock('Illuminate\Http\Request')->makePartial();
$request->shouldReceive('getAcceptableContentTypes')->andReturn(['application/json', '*/*']);

$displayers = (new ContentTypeFilter($request))->filter([$debug, $html, $json], new Exception());

Expand All @@ -103,8 +104,8 @@ public function testAcceptJustJson()
$html = new HtmlDisplayer(new ExceptionInfo('foo'), 'foo');
$json = new JsonDisplayer(new ExceptionInfo('foo'));

$request = Mockery::mock('Illuminate\Http\Request');
$request->shouldReceive('getAcceptableContentTypes')->once()->andReturn(['application/json']);
$request = Mockery::mock('Illuminate\Http\Request')->makePartial();
$request->shouldReceive('getAcceptableContentTypes')->andReturn(['application/json']);

$displayers = (new ContentTypeFilter($request))->filter([$debug, $html, $json], new Exception());

Expand All @@ -116,27 +117,43 @@ public function testAcceptApplication()
$debug = new DebugDisplayer();
$html = new HtmlDisplayer(new ExceptionInfo('foo'), 'foo');
$json = new JsonDisplayer(new ExceptionInfo('foo'));
$api = new JsonApiDisplayer(new ExceptionInfo('bar'));

$request = Mockery::mock('Illuminate\Http\Request');
$request->shouldReceive('getAcceptableContentTypes')->once()->andReturn(['application/*']);
$request = Mockery::mock('Illuminate\Http\Request')->makePartial();
$request->shouldReceive('getAcceptableContentTypes')->andReturn(['application/*']);

$displayers = (new ContentTypeFilter($request))->filter([$debug, $html, $json], new Exception());
$displayers = (new ContentTypeFilter($request))->filter([$debug, $html, $json, $api], new Exception());

$this->assertSame([$json], $displayers);
$this->assertSame([$json, $api], $displayers);
}

public function testAcceptComplexJson()
{
$debug = new DebugDisplayer();
$html = new HtmlDisplayer(new ExceptionInfo('foo'), 'foo');
$json = new JsonDisplayer(new ExceptionInfo('foo'));
$api = new JsonApiDisplayer(new ExceptionInfo('bar'));

$request = Mockery::mock('Illuminate\Http\Request');
$request->shouldReceive('getAcceptableContentTypes')->once()->andReturn(['application/foo+json']);
$request = Mockery::mock('Illuminate\Http\Request')->makePartial();
$request->shouldReceive('getAcceptableContentTypes')->andReturn(['application/foo+json']);

$displayers = (new ContentTypeFilter($request))->filter([$debug, $html, $json], new Exception());
$displayers = (new ContentTypeFilter($request))->filter([$debug, $html, $json, $api], new Exception());

$this->assertSame([$json], $displayers);
$this->assertSame([], $displayers);
}

public function testAcceptJsonApi()
{
$debug = new DebugDisplayer();
$json = new JsonDisplayer(new ExceptionInfo('foo'));
$api = new JsonApiDisplayer(new ExceptionInfo('bar'));

$request = Mockery::mock('Illuminate\Http\Request')->makePartial();
$request->shouldReceive('getAcceptableContentTypes')->andReturn(['application/vnd.api+json']);

$displayers = (new ContentTypeFilter($request))->filter([$debug, $json, $api], new Exception());

$this->assertSame([$api], $displayers);
}

public function testAcceptManyThings()
Expand All @@ -145,8 +162,8 @@ public function testAcceptManyThings()
$html = new HtmlDisplayer(new ExceptionInfo('foo'), 'foo');
$json = new JsonDisplayer(new ExceptionInfo('foo'));

$request = Mockery::mock('Illuminate\Http\Request');
$request->shouldReceive('getAcceptableContentTypes')->once()->andReturn(['text/*', 'application/foo+xml']);
$request = Mockery::mock('Illuminate\Http\Request')->makePartial();
$request->shouldReceive('getAcceptableContentTypes')->andReturn(['text/*', 'application/foo+xml']);

$displayers = (new ContentTypeFilter($request))->filter([$debug, $html, $json], new Exception());

Expand All @@ -159,8 +176,8 @@ public function testAcceptNothing()
$html = new HtmlDisplayer(new ExceptionInfo('foo'), 'foo');
$json = new JsonDisplayer(new ExceptionInfo('foo'));

$request = Mockery::mock('Illuminate\Http\Request');
$request->shouldReceive('getAcceptableContentTypes')->once()->andReturn(['application/xml']);
$request = Mockery::mock('Illuminate\Http\Request')->makePartial();
$request->shouldReceive('getAcceptableContentTypes')->andReturn(['application/xml']);

$displayers = (new ContentTypeFilter($request))->filter([$debug, $html, $json], new Exception());

Expand Down
2 changes: 1 addition & 1 deletion tests/ServiceProviderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public function testDisplayerConfig()
$displayers = $this->app->config->get('exceptions.displayers');

$this->assertInternalType('array', $displayers);
$this->assertCount(3, $displayers);
$this->assertCount(4, $displayers);

foreach ($displayers as $displayer) {
$this->assertTrue(starts_with($displayer, 'GrahamCampbell\\Exceptions\\Displayers\\'));
Expand Down

0 comments on commit 6fed80f

Please sign in to comment.