Querying Relationship Existence using multiple MySQL database connections in Laravel 5.2

自闭症网瘾萝莉.ら 提交于 2019-12-05 06:06:19
ira

Taking into account this post, this post and @Giedrius Kiršys answer below, I finally came up with a solution that fits my needs, using the following steps:

  1. create a method that returns a Relation object in the Model
  2. eager load this new relationship in the Controller
  3. filtered out the telephones of flag != 1 using a query scope in the Model

In Employee model

/**
 * This is the new relationship
 *
 */
public function flaggedTelephones()
{
    return $this->telephones()
        ->where('flag', 1); //this will return a relation object
}



/**
 *  This is the query scope that filters the flagged telephones
 *
 *    This is the raw query performed:
 *    select * from mydb1.employees where exists (
 *    select * from mydb2.telephones
 *    where telephones.employee_id = employee.id
 *    and flag = 1);
 *
 */    
public function scopeHasFlaggedTelephones($query, $id)
{
    return $query->whereExists(function ($query) use ($id) {
        $query->select(DB::raw('*'))
            ->from('mydb2.telephones')
            ->where('telephones.flag', $flag)
            ->whereRaw('telephones.employee_id = employees.id');
    });
}

In the Controller

Now I may use this elegant syntax a’la Eloquent

$employees = Employee::with('flaggedTelephones')->hasFlaggedTelephones()->get();

which reads like "Fetch all the employees with flagged telephones eager loaded, and then take only the employees that have at least one flagged telephone"

EDIT:

After dealing with the Laravel framework for a while (current version used 5.2.39), I figured, that in fact, whereHas() clauses do work in case of the relationship model exists in a different database using the from() method, as it is depicted below:

$employees = Employee::whereHas('telephones', function($query){

    $query->from('mydb2.telephones')->where('flag', 1);

})->get();

@Rob Contreras credits for stating the use of the from() method, however it looks like the method requires to take both the database and the table as an argument.

Not sure if this will work but you can use the from method to specify your database connection within the closure:

$employees = Employee::whereHas('telephones', function($query){

    $query->from('mydb2')->where('flag', 1);

})->get();

Hope this helps

Dirty solution:

Use whereExists and scope for better readability.

In Your Employee model put:

public function scopeFlags($query, $flag)
{
    $query->whereExists(function ($q) use ($flag) {
        $q->select(\DB::raw(1))
            ->from('mydb2.telephones')
            ->where('telephones.flag', $flag)
            ->whereRaw('telephones.employee_id = employees.id');
    });
}

Then modify your query like so:

$employees = Employee::flags(1)->get();
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!