duanna5749 2015-11-06 04:05
浏览 65
已采纳

Laravel 4-动态多域路由打破了模型绑定和链接

I have an application stack in Laravel that we're going to go ahead and switch to a SaaS model. In order to do this, I just assumed I could wrap all my routes in a group with dynamic domain properties, fire a filter, and then observe the $route parameters to make this occur.

I should note that this is actually a Multi-Tenancy application but we've actually decided to separate the databases out for this one.

So here we go:

In my routes.php file, I've got the following:

Route::group(array('domain' => '{domain}.{tld}', 'before' => 'database.setup'), function()
{
    Route::group(array('prefix' => 'backend', 'before' => 'auth'), function () {
        //all of my routes
    });
});

As you can see from the above, when any route is requested, it's going to the database.setup filter that I've got defined in filters.php:

Route::filter('database.setup', function($route, $request){
    $domain = $route->getParameter('domain').'.'.$route->getParameter('tld');

    $details = DB::table('my_table')->where('domain', '=', $domain)->first();
    if($details){

        Config::set('database.connections.account', [
            'driver' => 'mysql',
            'host' => 'my_host',
            'database' => Encryption::decrypt($details->db_hash, 'my_salt'),
            'username' => 'my_username',
            'password' => 'my_password',
            'collation' => 'utf8_unicode_ci',
            'prefix'    => '',
            'charset'   => 'utf8',
        ]);


        //these are things I was doing to get the URL-permalink working.
        Config::set('app.url', 'http://' . $domain);
        Config::set('app.domain', $domain);
        Config::set('session.domain', '.' . $domain);

        //This actually works exactly as I've intended
        Config::set('database.connections.default', 'account');
        DB::setDefaultConnection('account');
    }
});

Now initially I thought this was working fine. The correct record was pulled from the table, and the database switched on the fly without issue while destroying the previous instance. Great.

However, I noticed that I've lost all of my model binding relationships in the routes.

A route such as this:

Route::get('/shipping/packages/{package}', 'PackageController@get');

With a model defined as such:

Route::model('package', 'Package');

Unfortunately always results in this:

No query results for model [Package].

Now, if I remove my filter from the Route, everything works fine, but the default database will be used a big nono for my application.

Lastly, all of the permalink structure seems to be completely broken. Instead of seeing my domain when I hover over a link, such as:

http://example.com/shipping/packages/package

I instead see:

%7Bdomain%7D.%7Btld%7D/shipping/packages/package

I have no idea why this is occurring.

I've tried overloading the response object, altering the settings for the site Configuration within the filter, and a host of other things, but I always end up having the same issue in some way or another.

I'd be greatly appreciative if anyone has any clue's on how to solve this issue.

  • 写回答

1条回答 默认 最新

  • doucheyi1347 2015-11-06 04:48
    关注

    Okay, I've figured out what the issue is.

    I've apparently not read over the documentation well enough. If you walk through the router group call it will eventually invoke mergeGroup(), which in this particular function, you can observe the following code:

    $new['where'] = array_merge(array_get($old, 'where', []), array_get($new, 'where', []));
    

    Here, we can see that they're just using a stack to keep track of these values, so the literal interpretation of {domain}.{tld} was being pushed onto the stack.

    This was working fine initially because my filter actually grabs them explicitly:

    $domain = $route->getParameter('domain').'.'.$route->getParameter('tld');
    

    To resolve this, I just needed to create my own helper function that would grab the $host (this is an extremely rudimentary implementation, but should help for clarity)

    $domain = get_domain();
    
    Route::group(array('domain' => $domain, 'before' => 'database.setup'), function()
    

    Then in my helpers file, I've added the get_domain() function:

    if ( ! function_exists('get_domain'))
    {
        function get_domain()
        {
            $url_parts = parse_url(Request::root());
    
            return $url_parts['host'];
        }
    }
    

    Then I can simply call get_domain() in my filter as well and it'll always be in sync:

    Route::filter('database.setup', function($route, $request){
    $domain = get_domain();
    

    This works perfectly now.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥50 NT4.0系统 STOP:0X0000007B
  • ¥15 想问一下stata17中这段代码哪里有问题呀
  • ¥15 flink cdc无法实时同步mysql数据
  • ¥100 有人会搭建GPT-J-6B框架吗?有偿
  • ¥15 求差集那个函数有问题,有无佬可以解决
  • ¥15 【提问】基于Invest的水源涵养
  • ¥20 微信网友居然可以通过vx号找到我绑的手机号
  • ¥15 寻一个支付宝扫码远程授权登录的软件助手app
  • ¥15 解riccati方程组
  • ¥15 使用rabbitMQ 消息队列作为url源进行多线程爬取时,总有几个url没有处理的问题。