Laravel: 如何根据自定义实现更改 UrlGenerator(核心绑定)?
Laravel: How to change UrlGenerator (Core Binding) against custom Implementation?
我需要使用 UrlGenerator
的自定义实现。那么我该如何更改 laravel 的默认绑定,它在核心深处的某处实现为
'url' => ['Illuminate\Routing\UrlGenerator', 'Illuminate\Contracts\Routing\UrlGenerator'],
反对我自己的实现?
而且我不确定。我假设上面的这一行实际上做了两件事。它会将绑定存储在键“url
”下,它还会将接口映射到 class。所以我实际上需要覆盖两者!怎么做?此外,如何确定是否必须将其绑定为 "shared"(singleton) 或 "new instance every time"?
非常感谢!
查看服务容器指南http://laravel.com/docs/5.1/container
在这种特定情况下,我认为您需要做的就是告诉应用程序替换已经存在的别名。
要做到这一点,我建议创建一个 ServiceProvider,在 config/app.php
文件中注册,然后在该文件中的注册方法中输入如下内容:
$this->app->bind('Illuminate\Routing\UrlGenerator', 'yourownclasshere');
让我们知道它是否有效。
更新:我删除了无效的选项,只留下有效的选项。
我按照内斯特在他的回答中所说的做了,但对我来说不太管用。所以这就是我为让它发挥作用所做的。
在方法 register
中的服务提供商内部,我首先尝试了这个:
$this->app->bind('url', MyCustomProvider::class);
这确实注册了我的 URL 提供商,而不是默认提供商。问题是 现在我的供应商没有任何访问路由的权限。我检查了 \Illuminate\Routing\RoutingServiceProvider
的 Laravel 代码,因为它有一个方法 registerUrlGenerator
用于注册 URL 提供商。此方法直接实例化 Laravel URL 生成器 Illuminate\Routing\UrlGenerator
并在构造函数中提供适当的参数。
所以,我在我的服务提供商那里也做了同样的事情。我没有做 $this->app->bind
,而是做了 $this->app->singleton('url', function ($app) { ... })
,并在闭包函数中提供了与 RoutingServiceProvider::registerUrlGenerator
基本相同的代码,但创建了我的 URL 生成器的实例。这然后正常工作,现在每次都会调用我的生成器。最终代码是这样的:
// 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;
});
我讨厌复制代码,所以在我看来问题出在基本实现上。它应该为 URL 生成器采用正确的契约,而不是直接实例化基础 class。
我尝试了 Kosta 的方法,但它并不完全适合我,因为它以某种方式在框架中创建了一个无限递归循环。尽管如此,我还是得到了这段代码:
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);
};
}
}
当然,在 'providers'
下的 config/app.php
中注册了上述提供商
我需要使用 UrlGenerator
的自定义实现。那么我该如何更改 laravel 的默认绑定,它在核心深处的某处实现为
'url' => ['Illuminate\Routing\UrlGenerator', 'Illuminate\Contracts\Routing\UrlGenerator'],
反对我自己的实现?
而且我不确定。我假设上面的这一行实际上做了两件事。它会将绑定存储在键“url
”下,它还会将接口映射到 class。所以我实际上需要覆盖两者!怎么做?此外,如何确定是否必须将其绑定为 "shared"(singleton) 或 "new instance every time"?
非常感谢!
查看服务容器指南http://laravel.com/docs/5.1/container
在这种特定情况下,我认为您需要做的就是告诉应用程序替换已经存在的别名。
要做到这一点,我建议创建一个 ServiceProvider,在 config/app.php
文件中注册,然后在该文件中的注册方法中输入如下内容:
$this->app->bind('Illuminate\Routing\UrlGenerator', 'yourownclasshere');
让我们知道它是否有效。
更新:我删除了无效的选项,只留下有效的选项。
我按照内斯特在他的回答中所说的做了,但对我来说不太管用。所以这就是我为让它发挥作用所做的。
在方法 register
中的服务提供商内部,我首先尝试了这个:
$this->app->bind('url', MyCustomProvider::class);
这确实注册了我的 URL 提供商,而不是默认提供商。问题是 现在我的供应商没有任何访问路由的权限。我检查了 \Illuminate\Routing\RoutingServiceProvider
的 Laravel 代码,因为它有一个方法 registerUrlGenerator
用于注册 URL 提供商。此方法直接实例化 Laravel URL 生成器 Illuminate\Routing\UrlGenerator
并在构造函数中提供适当的参数。
所以,我在我的服务提供商那里也做了同样的事情。我没有做 $this->app->bind
,而是做了 $this->app->singleton('url', function ($app) { ... })
,并在闭包函数中提供了与 RoutingServiceProvider::registerUrlGenerator
基本相同的代码,但创建了我的 URL 生成器的实例。这然后正常工作,现在每次都会调用我的生成器。最终代码是这样的:
// 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;
});
我讨厌复制代码,所以在我看来问题出在基本实现上。它应该为 URL 生成器采用正确的契约,而不是直接实例化基础 class。
我尝试了 Kosta 的方法,但它并不完全适合我,因为它以某种方式在框架中创建了一个无限递归循环。尽管如此,我还是得到了这段代码:
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);
};
}
}
当然,在 'providers'
config/app.php
中注册了上述提供商