Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel: How to change UrlGenerator (Core Binding) against custom Implementation?

I need to use a custom Implementation of UrlGenerator. So how can I change the default binding of laravel, that is implemented somewhere deep in the core as

 'url'                  => ['Illuminate\Routing\UrlGenerator', 'Illuminate\Contracts\Routing\UrlGenerator'],

against my own implementation?

Furthermore I am not shure. I assume this line above does actually two things. it will store the bindinung under the key "url" and it will also do the mapping of the Interface to the class. So I actually need to override both! How to do that? Furthemore how to find out if this must be bound as "shared"(singleton) or "new instance every time"?

Thanks very much!

like image 241
Tim Schmidt Avatar asked Dec 18 '22 23:12

Tim Schmidt


2 Answers

Take a look at the Service Container guide http://laravel.com/docs/5.1/container

In this specific case I think all you need to do is to tell the app to replace the alias that already exists.

To do that I would recommend creating a ServiceProvider, registering int the config/app.php file and inside that one in the register method put something like:

$this->app->bind('Illuminate\Routing\UrlGenerator', 'yourownclasshere');

Let us know if it works.

Update: I removed the option that didn't work and left only the one that worked.

like image 140
Nestor Mata Cuthbert Avatar answered Dec 21 '22 12:12

Nestor Mata Cuthbert


I did what Nestor said in his answer, but it didn't quite work for me. So this is what I did to make it work. Inside my service provider in method register I first tried this:

$this->app->bind('url', MyCustomProvider::class);

This did register my URL provider instead of the default one. The problem was that now my provider didn't have any access to routes. I checked the Laravel code for \Illuminate\Routing\RoutingServiceProvider because it has a method registerUrlGenerator for registering the URL provider. This method did a direct instantiation of the Laravel URL generator Illuminate\Routing\UrlGenerator and giving proper parameters in the constructor.

So, I did the same in my service provider. Instead of doing $this->app->bind I did $this->app->singleton('url', function ($app) { ... }) and provided basically the same code in the closure function as in RoutingServiceProvider::registerUrlGenerator but created the instance of my URL generator. This then worked properly, and my generator is now called every time. The final code was this:

// the code is copied from the \Illuminate\Routing\RoutingServiceProvider::registerUrlGenerator() method
$this->app->singleton('url', function ($app) {
    /** @var \Illuminate\Foundation\Application $app */
    $routes = $app['router']->getRoutes();

    $app->instance('routes', $routes);

    // *** THIS IS THE MAIN DIFFERENCE ***
    $url = new \My\Specific\UrlGenerator(
        $routes,
        $app->rebinding(
            'request',
            static function ($app, $request) {
                $app['url']->setRequest($request);
            }
        ),
        $app['config']['app.asset_url']
    );

    $url->setSessionResolver(function () {
        return $this->app['session'] ?? null;
    });

    $url->setKeyResolver(function () {
        return $this->app->make('config')->get('app.key');
    });

    $app->rebinding('routes', static function ($app, $routes) {
        $app['url']->setRoutes($routes);
    });

    return $url;
});

I hate copying the code, so it seems to me that the problem is in the base implementation. It should take the correct contract for URL generator instead of making direct instantiation of a base class.

like image 22
Kosta Avatar answered Dec 21 '22 13:12

Kosta