iRazaSyed's avatar

Lumen - Binding Repo to Implementation based on Route Param?

Hi,

So basically, I'm porting my Laravel App to Lumen and in Laravel, I'm binding a repo to an implementation dynamically based on the route param passed and it works good for my purpose, even though i believe it's not a right method but it does the job!

However, It seems like Lumen doesn't support route binding and I'm having trouble binding my repo to an implementation based on the route param.

I've been trying for the past 2 days with several methods such as using Middleware (It seems even $request->route('param') doesn't work with Lumen), Service Provider, etc.

The idea is simple, Based on the param, I check to see if there's an implementation for the requested page and if yes, then bind it to the repo that's being injected in my controller, if there isn't any, then it goes with the default implementation.

This is a requirement so i can process the request based on each page that varies from each other in terms of logics, config and various other things.

Here's my Laravel specific codes that are added in RouteServiceProvider.php

        $router->bind('topic', function ($topic) {
            $namespace = 'App\Repositories\Topics\\';
            $repo_name = $namespace . studly_case($topic);
            $repo = class_exists($repo_name) ? $repo_name : $namespace . 'DefaultRepository';

            $this->app->bind($namespace . 'Repository', $repo);

            return $topic;
        });

This works fine as i said. How would you port this to Lumen though?

Any help is highly appreciated. TIA!

0 likes
6 replies
iRazaSyed's avatar
iRazaSyed
OP
Best Answer
Level 3

Here's the middleware attempt:

// Goes inside handle ofc.

// route('param') fails because it's returning an array.
$route = $request->route();
$route = last($route);

if (!is_null($route) AND isset($route['topic'])) {
    $topic = $route['topic'];
    $namespace = 'App\Repositories\Topics\\';
    $repo_name = $namespace . studly_case($topic);
    $repo = class_exists($repo_name) ? $repo_name : $namespace . 'DefaultRepository';

    app()->bind($namespace . 'Repository', $repo);
}

return $next($request);

Edit: Got the middleware solution working finally! Had to make some changes in controller.

dberry's avatar

Why are you porting your Laravel App to Lumen?

iRazaSyed's avatar

As already said above ^ :D

Performance matters for the kinda project I'm working on!

evsign's avatar

Another variant)

/**
     * Explicit binding route parameter to model
     *
     * @param $request
     * @param Closure $next
     * @param $param
     * @param $model
     */
    public function handle(Request $request, Closure $next, $param, $model)
    {
        $routeInfo = $request->route();
        $paramValue = $routeInfo[2][$param] ?? 0;

        $routeInfo[2][$param] = app($model)->findOrFail($paramValue);

        $request->setRouteResolver(function() use ($routeInfo) {
           return $routeInfo;
        });

        app()->bind($model, $routeInfo[2][$param]);

        return $next($request);
    }
mmghv's avatar

I created a package to add support for route-model-binding in Lumen, Check it here :

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();
}
1 like

Please or to participate in this conversation.