XF 2.2 Creating addon updates XF1 to XF2

Gobb

Member
Hey guys,

Just a query regarding how addon version checking is handled in the setup.php file for XenForo 2? I'm in the process of re-writing addons for the eventual move from 1.5 -> 2.2, but can't find much info as to how to actually update XF2 addons. What I mean is, in XF1, we could just add the $addon variable to the install function and then check the addon id with that to perform any updates. How is this done in XenForo 2? I assume using StepRunnerUpgradeTrait and the upgrade function, but I'm just a bit confused how I actually check the addon id within that function. When trying with the below, the base install function still seems to run and I get errors, obviously because the tables or columns added already exist... 1100010 is the addon version id from the addon.json file, I think this is correct?

PHP:
public function upgrade1100010Step1(array $stepParams) {

}

I don't really have anything to put within that upgrade function itself as I am not intending to make any changes to existing 1.5 addon tables at this point in time. Should the install function just not add any tables or modifications if they already exist from the 1.5 addon?

Any help would be much appreciated,
Thanks.
 

Chris D

XenForo developer
Staff member
In XF1 you would typically have a single install method and passed into that would be the current details of the installed add-on, or it would be empty if it wasn't yet installed.

Something like this:

PHP:
public static function install($addOn)
{
    if (!$addOn)
    {
        // new install
    }
    else
    {
        if ($addOn['version_id'] < 1000070)
        {
            // upgrading *to* version 1.0.0 (1000070)
        }
    }
}

We've made this a little clearer in XF2. There are separate methods for installs and upgrades. Plus when using the StepRunnerInstallTrait, StepRunnerUpgradeTrait, or StepRunnerUninstallTrait traits you can split each process even further into distinct steps.

e.g. public function installStep1() and public function installStep2() and so on

For upgrades it's a little more complicated and it will look like e.g. public function upgrade2000070Step1() where the first number is the version being upgraded to and the second number is the step number.

So, if your current add-on version is 1.0.0 and has a version ID, e.g. 1000070 and the new add-on version you are working on is 2.0.0 and version ID, e.g. 2000070 then your upgrade method will look like:

PHP:
public function upgrade2000070Step1()
{
    // upgrading *to* version 2.0.0 (2000070)
}

Eventually you'll release version 2.0.1 and 2.0.2 and then maybe 2.1.0 so you'll end up with methods that look like this:

PHP:
public function upgrade2000070Step1()
{
    // upgrading *to* version 2.0.0 (2000070)
}

public function upgrade2000170Step1()
{
    // upgrading *to* version 2.0.1 (2000170)
}

public function upgrade2000270Step1()
{
    // upgrading *to* version 2.0.2 (2000270)
}

public function upgrade2010070Step1()
{
    // upgrading *to* version 2.1.0 (2010070)
}

The idea here being that the upgrade methods will allow you to upgrade from any version to any version.

So if an admin still has version 1.0.0 and they upgrade to version 2.1.0 it will actually run all of the upgrade steps above in order. Or if an admin in the future is upgrading from 2.0.1 to 2.1.0 then it will run the upgrade2000270Step1 and upgrade2010070Step1 methods.

If an admin is upgrading from an old version on 1.5 to the new version in 2.2 they shouldn't be hitting the install method at all. Different to XF1 add-ons, the install method should only be hit if it is a clean install, rather than an upgrade.

If someone is upgrading from an old version, the old version will still be listed in their xf_addon table. During the upgrade to XF2 we would have disabled the add-on and marked it as is_legacy.

To replicate that if you're working on a clean install, use the following query to add it to your xf_addon table:

Rich (BB code):
INSERT INTO xf_addon (addon_id, title, version_string, version_id, json_hash, active, is_legacy, is_processing, last_pending_action) VALUES
('AddOnId', 'Add-on title', '1.0.0', 1000070, '', 0, 1, 0, NULL);

Just change the bits in red. The first bit is the add-on ID, the second is the title, the third is the add-on version string (the old version) and the fourth is the numeric version ID.

You'll notice that the add-on should now appear in the add-on list as being upgradeable.

Sorry lots of info there, hopefully that makes sense! This doesn't go into as much detail but there's a bit about the setup class here:
 

Gobb

Member
In XF1 you would typically have a single install method and passed into that would be the current details of the installed add-on, or it would be empty if it wasn't yet installed.

Something like this:

PHP:
public static function install($addOn)
{
    if (!$addOn)
    {
        // new install
    }
    else
    {
        if ($addOn['version_id'] < 1000070)
        {
            // upgrading *to* version 1.0.0 (1000070)
        }
    }
}

