Files
portal/app/tests/Concerns/SharesAdminPdo.php
T

56 lines
2.9 KiB
PHP
Raw Normal View History

<?php
declare(strict_types=1);
namespace Tests\Concerns;
use Illuminate\Database\Connection;
use Illuminate\Support\Facades\DB;
/**
* Share PDO между pgsql и pgsql_admin connections в тестах.
*
* Зачем: middleware UseAdminConnection (alias admin-db) на группе saas-admin
* переключает default-подключение на pgsql_admin (роль crm_admin_user). В тестах
* DatabaseTransactions оборачивает каждый connection в свою транзакцию: данные,
* засеянные через default Tenant::factory() ($pgsql), не видны с pgsql_admin
* connection до commit'а → admin-эндпоинты в тестах видят 0 строк / 404.
* Sharing PDO означает — обе connection используют ту же PDO session → одну
* транзакцию, и засеянные данные видны admin-контроллеру.
*
* На production обе connection реальные separate PDO; pgsql_admin (srv_bypass)
* видит все тенанты по READ COMMITTED. Этот trait — только для test-окружения.
*
* Зеркало [[SharesSupplierPdo]] для pgsql_admin. Применяется глобально к Feature
* suite (см. tests/Pest.php), т.к. admin-db висит на всей группе saas-admin —
* любой admin-тест (текущий и будущий) получает cross-connection visibility без
* per-file opt-in. Для не-admin тестов инертен (pgsql_admin просто не запрашивают).
*/
trait SharesAdminPdo
{
protected function setUpSharesAdminPdo(): void
{
if (! config()->has('database.connections.pgsql_admin')) {
return;
}
$defaultConnection = DB::connection('pgsql');
$adminConnection = DB::connection('pgsql_admin');
$adminConnection->setPdo($defaultConnection->getPdo());
$adminConnection->setReadPdo($defaultConnection->getReadPdo());
// Синхронизируем уровень вложенности транзакции: DatabaseTransactions уже
// открыл транзакцию на pgsql (тот же PDO) к моменту setUp. Без синхронизации
// pgsql_admin считает transactions=0 и при ->transaction() зовёт
// PDO->beginTransaction() на уже активной транзакции → PDOException
// "There is already an active transaction" (например AdminTenantsController::
// updateBalance). С синхронизацией вложенный transaction() делает SAVEPOINT.
$level = $defaultConnection->transactionLevel();
if ($level > 0) {
$prop = new \ReflectionProperty(Connection::class, 'transactions');
$prop->setAccessible(true);
$prop->setValue($adminConnection, $level);
}
}
}