Много просто:
public function bs()
{
$database = $this->getConnection()->getDatabaseName();
return $this->belongsToMany('B', "$database.a_bs", 'a_id', 'b_id');
}
Получавам името на базата данни динамично, защото връзката ми е конфигурирана въз основа на променлива на средата. Laravel изглежда предполага, че въртящата се таблица съществува в същата база данни като целевата релация, така че това ще я принуди да търси вместо това базата данни, съответстваща на модела, в който се намира този метод, вашата 'A' област.
Ако не се притеснявате за базите данни на SQLite, т.е. в обхвата на единичен тест, това е всичко, от което се нуждаете. Но ако сте, продължете да четете.
Първо, предишният пример не е достатъчен сам по себе си. Стойността на $database в крайна сметка ще бъде файлов път, така че трябва да го поставите като псевдоним, което няма да наруши SQL израз, и да го направите достъпен за текущата връзка. "ATTACH DATABASE '$database' AS $name"
е как да направите това:
public function bs()
{
$database = $this->getConnection()->getDatabaseName();
if (is_file($database)) {
$connection = app('B')->getConnection()->getName();
$name = $this->getConnection()->getName();
\Illuminate\Support\Facades\DB::connection($connection)->statement("ATTACH DATABASE '$database' AS $name");
$database = $name;
}
return $this->belongsToMany('B', "$database.a_bs", 'a_id', 'b_id');
}
Предупреждение:Транзакциите объркват това: Ако текущата връзка използва транзакции, операторът ATTACH DATABASE ще се провали. Вие можете използвайте транзакции за него след изпълнение на това изявление.
Докато, ако свързани връзката използва транзакции, получените данни ще бъдат незабележими невидими за текущата. Това ме побърка за по-дълго, отколкото бих искал да призная, защото заявките ми се изпълняваха без грешка, но продължаваха да излизат празни. Изглежда, че само данните, наистина записани в прикачената база данни, са действително достъпни за тази, към която е прикачена.
Така че, след като сте принудени да пишете във вашата прикачена база данни, може да искате тестът ви да се изчисти след себе си. Едно просто решение би било просто да използвате $this->artisan('migrate:rollback', ['--database' => $attachedConnectionName]);
. Но ако имате множество тестове, които се нуждаят от едни и същи таблици, това не е много ефективно, тъй като ги принуждава да ги изграждат отново всеки път.
По-добър вариант би бил да съкратите таблиците, но да оставите структурата им в такт:
//Get all tables within the attached database
collect(DB::connection($database)->select("SELECT name FROM sqlite_master WHERE type = 'table'"))->each(function ($table) use ($name) {
//Clear all entries for the table
DB::connection($database)->delete("DELETE FROM '$table->name'");
//Reset any auto-incremented index value
DB::connection($database)->delete("DELETE FROM sqlite_sequence WHERE name = '$table->name'");
});
}
Това ще изтрие всички данни от тази връзка , но няма причина да не можете да приложите някакъв вид филтър към това, както сметнете за добре. Като алтернатива можете да се възползвате от факта, че SQLite DBs са лесно достъпни файлове и просто да копирате прикачения във временен файл и да го използвате, за да презапишете източника, след като тестът приключи. Резултатът би бил функционално идентичен с транзакция.