如何在 Symfony 3.4 下使用 SQLite 功能测试启用外键检查
How to enable foreign key checks with SQLite functional tests under Symfony 3.4
我已经设置了一对多的关系,希望在删除父项时删除子项。
我忘记这样做了,这在 MySQL 的生产中造成了一个错误,因为它拒绝删除父项,因为存在子项。
我想对此编写一个功能测试,但 SQLite 默认禁用外键检查。
如何 PRAGMA foreign_keys = ON
控制器使用的连接?我在测试端(固定装置)有 运行 这个,但这不是同一个连接,所以外键检查仍然被禁用并且删除具有现有子项的父项不会失败(它应该)。
覆盖您的包的 boot
函数,并在那里执行请求:
public function boot() {
parent::boot();
$env = $this->container->getParameter('kernel.environment');
if ($env !== "test") {
return;
}
/** @var Connection $connection */
$connection = $this->container->get('doctrine')->getConnection();
// Get initial state -- should be disabled
$statement = $connection->prepare("PRAGMA foreign_keys");
$statement->execute();
echo __FILE__ . "@" . __LINE__ . "\n";
print_r($statement->fetchAll());
// Actually enable the foreign key checks on this connection
$connection->exec("PRAGMA foreign_keys = ON;");
// See if it was enabled
$statement = $connection->prepare("PRAGMA foreign_keys");
$statement->execute();
echo __FILE__ . "@" . __LINE__ . "\n";
print_r($statement->fetchAll());
}
这会产生以下结果:
./src/AppBundle/DependencyInjection/Compiler/DoctrineCompilerPass.php@23
Array
(
[0] => Array
(
[foreign_keys] => 0
)
)
./src/AppBundle/DependencyInjection/Compiler/DoctrineCompilerPass.php@30
Array
(
[0] => Array
(
[foreign_keys] => 1
)
)
现在,根据您使用的装置,您可能需要在擦除数据库模式时禁用外键检查:
public function setUp() {
$manager = $this->getContainer()
->get('doctrine')
->getManager();
if (!isset($metadata)) {
$metadata = $manager->getMetadataFactory()
->getAllMetadata();
}
$schemaTool = new SchemaTool($manager);
// Disable the foreign key checks before the database is wiped
$manager->getConnection()->exec("PRAGMA foreign_keys = OFF");
$schemaTool->dropDatabase();
if (!empty($metadata)) {
$schemaTool->createSchema($metadata);
}
// Re-enable the foreign key checks now that it is created
$manager->getConnection()->exec("PRAGMA foreign_keys = ON");
$this->postFixtureSetup();
$this->referenceRepository = $this->loadFixtures(array(ZZZ::class))->getReferenceRepository();
$this->loadFixtures(array(ZZZ::class));
$this->client = $this->makeClient();
}
我已经设置了一对多的关系,希望在删除父项时删除子项。
我忘记这样做了,这在 MySQL 的生产中造成了一个错误,因为它拒绝删除父项,因为存在子项。
我想对此编写一个功能测试,但 SQLite 默认禁用外键检查。
如何 PRAGMA foreign_keys = ON
控制器使用的连接?我在测试端(固定装置)有 运行 这个,但这不是同一个连接,所以外键检查仍然被禁用并且删除具有现有子项的父项不会失败(它应该)。
覆盖您的包的 boot
函数,并在那里执行请求:
public function boot() {
parent::boot();
$env = $this->container->getParameter('kernel.environment');
if ($env !== "test") {
return;
}
/** @var Connection $connection */
$connection = $this->container->get('doctrine')->getConnection();
// Get initial state -- should be disabled
$statement = $connection->prepare("PRAGMA foreign_keys");
$statement->execute();
echo __FILE__ . "@" . __LINE__ . "\n";
print_r($statement->fetchAll());
// Actually enable the foreign key checks on this connection
$connection->exec("PRAGMA foreign_keys = ON;");
// See if it was enabled
$statement = $connection->prepare("PRAGMA foreign_keys");
$statement->execute();
echo __FILE__ . "@" . __LINE__ . "\n";
print_r($statement->fetchAll());
}
这会产生以下结果:
./src/AppBundle/DependencyInjection/Compiler/DoctrineCompilerPass.php@23
Array
(
[0] => Array
(
[foreign_keys] => 0
)
)
./src/AppBundle/DependencyInjection/Compiler/DoctrineCompilerPass.php@30
Array
(
[0] => Array
(
[foreign_keys] => 1
)
)
现在,根据您使用的装置,您可能需要在擦除数据库模式时禁用外键检查:
public function setUp() {
$manager = $this->getContainer()
->get('doctrine')
->getManager();
if (!isset($metadata)) {
$metadata = $manager->getMetadataFactory()
->getAllMetadata();
}
$schemaTool = new SchemaTool($manager);
// Disable the foreign key checks before the database is wiped
$manager->getConnection()->exec("PRAGMA foreign_keys = OFF");
$schemaTool->dropDatabase();
if (!empty($metadata)) {
$schemaTool->createSchema($metadata);
}
// Re-enable the foreign key checks now that it is created
$manager->getConnection()->exec("PRAGMA foreign_keys = ON");
$this->postFixtureSetup();
$this->referenceRepository = $this->loadFixtures(array(ZZZ::class))->getReferenceRepository();
$this->loadFixtures(array(ZZZ::class));
$this->client = $this->makeClient();
}