Creating Extras for Revo 3 Part 3: Resources and Users in Transport Packages

Dealing with Resources and users when converting a MODX Extra for Revolution 3.

By Bob Ray
May 16, 2022
Creating Extras for Revo 3 Part 3: Resources and Users in Transport Packages

In my previous article, we looked at Transport Package issues in converting an Extra for Revolution 3. In this one, we’ll look specifically at Resources and users.

Resources

If you create a package that will run in both Revo 2 and Revo 3, the correct class_key of a Resource properly varies. In Revo 2 it’s modDocument. In Revo 3 it’s MODX\Revolution\modDocument.

In the last article, we saw some code for setting the class_key field correctly after-the-fact in a resolver. In that article, I hinted that there was a better way. Here it is: if the class_key field of a Resource being transported in a Transport Package is unset, MODX will fill it with the correct value for the version of MODX the process is running in.

Usually, any Resources you put into a package have some fields set, like pagetitle, description, introtext, published, etc. As long as you don’t send the class_key field, it will get set properly.

If you’ve created the fields using $resource->toArray(), you can always just edit out the class_key field, or if the process is automated, use unset($fields['class_key']);. This has to be done before running the build.transport.php script (unless you want to dig into the guts of the resulting transport file, which you definitely don’t).

Although dropping the class_key field before building the transport package is the best method, there is a situation where you might want to fix it in a resolver. If a Revo 3 user has installed an older version of your package, and that version has the Resource class_key field set to modDocument, you can update it in a resolver to the correct value. Here is the code, quoted from my previous article:

$isMODX3 = $modx->getVersionData()['version] >= 3;
$classPrefix = $isMODX3 ? 'MODX\Revolution\\' : '';

/* Get the resources here and loop through them setting the class_key: */
$aliases = array(
    'myresource1',
    'myresource2',
    /* ... */
);

foreach ($aliases as $alias) {
    $resource = $modx->getObject($classPrefix . 'modResource, array('alias' => $alias));
    if ($resource) {
        $resource->set('class_key', $classPrefix . 'modDocument);
        $resource->save();
    }
}

This is a fairly rare occurrence. When a site is updated from Revo 2 to Revo 3, Setup updates all the Resource class keys. So the user would have to have installed the older version after upgrading to Revo 3. Still, you might want to do this, just to be on the safe side.

It’s uncommon to create anything other than modDocument Resources in a Transport Package, but if you do, you can adapt the resolver code above to correct their class keys.

Users

The user object also has a class_key field. In Revo 2, it’s modUser. In Revo 3, it’s MODX\Revolution\modUser.

If your Extra doesn’t create any users, you don’t have to worry about them in your Transport Package. If you do create users, the best practice, as for Resources, is to omit or unset the class_key field for all users before the package is built. MODX will set it correctly for you.

If the package is an upgrade, you may want to create a resolver that makes sure the class_key is correct for the MODX version of the site, as we did for Resources just above. You can adapt the code above for this by just changing modResource to modUser in the code, and retrieving the objects by username rather than alias.

Use Statements and instanceof

As you’ve probably figured out, use statements can’t be used in code that’s meant to run in both Revo 2 and Revo 3, because they would only be used in Revo 3, and there’s no such thing as a conditional use statement. Because they apply at compile time rather than run time, they can’t be enclosed in an if statement, and you can’t use a variable holding a string for them either.

There’s also no way to make instanceof work in both Revo 2 and Revo 3 because the classes won’t be the same, and like use you can’t use a variable to represent the class name. Luckily, MODX is very reliable about returning null if it can’t instantiate or retrieve a class object, so something like this will work fine:

$doc = $modx->getObject($classPrefix . 'modResource', $criteria);
/* Or $doc = $modx->newObject($classPrefix . 'modResource'); */

if (! $doc) {
    /* call failed */
}

If you feel you really need to find out if you have a genuine object of a specific class, you can do something like this:

if (isObject($doc) && (get_class($doc) === $classPrefix . 'modResource')) {
     /* Object is legit */
} else {
    /* not an instance of $classPrefix . modResource */
}

Of course if you have a separate version of your package for Revo 3, you’re free to use both use and instanceof at will.


Bob Ray is the author of the MODX: The Official Guide and dozens of MODX Extras including QuickEmail, NewsPublisher, SiteCheck, GoRevo, Personalize, EZfaq, MyComponent and many more. His website is Bob’s Guides. It not only includes a plethora of MODX tutorials but there are some really great bread recipes there, as well.