We've made this a little clearer in XF2. There are separate methods for installs and upgrades. Plus when using the StepRunnerInstallTrait, StepRunnerUpgradeTrait, or StepRunnerUninstallTrait traits you can split each process even further into distinct steps.

e.g. public function installStep1() and public function installStep2() and so on

For upgrades it's a little more complicated and it will look like e.g. public function upgrade2000070Step1() where the first number is the version being upgraded to and the second number is the step number.

So, if your current add-on version is 1.0.0 and has a version ID, e.g. 1000070 and the new add-on version you are working on is 2.0.0 and version ID, e.g. 2000070 then your upgrade method will look like:

PHP:
public function upgrade2000070Step1()
{
    // upgrading *to* version 2.0.0 (2000070)
}

Eventually you'll release version 2.0.1 and 2.0.2 and then maybe 2.1.0 so you'll end up with methods that look like this:

PHP:
public function upgrade2000070Step1()
{
    // upgrading *to* version 2.0.0 (2000070)
}

public function upgrade2000170Step1()
{
    // upgrading *to* version 2.0.1 (2000170)
}

public function upgrade2000270Step1()
{
    // upgrading *to* version 2.0.2 (2000270)
}

public function upgrade2010070Step1()
{
    // upgrading *to* version 2.1.0 (2010070)
}

The idea here being that the upgrade methods will allow you to upgrade from any version to any version.

So if an admin still has version 1.0.0 and they upgrade to version 2.1.0 it will actually run all of the upgrade steps above in order. Or if an admin in the future is upgrading from 2.0.1 to 2.1.0 then it will run the upgrade2000270Step1 and upgrade2010070Step1 methods.

If an admin is upgrading from an old version on 1.5 to the new version in 2.2 they shouldn't be hitting the install method at all. Different to XF1 add-ons, the install method should only be hit if it is a clean install, rather than an upgrade.

If someone is upgrading from an old version, the old version will still be listed in their xf_addon table. During the upgrade to XF2 we would have disabled the add-on and marked it as is_legacy.

To replicate that if you're working on a clean install, use the following query to add it to your xf_addon table:

Rich (BB code):
INSERT INTO xf_addon (addon_id, title, version_string, version_id, json_hash, active, is_legacy, is_processing, last_pending_action) VALUES
('AddOnId', 'Add-on title', '1.0.0', 1000070, '', 0, 1, 0, NULL);

Just change the bits in red. The first bit is the add-on ID, the second is the title, the third is the add-on version string (the old version) and the fourth is the numeric version ID.

You'll notice that the add-on should now appear in the add-on list as being upgradeable.

Sorry lots of info there, hopefully that makes sense! This doesn't go into as much detail but there's a bit about the setup class here:
Thanks for your in-depth response Chris, I really appreciate it. I believe I've understood everything and it's pretty much answered all of my questions. Just to clarify the bolded, in my test environment as I've already got the existing addon showing as legacy after upgrading to XF2, I should leave the install method completely out of the setup file? Or you mean that if I've done everything correctly, even if the install method is within the setup file, this shouldn't be called as it would be pointed to upgrade the legacy addon?
 

Chris D

XenForo developer
Staff member
Or you mean that if I've done everything correctly, even if the install method is within the setup file, this shouldn't be called as it would be pointed to upgrade the legacy addon?
Yes, this.

If it is showing up in the "Installable add-ons" section and the "Legacy add-ons" section then something is not quite right.

In fact, if the add-on ID of the new version and the old version is the same, and the version_id in the addon.json file is greater than the legacy add-on then it shouldn't be listed as legacy at all, it should just be listed under the "Upgradable add-ons" section.

The add-on ID is dictated by the folder structure of the add-on. If the add-on ID is different then you can specify the old add-on ID in the new addon.json file under the legacy_addon_id key:

JSON:
"legacy_addon_id": "OldAddOnId",
 

Gobb

Member
Yes, this.

If it is showing up in the "Installable add-ons" section and the "Legacy add-ons" section then something is not quite right.

In fact, if the add-on ID of the new version and the old version is the same, and the version_id in the addon.json file is greater than the legacy add-on then it shouldn't be listed as legacy at all, it should just be listed under the "Upgradable add-ons" section.

The add-on ID is dictated by the folder structure of the add-on. If the add-on ID is different then you can specify the old add-on ID in the new addon.json file under the legacy_addon_id key:

JSON:
"legacy_addon_id": "OldAddOnId",
Ok, thank you for clarifying. I believe it's my fault originally it wasn't pointing to the legacy ID so I've tried installing it as a standalone new addon as I didn't exactly understand how to correctly update the addon. I might just have to try again with a clean install. Thanks again :)

Edit: Clearing the entry from the addon table enabled me to upgrade the legacy addon. Thanks for all of the support!
 
Top