Skip to content

Instantly share code, notes, and snippets.

@webkonstantin
Created March 27, 2016 10:47
Show Gist options
  • Save webkonstantin/bdc8285b61be5a8e064d to your computer and use it in GitHub Desktop.
Save webkonstantin/bdc8285b61be5a8e064d to your computer and use it in GitHub Desktop.
<?php
namespace App\Http\Middleware;
use Closure;
use ReflectionMethod;
use ReflectionFunction;
use Illuminate\Database\Eloquent\Model;
class SubstituteImplicitBindings
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$routeInfo = $request->route();
$parameters = $routeInfo[2];
$signatureParameters = $this->signatureParameters($routeInfo[1], Model::class);
foreach ($signatureParameters as $parameter) {
$class = $parameter->getClass();
if (array_key_exists($parameter->name, $parameters)) {
$method = $parameter->isDefaultValueAvailable() ? 'first' : 'firstOrFail';
$model = $class->newInstance();
$routeInfo[2][$parameter->name] = $model->where(
$model->getRouteKeyName(), $parameters[$parameter->name]
)->{$method}();
}
}
$request->setRouteResolver(function () use ($routeInfo) {
return $routeInfo;
});
return $next($request);
}
private function signatureParameters($action, $subClass = null)
{
if (isset($action['uses'])) {
list($class, $method) = explode('@', $action['uses']);
$parameters = (new ReflectionMethod($class, $method))->getParameters();
} else {
$parameters = (new ReflectionFunction($action[0]))->getParameters();
}
return is_null($subClass) ? $parameters : array_filter($parameters, function ($p) use ($subClass) {
return $p->getClass() && $p->getClass()->isSubclassOf($subClass);
});
}
}
@mmghv
Copy link

mmghv commented Oct 27, 2016

Check out this package Lumen Route Binding

It requires :

php >= 5.4.0
Lumen 5.*

It supports Explicit binding :

$binder->bind('user', 'App\User');

And Implicit binding :

$binder->implicitBind('App\Models');

And Composite binding : (bind more than one wildcard together, In situations like posts\{post}\comments\{comment} you will be able to bind it to a callable that will resolve the Post and the Comment related to the post)

$binder->compositeBind(['post', 'comment'], function($postKey, $commentKey) {
    $post = \App\Post::findOrFail($postKey);
    $comment = $post->comments()->findOrFail($commentKey);

    return [$post, $comment];
});

Also can work with other classes like Repositories :

// Add a suffix to the class name
$binder->implicitBind('App\Repositories', '', 'Repository');

Can use a custom method on the repository :

// Use a custom method on the class
$binder->implicitBind('App\Repositories', '', 'Repository', 'findForRoute');

Where in the repository class you can do :

public function findForRoute($val)
{
    return $this->model->where('slug', $val)->firstOrFail();
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment