DatabaseTruncation.php
TLDR
The DatabaseTruncation.php
file in the Illuminate\Foundation\Testing
namespace provides a trait called DatabaseTruncation
. This trait is used to truncate the database tables for all configured connections. It contains several methods for truncating tables, retrieving the connections to truncate, and performing tasks before and after truncating the database.
Methods
truncateDatabaseTables
This method truncates the database tables for all configured connections. It first checks if the database has been migrated and seeded before. If not, it runs the necessary migrations and seeds. Then, it truncates the tables for all connections and performs additional seeding if necessary.
truncateTablesForAllConnections
This method truncates the database tables for all configured connections. It fetches the database instance from the application container and iterates over the connections to truncate. For each connection, it disables foreign key constraints and calls the truncateTablesForConnection
method.
truncateTablesForConnection
This method truncates the database tables for the given database connection. It retrieves the list of tables for the connection and filters them based on the tablesToTruncate
and exceptTables
properties. It then iterates over the filtered tables and truncates them using the connection instance.
withoutTablePrefix
This method removes the table prefix from a table name, if it exists. It accepts a connection instance and a table name as parameters. It checks if the table name starts with the connection's table prefix and removes the prefix if it does.
connectionsToTruncate
This method returns an array of database connections that should have their tables truncated. If the connectionsToTruncate
property is defined, it is returned; otherwise, an array with a null
value is returned.
exceptTables
This method returns an array of tables that should not be truncated. It accepts a connection name as an optional parameter. It first retrieves the migrations table name from the configuration. Then, it checks if the exceptTables
property is defined. If it is a list, it merges it with the migrations table name. If it is an associative array, it merges the connection-specific except tables with the migrations table name.
beforeTruncatingDatabase
This method is a hook that can be overridden by child classes or traits to perform any work that should take place before the database starts truncating.
afterTruncatingDatabase
This method is a hook that can be overridden by child classes or traits to perform any work that should take place once the database has finished truncating.
END
<?php
namespace Illuminate\Foundation\Testing;
use Illuminate\Contracts\Console\Kernel;
use Illuminate\Database\ConnectionInterface;
use Illuminate\Foundation\Testing\Traits\CanConfigureMigrationCommands;
trait DatabaseTruncation
{
use CanConfigureMigrationCommands;
/**
* The cached names of the database tables for each connection.
*
* @var array
*/
protected static array $allTables;
/**
* Truncate the database tables for all configured connections.
*
* @return void
*/
protected function truncateDatabaseTables(): void
{
$this->beforeTruncatingDatabase();
// Migrate and seed the database on first run...
if (! RefreshDatabaseState::$migrated) {
$this->artisan('migrate:fresh', $this->migrateFreshUsing());
$this->app[Kernel::class]->setArtisan(null);
RefreshDatabaseState::$migrated = true;
return;
}
// Always clear any test data on subsequent runs...
$this->truncateTablesForAllConnections();
if ($seeder = $this->seeder()) {
// Use a specific seeder class...
$this->artisan('db:seed', ['--class' => $seeder]);
} elseif ($this->shouldSeed()) {
// Use the default seeder class...
$this->artisan('db:seed');
}
$this->afterTruncatingDatabase();
}
/**
* Truncate the database tables for all configured connections.
*
* @return void
*/
protected function truncateTablesForAllConnections(): void
{
$database = $this->app->make('db');
collect($this->connectionsToTruncate())
->each(function ($name) use ($database) {
$connection = $database->connection($name);
$connection->getSchemaBuilder()->withoutForeignKeyConstraints(
fn () => $this->truncateTablesForConnection($connection, $name)
);
});
}
/**
* Truncate the database tables for the given database connection.
*
* @param \Illuminate\Database\ConnectionInterface $connection
* @param string|null $name
* @return void
*/
protected function truncateTablesForConnection(ConnectionInterface $connection, ?string $name): void
{
$dispatcher = $connection->getEventDispatcher();
$connection->unsetEventDispatcher();
collect(static::$allTables[$name] ??= $connection->getDoctrineSchemaManager()->listTableNames())
->when(
property_exists($this, 'tablesToTruncate'),
fn ($tables) => $tables->intersect($this->tablesToTruncate),
fn ($tables) => $tables->diff($this->exceptTables($name))
)
->filter(fn ($table) => $connection->table($this->withoutTablePrefix($connection, $table))->exists())
->each(fn ($table) => $connection->table($this->withoutTablePrefix($connection, $table))->truncate());
$connection->setEventDispatcher($dispatcher);
}
/**
* Remove the table prefix from a table name, if it exists.
*
* @param \Illuminate\Database\ConnectionInterface $connection
* @param string $table
* @return string
*/
protected function withoutTablePrefix(ConnectionInterface $connection, string $table)
{
$prefix = $connection->getTablePrefix();
return strpos($table, $prefix) === 0
? substr($table, strlen($prefix))
: $table;
}
/**
* The database connections that should have their tables truncated.
*
* @return array
*/
protected function connectionsToTruncate(): array
{
return property_exists($this, 'connectionsToTruncate')
? $this->connectionsToTruncate : [null];
}
/**
* Get the tables that should not be truncated.
*
* @param string|null $connectionName
* @return array
*/
protected function exceptTables(?string $connectionName): array
{
$migrations = $this->app['config']->get('database.migrations');
$migrationsTable = is_array($migrations) ? ($migrations['table'] ?? null) : $migrations;
if (property_exists($this, 'exceptTables')) {
if (array_is_list($this->exceptTables ?? [])) {
return array_merge(
$this->exceptTables ?? [],
[$migrationsTable],
);
}
return array_merge(
$this->exceptTables[$connectionName] ?? [],
[$migrationsTable],
);
}
return [$migrationsTable];
}
/**
* Perform any work that should take place before the database has started truncating.
*
* @return void
*/
protected function beforeTruncatingDatabase(): void
{
//
}
/**
* Perform any work that should take place once the database has finished truncating.
*
* @return void
*/
protected function afterTruncatingDatabase(): void
{
//
}
}