Skip to content

Instantly share code, notes, and snippets.

@cowboymathu
Forked from adamwathan/1-add-macros.php
Created February 15, 2018 22:14
Show Gist options
  • Save cowboymathu/c98e996165b7dab766378635dcd19de0 to your computer and use it in GitHub Desktop.
Save cowboymathu/c98e996165b7dab766378635dcd19de0 to your computer and use it in GitHub Desktop.
Multiformat Endpoints in Laravel
<?php
namespace App\Http\Middleware;
class CaptureRequestExtension
{
public function handle($request, $next)
{
if ($request->route()->parameter('_extension') !== null) {
$request->attributes->set('_extension', substr($request->route()->parameter('_extension'), 1));
$request->route()->forgetParameter('_extension');
}
return $next($request);
}
}
<?php
namespace App\Providers;
use Illuminate\Http\Request;
use Illuminate\Routing\Route;
use Illuminate\Support\ServiceProvider;
use App\Http\Middleware\CaptureRequestExtension;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Route::macro('multiformat', function () {
// Hello darkness, my old friend
if (count($this->parameterNames()) > 0 && ends_with($this->uri(), '}')) {
$lastParameter = array_last($this->parameterNames());
// I've come to talk with you again
if (! isset($this->wheres[$lastParameter])) {
$this->where($lastParameter, '[^\/.]+');
}
}
$this->uri = $this->uri . '{_extension?}';
$this->where('_extension', '(\..+)');
$this->middleware(CaptureRequestExtension::class);
$this->parameterNames = $this->compileParameterNames();
return $this;
});
Request::macro('match', function ($responses, $defaultFormat = 'html') {
if ($this->attributes->get('_extension') !== null) {
return value(array_get($responses, $this->attributes->get('_extension'), function () {
abort(404);
}));
}
return value(array_get($responses, $this->format($defaultFormat)));
});
}
/**
* Register any application services.
*
* @return void
*/
public function register()
{
//
}
}
<?php
/**
* Mark a route as 'multiformat' to allow different extensions (html, json, xml, etc.)
*
* This route will match all of these requests:
* /podcasts/4
* /podcasts/4.json
* /podcasts/4.html
* /podcasts/4.zip
*/
Route::get('/podcasts/{id}', 'PodcastsController@show')->multiformat();
/**
* Use `Request::match()` to return the right response for the requested format.
*
* Supports closures to avoid doing unnecessary work, and returns 404 if the
* requested format is not supported.
*
* Will also take into account the `Accept` header if no extension is provided.
*/
class PodcastsController
{
public function show($id)
{
$podcast = Podcast::findOrFail($id);
return request()->match([
'html' => view('podcasts.show', [
'podcast' => $podcast,
'episodes' => $podcast->recentEpisodes(5),
]),
'json' => $podcast,
'xml' => function () use ($podcast) {
return response($podcast->toXml(), 200, ['Content-Type' => 'text/xml']);
}
]);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment