When working with TYPO3, you may have external or custom tables that you don’t want TYPO3’s Database Analyser to process. This is common when using WordPress tables (wp_ prefix) or other third-party integrations.
Introduction to TYPO3 Database Analyser
In some TYPO3 projects, you might have custom tables that you do not want TYPO3’s Database Analyser (Install Tool → “Analyze Database Structure”) to modify or drop. This is common when you have third-party tables (e.g., WordPress tables like wp_*), or any external data that must remain untouched by TYPO3’s schema management processes.
In this tutorial, we’ll explore two approaches to ignore custom tables in Database Analyser:
- Using an Event Listener (AlterTableDefinitionStatementsEvent)
- Overriding the ConnectionMigrator and using IGNORE_TABLE_PREFIXES/IGNORE_TABLE_NAMES
Both methods work in TYPO3 v12 and TYPO3 v13 and can be adapted to earlier versions with minimal changes.
Approach 1: Using an Event Listener
In this method, we hook into the database schema generation process using TYPO3’s event system. We’ll instruct TYPO3 to recognize certain tables (e.g., those prefixed with wp_) so that it won’t flag them as "to be dropped."
Step 1: Register Event in Services.yaml
Create or update your Services.yaml (usually found in your extension’s Configuration folder) to register a listener for the AlterTableDefinitionStatementsEvent.
# Configuration/Services.yaml
services:
Vendor\MyExtension\EventListener\Setup:
tags:
- name: event.listener
identifier: 'table-connection'
method: 'schemaEvent'
event: TYPO3\CMS\Core\Database\Event\AlterTableDefinitionStatementsEvent
Step 2: Create the Event Listener PHP Class
Below is a sample PHP class that adds your custom tables to TYPO3’s internal schema list, effectively telling TYPO3’s Database Analyser that they are part of the valid schema (and thus shouldn’t be dropped).
<?php
namespace Vendor\MyExtension\EventListener;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Database\Event\AlterTableDefinitionStatementsEvent;
class Setup
{
/**
* Builds and returns the current schema for the Install Tool.
*
* @param array $list List of SQL statements
* @return array SQL statements required for the install tool
*/
public function Schema(array $list): array
{
$connectionPool = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\ConnectionPool::class);
$connection = $connectionPool->getConnectionByName('Default');
$schemaManager = $connection->createSchemaManager();
$tables = [];
// Fetch custom tables starting with 'wp_'
foreach ($schemaManager->listTableNames() as $tableName) {
if (!\str_starts_with($tableName, 'wp_')) {
continue;
}
$tables[] = $tableName;
}
// For each custom table, retrieve and modify the CREATE statement
foreach ($tables as $wpTable) {
$query = "SHOW CREATE TABLE `$wpTable`";
$result = $connection->query($query);
$row = $result->fetch();
$createTableQuery = $row['Create Table'] ?? '';
// Minor string modifications to make it compatible
$createTableQuery = str_replace('"', '`', $createTableQuery);
$createTableQuery = preg_replace('/CONSTRAINT `[a-zA-Z0-9_-]+` /', '', $createTableQuery);
$createTableQuery = preg_replace('/ DEFAULT CHARSET=[^ ;]+/', '', $createTableQuery);
$createTableQuery = preg_replace('/ COLLATE=[^ ;]+/', '', $createTableQuery);
$list[] = $createTableQuery . ";\n";
}
return ['sqlString' => $list];
}
/**
* Handle the AlterTableDefinitionStatementsEvent to prevent dropping certain tables.
*/
public function schemaEvent(AlterTableDefinitionStatementsEvent $event): void
{
$list = $this->Schema([]);
foreach ($list['sqlString'] ?? [] as $sql) {
$event->addSqlData($sql);
}
}
}
Let's see How it works
- When TYPO3’s Database Analyser runs, it triggers - AlterTableDefinitionStatementsEvent.
- Our listener grabs the wp_ tables from the database, fetches their CREATE statements, and appends them to the recognized schema.
- The Database Analyser now sees these tables as valid and does not list them for deletion.
Approach 2: Overriding the ConnectionMigrator
If you prefer a more straightforward approach—especially if you frequently need to ignore large sets of tables—overriding the ConnectionMigrator class might be simpler. TYPO3’s Database Compare allows you to specify prefixes and table names to ignore entirely.
Step 1: Configure ext_localconf.php or AdditionalConfiguration.php
Add the following lines to tell TYPO3 which table prefixes and specific table names to ignore:
// Ignore tables with a specific prefix
$GLOBALS['TYPO3_CONF_VARS']['SYS']['DATABASE_COMPARE']['IGNORE_TABLE_PREFIXES'] = [
'wp_',
];
// Ignore specific table names
$GLOBALS['TYPO3_CONF_VARS']['SYS']['DATABASE_COMPARE']['IGNORE_TABLE_NAMES'] = [
'some_table_name',
];
Step 2: Override ConnectionMigrator
Next, override the ConnectionMigrator service in ext_localconf.php (or your extension’s configuration). This will force TYPO3 to use your custom class instead of the core default:
// Override the default ConnectionMigrator
$GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][\TYPO3\CMS\Core\Database\Schema\ConnectionMigrator::class] = [
'className' => \Vendor\ExtensionName\Database\Schema\ConnectionMigrator::class
];
Step 3: Create Your Custom ConnectionMigrator Class
In your extension under Classes/Database/Schema/ConnectionMigrator.php:
<?php
declare(strict_types=1);
namespace Vendor\ExtensionName\Database\Schema;
use Doctrine\DBAL\Schema\SchemaDiff;
use Doctrine\DBAL\Schema\Table;
class ConnectionMigrator extends \TYPO3\CMS\Core\Database\Schema\ConnectionMigrator
{
protected function buildSchemaDiff(bool $renameUnused = true): SchemaDiff
{
$schemaDiff = parent::buildSchemaDiff($renameUnused);
return $this->cleanSchemaDiff($schemaDiff);
}
protected function cleanSchemaDiff(SchemaDiff $schemaDiff): SchemaDiff
{
$schemaDiff->newTables = $this->cleanTables($schemaDiff->newTables);
$schemaDiff->changedTables = $this->cleanTables($schemaDiff->changedTables);
$schemaDiff->removedTables = $this->cleanTables($schemaDiff->removedTables);
return $schemaDiff;
}
protected function cleanTables(array $tables): array
{
$ignorePrefixes = $GLOBALS['TYPO3_CONF_VARS']['SYS']['DATABASE_COMPARE']['IGNORE_TABLE_PREFIXES'] ?? [];
$ignoreTables = $GLOBALS['TYPO3_CONF_VARS']['SYS']['DATABASE_COMPARE']['IGNORE_TABLE_NAMES'] ?? [];
$deletedPrefix = $this->deletedPrefix;
return array_filter(
$tables,
function ($table) use ($ignorePrefixes, $ignoreTables, $deletedPrefix) {
if ($table instanceof Table) {
$tableName = $table->getName();
} else {
// For changed/removed tables, newName or name might be used
$tableName = trim($table->newName ?: $table->name, '`');
}
// If the table name has a deleted prefix, remove that before comparing
if (strpos($tableName, $deletedPrefix) === 0) {
$tableName = substr($tableName, strlen($deletedPrefix));
}
// Ignore if table is explicitly listed or has an ignored prefix
if (in_array($tableName, $ignoreTables, true)) {
return false;
}
foreach ($ignorePrefixes as $prefix) {
if (strpos($tableName, $prefix) === 0) {
return false;
}
}
return true;
}
);
}
}
Let's see How its works
- This custom migrator inspects all new, changed, and removed tables during the schema analysis.
- It filters out any table whose name matches a prefix in IGNORE_TABLE_PREFIXES or a name in IGNORE_TABLE_NAMES.
- As a result, TYPO3’s Database Compare tool will not list these tables for creation or dropping.
How to use in Real-World Applications
- WordPress and TYPO3 Hybrid: Running TYPO3 alongside WordPress in the same database. You can ignore all wp_* tables so that TYPO3 never tries to touch them.
- Third-Party Integrations: When using external modules (like e-commerce solutions) that store data in custom tables, you can ensure those tables remain intact.
- Custom Data: If you have your own unregistered tables (not managed by TYPO3), you can protect them from any accidental changes.
Conclusion
Ignoring certain database tables from TYPO3’s Database Analyser can prevent unexpected drops or modifications to critical data. You can choose one of these two approaches:
- Event Listener: Dynamically add the custom tables into TYPO3’s recognized schema.
- Overriding the ConnectionMigrator: Use TYPO3’s built-in ignore lists for prefixes and names
Both methods are valid and can be adapted to different scenarios. If you have only a few special-case tables, the Event Listener approach gives you granular control. If you have a consistent pattern of tables to ignore (e.g., always ignoring wp_), the ConnectionMigrator override might be simpler.
If you found this TYPO3 tutorial helpful, share your favorite part in the comments! Feel free to mix and match strategies or choose the one that best fits your workflow.
Happy coding in TYPO3!
Post a Comment