Resolvers VII - Updating Property Sets

Using resolvers in a transport package to update element property sets.

By Bob Ray  |  August 5, 2025  |  4 min read
Resolvers VII - Updating Property Sets

Overview

In my previous article, I wrote about using resolvers in a transport package to modify snippet default properties. In this one, we'll see examples of using code in a resolver to update any property sets attached to our snippets, which is a little tricky.

We'll still use the material at the top to set the class prefix, the search and replace strings and arrays, and the function to check for the old class names. Here's that code:

function checkContent(array $terms, string $content) {

    foreach ($terms as $term) {
        if (strpos($content, $term) !== false) {
            return true;
        }
    }

    return false;
}

$base = MODX_CORE_PATH . 'components/classextender/model/';

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

$uSearch = 'UserData';
$uReplace = 'userData';
$rSearch = 'ResourceData';
$rReplace = 'resourceData';

$searchArray = array(
    $uSearch,
    $rSearch,
);
$replaceArray = array(
    $uReplace,
    $rReplace,
);

Property Sets attached to the Snippet

As I said in the previous article, users may have put properties in the snippet tags themselves, which would override the snippet's default properties. We already handled that in the earlier article where we modified the content of the resource that hold those snippet tags. But what if the user created one or more property sets that contain the UserDataClass and/or ResourceDataClass properties?

We can get any property sets attached to each snippet by asking for them by their alias with this line of code:

$propertySets = $snippetObj->getMany('PropertySets');

The Property Set Code

Things get a little crazy here, because that line above doesn't return what the name suggests. We'll discuss that after the code. See if you can figure out what the property set section of the code below is doing:

$snippets = array(
    'GetExtUsers',
    'SetUserPlaceholders',
    'GetExtResources',
    'MyGetExtUsers',
    'MySetUserPlaceholders',
    'MyGetExtResources',
);

$snippetCount = 0;
$propertySetCount = 0;
$fixedSnippetCount  = 0;
$fixedPropertiesCount

foreach ($snippets as $snippet) {
    $snippetObj = $modx->getObject($prefix . 'modSnippet', array('name' => $snippet));
    if ($snippetObj) {
        /* Correcting the snippet code went here */
        /* Check snippet's default properties went here */

        /* Check Property Sets (if any) */
        $intersects = $snippetObj->getMany('PropertySets');

        if (!empty($propertySets)) {
            foreach ($intersects as $intersect) {
                $dirty = false;
                $propsetId = $intersect->get('property_set');
                $propertySetCount++;
                $actualPropertySet = $modx->getObject($prefix . 'modPropertySet', $propsetId);

                $props = $actualPropertySet->get('properties');

                if (isset($props['UserDataClass'])) {
                    if ($props['UserDataClass']['value'] === $uSearch) {
                        $fixedPropertySetCount++;
                        $props['UserDataClass']['value'] = $uReplace;
                        $actualPropertySet->set('properties',$props);
                        $dirty = true;
                    }
                }
                if (isset($props['ResourceDataClass'])) {

                    if ($props['ResourceDataClass']['value'] === $rSearch) {
                        $fixedPropertyCount++;
                        $props['ResourceDataClass']['value'] = $rReplace;
                        $actualPropertySet->set('properties',$props);
                        $dirty = true;
                    }
                }
                if ($dirty) {
                    $actualPropertySet->save();
                }
            }
        }
    }
}

First, we check to see if there are any property sets. Often there won't be. If there are, we need to get the property set's properties. This gets a little strange because what our $intersects = $snippetObj->getMany('PropertySets') call returns is actually an array of, not property sets, but modElementPropertySet objects. These are the intersect objects that connect elements to their property sets. They only have three fields:

element  (integer) — ID of the element
element_class  (string) — class of the element (e.g., modSnippet)
property_set  (integer) — ID of the property set

These intersect objects are necessary because it's a many-to-many relationship. An element can be connected to more than one property set and a property set can be connected to more than one element. Looking at the fields above, you can see that there's no room there for the actual property values, which are held in the modPropertySet object. When we made our getMany('PropertySets') call, we were really asking for the modElementPropertySet objects have the ID of our snippet in their element field.

Typically, there will be only one result, but there could be more, and the return value is an array, so we loop through it to get the actual propertySet(s). We get the property set with the ID held in the intersect's property_set field:

$propsetId = $intersect->get('property_set');
$propertySetCount++;
$actualPropertySet = $modx->getObject($prefix . 'modPropertySet', $propsetId);

Notice that we don't need to know what kind of element it is. Since they are all modProperty set objects, they all have the same structure.

We only want the properties, which we get with $actualPropertySet->get('properties'). The properties are held as a JSON string in the properties field of a property set. When we call get() to retrieve them, MODX automatically converts them to a PHP associative array before returning them. At this point, we no longer need the intersect or the snippet, we just modify the class-name member of the returned array of properties (if necessary), update the property set's properties with set('properties'), and then save the property set.

Coming Up

In my next article, we'll look at how to update Template Variables in a resolver.


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.