Does Magento 2's UpgradeSchema Pattern Handle non-contiguous Version Jumps
-
06-10-2020 - |
Question
Magento 2 replaced Magento 1's Setup Upgrade scripts with a bin/magento setup:upgrade
command.
When a module's installed, this command looks for a InstallSchema
and InstallData
class in a module's Setup
folder, and runs both class's install
method.
When a module is upgraded, this command looks for an UpgradeSchema
and UpgradeData
class in a module's Setup
folder, and runs these class's upgrade
method. Unlike Magento 1, there is no longer any built-in logic to run through a set of scripts named with version numbers.
The pattern used by Magento 2's core in Upgrade scripts looks like this
public function upgrade(SchemaSetupInterface $setup, ModuleContextInterface $context)
{
$installer = $setup;
$connection = $installer->getConnection();
if (version_compare($context->getVersion(), '2.0.1') < 0) {
//... upgrade scripts here ...
}
if (version_compare($context->getVersion(), '2.0.2') < 0) {
//... upgrade scripts here ...
}
if (version_compare($context->getVersion(), '2.0.3') < 0) {
//... upgrade scripts here ...
}
if (version_compare($context->getVersion(), '2.0.4') < 0) {
//... upgrade scripts here ...
}
}
i.e. The Upgrade classes need to include programatic logic for version checks.
Looking over how Magento's coded these in the core though -- it's not clear how this system works. Is $context->getVersion()
the version of am module the user is upgrading from? Or to? If you're jumping module versions (from say, 2.0.2
to 2.0.5
) does setup:upgrade
call this upgrade
once, or does it run through the scripts multiple times (one for the 2.0.3
upgrade, again for 2.0.4
upgrade, and again for 2.0.5
?
This doesn't (seem to be) documented on the dev docs site -- and setup code is pretty tricky to test by trial and error. Does anyone know how these work, and if Magento's implementation is "non-contiguous version upgrade" safe? If you're tempted to answer of course to the later without testing -- welcome newcomer!
Solution
Here are the upgrade steps as I understand them:
- For all active modules
$ bin/magento setup:upgrade
checks the configured (module.xml
file) version versus the database (setup_module table) schema+data values [1] - Differences between configured version and database version trigger execution of
UpgradeSchema->upgrade()
and thenUpgradeData->upgrade()
for each module one time each [2] $context->getVersion()
returns the respective database value for that module from the setup_module table, and that is used in the conditional state
[1] As with Magento 1, the setup_module.schema_version
and setup_module.data_version
values will (should) always be the equal; unequal values indicates a failed upgrade process.
Tangentially, thanks for reminding me to get an answer on why we changed approach. (I think that I have once, but I've forgotten.) I'll also see about getting all of this more thoroughly documented, including...
[2] ...the caveat that each upgrade()
is only executed once with the corresponding value from the database, which means that the entire upgrade logic is processed sequentially per module, which must be considered if a module depends on some other module's schema or data to be at a certain state.