Reputation: 684
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!
Upvotes: 6
Views: 5608
Reputation: 2408
I tried the Kosta's approach but it didn't fully work for me because it somehow created an endless recursion loop in the framework. Nonetheless, I ended up with this code:
namespace App\Providers;
use App\Routing\UrlGenerator;
use Illuminate\Support\ServiceProvider;
class UrlGeneratorServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->singleton("url", function($app) {
$routes = $app['router']->getRoutes();
return new UrlGenerator( // this is actually my class due to the namespace above
$routes, $app->rebinding(
'request', $this->requestRebinder()
), $app['config']['app.asset_url']
);
});
}
protected function requestRebinder()
{
return function ($app, $request) {
$app['url']->setRequest($request);
};
}
}
And of course, registered the above provider in config/app.php
under 'providers'
Upvotes: 3
Reputation: 1867
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.
Upvotes: 7
Reputation: 1359
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.
Upvotes: 7