使用前缀或域路由

Joh*_*ing 4 laravel laravel-routing laravel-5

我正在开发一个平台,允许用户在主网站域的子文件夹中运行自己的网站,或者为他们的网站映射自定义域.

使用自定义域时,每个路由的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'));
});
Run Code Online (Sandbox Code Playgroud)

以下是使用自定义域的示例

Route::group(array('domain' => '{users_domain}'), function() {
    Route::get('/photos/{album_id}.html', array('uses' => 'Media\PhotosController@album_view', 'as' => 'photo_album'));
});
Run Code Online (Sandbox Code Playgroud)

理想情况下,我希望能够使用其中任何一个

route('photo_album', ['username' => 'johnboy', 'album_id' => 123] )
Run Code Online (Sandbox Code Playgroud)

并被退回

http://www.mainwebsitedomain.com/sites/johnboy/photos/123.html
Run Code Online (Sandbox Code Playgroud)

或使用不同的参数调用相同的路由

route('photo_album', ['users_domain' => 'www.johnboy.com', 'album_id' => 123] )
Run Code Online (Sandbox Code Playgroud)

并被退回

http://www.johnboy.com/photos/123.html
Run Code Online (Sandbox Code Playgroud)

luk*_*ter 5

这是一个非常棘手的问题,所以期待我的回答中有一些不那么完美的解决方法......

我建议你先阅读所有内容,然后再尝试一下.这个答案包括几个简化步骤,但我写下了整个过程以帮助理解

这里的第一个问题是,如果要按名称调用它们,则不能有多个具有相同名称的路由.

让我们通过添加"路由名称前缀"来解决这个问题:

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'));
});
Run Code Online (Sandbox Code Playgroud)

所以现在我们可以用它来生成网址:

route('photo_album', ['username' => 'johnboy', 'album_id' => 123] )
route('domain.photo_album', ['users_domain' => 'www.johnboy.com', 'album_id' => 123])
Run Code Online (Sandbox Code Playgroud)

(不用担心我们将domain.在以后的URL生成中删除...)


下一个问题是Laravel不允许使用完整的通配符域'domain' => '{users_domain}'.它适用于生成URL,但如果您尝试实际访问它,则会得到404.您问的解决方案是什么?您必须创建一个其他组来侦听您当前所在的域.但前提是它不是您网站的根域.

为简单起见,我们首先将应用程序域添加到您的配置中.我建议这样config/app.php:

'domain' => env('APP_DOMAIN', 'www.mainwebsitedomain.com')
Run Code Online (Sandbox Code Playgroud)

这样,它也可以通过环境文件进行配置以进行开发.

之后我们可以添加这个条件路由组:

$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'));
    });
}
Run Code Online (Sandbox Code Playgroud)

Soooo ......我们得到了我们的路线.然而,即使只有一条路线,这也非常混乱.为了减少代码重复,您可以将实际路由移动到一个(或多个)外部文件.像这样:

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']);
Run Code Online (Sandbox Code Playgroud)

然后是新的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';
});
Run Code Online (Sandbox Code Playgroud)

现在唯一缺少的是自定义URL生成功能.不幸的是,Laravel route()将无法处理这种逻辑,所以你必须覆盖它.例如,创建一个带有自定义帮助函数的文件,app/helpers.php并在加载bootstrap/autoload.php 之前 vendor/autoload.php将其命令:

require __DIR__.'/../app/helpers.php';

require __DIR__.'/../vendor/autoload.php';
Run Code Online (Sandbox Code Playgroud)

然后将此函数添加到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);
}
Run Code Online (Sandbox Code Playgroud)

您可以完全按照要求调用此函数,它route()在选项和传递参数方面的行为与正常情况相同.