使用前缀或域路由
Route using either a prefix or a domain
我正在开发一个允许用户在主网站域的子文件夹中 运行 自己的站点,或者为他们的站点映射自定义域的平台。
当使用自定义域时,每个路由的 URL 结构略有不同,因为它以用户名为前缀,但当使用自定义域时,则不使用此前缀。
在我的 Route::group 中是否有一种聪明的方法可以在一个路由中处理两种请求类型,并成功地使用反向路由根据传递给它的参数生成适当的 URL。
下面是使用前缀
的例子
Route::group(array( 'prefix' => 'sites/{username}'), function() {
Route::get('/photos/{album_id}.html', array('uses' => 'Media\PhotosController@album_view', 'as' => 'photo_album'));
});
这里是使用自定义域的示例
Route::group(array('domain' => '{users_domain}'), function() {
Route::get('/photos/{album_id}.html', array('uses' => 'Media\PhotosController@album_view', 'as' => 'photo_album'));
});
理想情况下,我希望处于可以使用任何一种的位置
route('photo_album', ['username' => 'johnboy', 'album_id' => 123] )
并返回
http://www.mainwebsitedomain.com/sites/johnboy/photos/123.html
或者用不同的参数调用相同的路由
route('photo_album', ['users_domain' => 'www.johnboy.com', 'album_id' => 123] )
并返回
http://www.johnboy.com/photos/123.html
这是一个非常棘手的问题,所以希望我的回答中有一些不太完美的解决方法...
我建议您先阅读所有内容,然后再尝试。这个答案包括几个简化步骤,但我写下了整个过程以帮助理解
这里的第一个问题是,如果你想按名称调用它们,你不能有多个同名的路由。
让我们通过添加 "route name prefix":
来解决这个问题
Route::group(array( 'prefix' => 'sites/{username}'), function() {
Route::get('/photos/{album_id}.html', array('uses' => 'Media\PhotosController@album_view',
'as' => 'photo_album'));
});
Route::group(array('domain' => '{users_domain}'), function() {
Route::get('/photos/{album_id}.html', array('uses' => 'Media\PhotosController@album_view',
'as' => 'domain.photo_album'));
});
所以现在我们可以使用它来生成 urls:
route('photo_album', ['username' => 'johnboy', 'album_id' => 123] )
route('domain.photo_album', ['users_domain' => 'www.johnboy.com', 'album_id' => 123])
(不用担心我们会在 URL 代之后摆脱 domain.
...)
下一个问题是 Laravel 不允许像 'domain' => '{users_domain}'
这样的完整通配符域。它可以很好地生成 URLs,但是如果您尝试实际访问它,您会得到一个 404。您问的解决方案是什么?您必须创建一个额外的组来侦听您当前所在的域。但前提是它不是您网站的根域。
为简单起见,让我们首先将应用程序域添加到您的配置中。我建议在 config/app.php
:
'domain' => env('APP_DOMAIN', 'www.mainwebsitedomain.com')
这样也可以通过开发环境文件进行配置。
之后我们可以添加这个条件路由组:
$currentDomain = Request::server('HTTP_HOST');
if($currentDomain != config('app.domain')){
Route::group(array('domain' => $currentDomain), function() {
Route::get('/photos/{album_id}.html', array('uses' => 'Media\PhotosController@album_view',
'as' => 'current_domain.photo_album'));
});
}
太棒了...我们得到了我们的路线。然而,这非常混乱,即使只有一条路线。为了减少代码重复,您可以将实际路由移动到一个(或多个)外部文件。像这样:
app/Http/routes/photos.php
:
if(!empty($routeNamePrefix)){
$routeNamePrefix = $routeNamePrefix . '.';
}
else {
$routeNamePrefix = '';
}
Route::get('/photos/{album_id}.html', ['uses' => 'Media\PhotosController@album_view',
'as' => $routeNamePrefix.'photo_album']);
然后是新的routes.php
:
// routes for application domain routes
Route::group(['domain' => config('app.domain'), 'prefix' => 'sites/{username}'], function($group){
include __DIR__.'/routes/photos.php';
});
// routes to LISTEN to custom domain requests
$currentDomain = Request::server('HTTP_HOST');
if($currentDomain != config('app.domain')){
Route::group(['domain' => $currentDomain], function(){
$routeNamePrefix = 'current_domain';
include __DIR__.'/routes/photos.php';
});
}
// routes to GENERATE custom domain URLs
Route::group(['domain' => '{users_domain}'], function(){
$routeNamePrefix = 'domain';
include __DIR__.'/routes/photos.php';
});
现在唯一缺少的是自定义 URL 生成函数。不幸的是 Laravel 的 route()
将无法处理此逻辑,因此您必须覆盖它。创建一个带有自定义辅助函数的文件,例如 app/helpers.php
并在 bootstrap/autoload.php
之前加载它 vendor/autoload.php
加载:
require __DIR__.'/../app/helpers.php';
require __DIR__.'/../vendor/autoload.php';
然后把这个函数添加到helpers.php
:
function route($name, $parameters = array(), $absolute = true, $route = null){
$currentDomain = Request::server('HTTP_HOST');
$usersDomain = array_get($parameters, 'users_domain');
if($usersDomain){
if($currentDomain == $usersDomain){
$name = 'current_domain.'.$name;
array_forget($parameters, 'users_domain');
}
else {
$name = 'domain.'.$name;
}
}
return app('url')->route($name, $parameters, $absolute, $route);
}
您可以完全按照您的要求调用此函数,它在选项和传递参数方面的行为与正常 route()
相同。
我正在开发一个允许用户在主网站域的子文件夹中 运行 自己的站点,或者为他们的站点映射自定义域的平台。
当使用自定义域时,每个路由的 URL 结构略有不同,因为它以用户名为前缀,但当使用自定义域时,则不使用此前缀。
在我的 Route::group 中是否有一种聪明的方法可以在一个路由中处理两种请求类型,并成功地使用反向路由根据传递给它的参数生成适当的 URL。
下面是使用前缀
的例子Route::group(array( 'prefix' => 'sites/{username}'), function() {
Route::get('/photos/{album_id}.html', array('uses' => 'Media\PhotosController@album_view', 'as' => 'photo_album'));
});
这里是使用自定义域的示例
Route::group(array('domain' => '{users_domain}'), function() {
Route::get('/photos/{album_id}.html', array('uses' => 'Media\PhotosController@album_view', 'as' => 'photo_album'));
});
理想情况下,我希望处于可以使用任何一种的位置
route('photo_album', ['username' => 'johnboy', 'album_id' => 123] )
并返回
http://www.mainwebsitedomain.com/sites/johnboy/photos/123.html
或者用不同的参数调用相同的路由
route('photo_album', ['users_domain' => 'www.johnboy.com', 'album_id' => 123] )
并返回
http://www.johnboy.com/photos/123.html
这是一个非常棘手的问题,所以希望我的回答中有一些不太完美的解决方法...
我建议您先阅读所有内容,然后再尝试。这个答案包括几个简化步骤,但我写下了整个过程以帮助理解
这里的第一个问题是,如果你想按名称调用它们,你不能有多个同名的路由。
让我们通过添加 "route name prefix":
来解决这个问题Route::group(array( 'prefix' => 'sites/{username}'), function() {
Route::get('/photos/{album_id}.html', array('uses' => 'Media\PhotosController@album_view',
'as' => 'photo_album'));
});
Route::group(array('domain' => '{users_domain}'), function() {
Route::get('/photos/{album_id}.html', array('uses' => 'Media\PhotosController@album_view',
'as' => 'domain.photo_album'));
});
所以现在我们可以使用它来生成 urls:
route('photo_album', ['username' => 'johnboy', 'album_id' => 123] )
route('domain.photo_album', ['users_domain' => 'www.johnboy.com', 'album_id' => 123])
(不用担心我们会在 URL 代之后摆脱 domain.
...)
下一个问题是 Laravel 不允许像 'domain' => '{users_domain}'
这样的完整通配符域。它可以很好地生成 URLs,但是如果您尝试实际访问它,您会得到一个 404。您问的解决方案是什么?您必须创建一个额外的组来侦听您当前所在的域。但前提是它不是您网站的根域。
为简单起见,让我们首先将应用程序域添加到您的配置中。我建议在 config/app.php
:
'domain' => env('APP_DOMAIN', 'www.mainwebsitedomain.com')
这样也可以通过开发环境文件进行配置。
之后我们可以添加这个条件路由组:
$currentDomain = Request::server('HTTP_HOST');
if($currentDomain != config('app.domain')){
Route::group(array('domain' => $currentDomain), function() {
Route::get('/photos/{album_id}.html', array('uses' => 'Media\PhotosController@album_view',
'as' => 'current_domain.photo_album'));
});
}
太棒了...我们得到了我们的路线。然而,这非常混乱,即使只有一条路线。为了减少代码重复,您可以将实际路由移动到一个(或多个)外部文件。像这样:
app/Http/routes/photos.php
:
if(!empty($routeNamePrefix)){
$routeNamePrefix = $routeNamePrefix . '.';
}
else {
$routeNamePrefix = '';
}
Route::get('/photos/{album_id}.html', ['uses' => 'Media\PhotosController@album_view',
'as' => $routeNamePrefix.'photo_album']);
然后是新的routes.php
:
// routes for application domain routes
Route::group(['domain' => config('app.domain'), 'prefix' => 'sites/{username}'], function($group){
include __DIR__.'/routes/photos.php';
});
// routes to LISTEN to custom domain requests
$currentDomain = Request::server('HTTP_HOST');
if($currentDomain != config('app.domain')){
Route::group(['domain' => $currentDomain], function(){
$routeNamePrefix = 'current_domain';
include __DIR__.'/routes/photos.php';
});
}
// routes to GENERATE custom domain URLs
Route::group(['domain' => '{users_domain}'], function(){
$routeNamePrefix = 'domain';
include __DIR__.'/routes/photos.php';
});
现在唯一缺少的是自定义 URL 生成函数。不幸的是 Laravel 的 route()
将无法处理此逻辑,因此您必须覆盖它。创建一个带有自定义辅助函数的文件,例如 app/helpers.php
并在 bootstrap/autoload.php
之前加载它 vendor/autoload.php
加载:
require __DIR__.'/../app/helpers.php';
require __DIR__.'/../vendor/autoload.php';
然后把这个函数添加到helpers.php
:
function route($name, $parameters = array(), $absolute = true, $route = null){
$currentDomain = Request::server('HTTP_HOST');
$usersDomain = array_get($parameters, 'users_domain');
if($usersDomain){
if($currentDomain == $usersDomain){
$name = 'current_domain.'.$name;
array_forget($parameters, 'users_domain');
}
else {
$name = 'domain.'.$name;
}
}
return app('url')->route($name, $parameters, $absolute, $route);
}
您可以完全按照您的要求调用此函数,它在选项和传递参数方面的行为与正常 route()
相同。