Database Upgraders¶
If your extension defines entities or manages database tables, you should create a class for managing database upgrades. This allows your extension to create, drop, and modify its tables as it evolves across releases.
Generating the Upgrader Class¶
To generate a database upgrader class for your extension, run:
civix generate:upgrader
This creates the file CRM/Myextension/Upgrader.php. This class acts as a wrapper for hook_civicrm_upgrade and provides a clean, structured way to write sequential database upgrades.
Writing Upgrade Steps¶
Caution
Extension upgraders are intended only for an extension's own tables. Think twice before making changes outside that scope of your own extension's tables.
Upgrade steps are defined as public methods on your upgrader class that follow the naming pattern "upgrade_XXXX()," where XXXX is a sequential number (independent of the extension's version).
Example:
/**
* Example upgrade step.
*
* By convention, 1001 is the first upgrade step for any extension, followed by 1002, etc.
*/
public function upgrade_1001(): bool {
// Perform database changes here...
return TRUE;
}
When users upgrade your extension, CiviCRM will automatically execute these functions sequentially to transition the database schema to the latest version. Or for dev purposes pending upgrade functions can be triggered with the command:
cv up
Using E::schema()¶
Within your upgrader class, you can access the schema helper using E::schema(). This provides a high-level, object-oriented API for managing your extension's tables.
Why reference E?
In these examples, E is an alias for your extension's utility class (e.g. use CRM_Myextension_ExtensionUtil as E;).
Creating a table for a new entity¶
If you define a new entity in your schema/<entity_name>.entityType.php file:
- Copy the current version of the entity file from
schema/<entity_name>.entityType.phpto a new folder dedicated to historical schema definitions (e.g.upgrade/schema/10001-myEntity.entityType.php). - Add an upgrade step that calls
createEntityTable()referencing that copied file:
public function upgrade_10001(): bool {
E::schema()->createEntityTable('upgrade/schema/10001-myEntity.entityType.php');
return TRUE;
}
Why copy the schema file?
Upgrades are a linear process. To ensure upgrade steps are reproducible, always use a snapshot copy of the schema file in the upgrade/ folder. This guarantees the step will behave identically in the future, even if your main entity definition evolves.
For a complete step-by-step walkthrough, see Create entity: step-by-step.
Modifying columns (Adding/Altering Fields)¶
To add a new column or modify an existing column, copy and paste the field definition array from your entityType.php file and pass it to alterSchemaField():
public function upgrade_1002(): bool {
E::schema()->alterSchemaField('MyEntity', 'my_new_column', [
'title' => E::ts('Field Title'),
'sql_type' => 'varchar(255)',
'input_type' => 'Text',
'required' => FALSE,
]);
return TRUE;
}
Dropping a column¶
To remove a column:
public function upgrade_1003(): bool {
E::schema()->dropSchemaField('MyEntity', 'my_new_column');
return TRUE;
}
Managing Indexes¶
Adding an index¶
Define the index appropriately in the getIndices function of the entityType.php file, then write an upgrade step:
public function upgrade_1004(): bool {
E::schema()->createIndex('<table name>', 'index_name', [
'fields' => [
'field_name' => TRUE,
],
'unique' => TRUE, // Optional, defaults to FALSE
]);
return TRUE;
}
Dropping an index¶
public function upgrade_1005(): bool {
E::schema()->dropIndex('<table name>', 'index_name');
return TRUE;
}
Dropping a table¶
To drop an extension's table:
public function upgrade_1006(): bool {
E::schema()->dropTable('<table name>');
return TRUE;
}
Managing Triggers¶
If you need to create database triggers, use hook_civicrm_triggerInfo.