LoginSignup
4
3

More than 5 years have passed since last update.

Laravel4で楽にDBの水平分割が出来ないだろうか?

Last updated at Posted at 2015-02-17

水平分割させたいモデルの基底クラス

HorizonModelBase.php
class HorizonModelBase
{
    use SoftDeletingTrait;
    private static $isEnableGlobalConnection = false;

    public function newQuery($excludeDeleted = true)
    {
        $this->setOwnConnection();
        $builder = parent::newQuery($excludeDeleted);
        $this->resetOwnConnection();
        return $builder;
    }

    public function newFromBuilder($attributes = array())
    {
        $this->setOwnConnection();
        $result = parent::newFromBuilder($attributes);
        $this->resetOwnConnection();
        return $result;
    }

    public static function aroundQuery($func)
    {
        self::$isEnableGlobalConnection = true;
        $result_collection = new Collection();
        foreach(self::getAroundConnections() as $connection)
        {
            Config::set('database.default', $connection);
            $result_collection = $result_collection->merge(call_user_func($func));
        }
        Config::set('database.default', "mastar_data");
        $result_collection->sortBy(function($record){return $record->id;})->values();

        self::$isEnableGlobalConnection = false;

        return $result_collection;
    }

    public static function aroundAll()
    {
        return self::aroundQuery(function(){
            return self::all();
        });
    }



    private static function getAroundConnections()
    {
        return Config::get("database.user_db_connections");
    }

    private function setOwnConnection()
    {
        if (self::$isEnableGlobalConnection) { return; }

        if (property_exists($this, "user_id"))
        {
            $connection_no = $this->user_id % Config::get("database.user_db_connection_count");
        }
        else
        {
            $connection_no = $this->id % Config::get("database.user_db_connection_count");
        }
        $connection = "user_data_" . strval($connection_no);
        $this->setConnection($connection);
    }

    private function resetOwnConnection()
    {
        if (self::$isEnableGlobalConnection) { return; }
        $this->setConnection('user_data_0');
    }
}

Eloquentの変更を最小限にしつつ、従来通りの使い方で、データアクセス出来ないだろうかと模索した結果、こんな感じになった。

Config::get("database.user_db_connections");
global.phpのどっかで、上記コンフィグの設定はしとかないとダメ。

使うときは

User.php
class User extends HorizonModelBase
{
}
Test.php
$users = User::aroundQuery(function(){
   User::where('level', 10)->where('friend_num', '>', '3')->get();
}

echo $users;

みたいな感じ。
かなりやっつけ実装だが、まあ正常に動く。
ページネートどうするかとか、凝ったクエリー流したいときとか、
色々問題は出ててきそうだが・・・
もっと良い実装は無いだろうか・・・。

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3