Avoid Trashing Properties with setProperties()

The safe way to set an element property

Suppose that you want to change the value of a single property of a MODX element (usually a snippet) in code. There is no setProperty() method, but you would expect this code to do the job:

/* Don't use this code! */
$props = $snippet->getProperties();
$props['someKey'] = 'someValue';

It looks innocent enough but it will trash all the properties of the snippet (including the one you're trying to set).


The problem is that the modElement class's getProperties() and setProperties() methods are not symmetrical. The getProperties() method gets only the name (key) and value fields. Usually, that's all you want, but there are a number of other fields such as the description, lexicon, and type field, which getProperties() does not retrieve. The setProperties() method, on the other hand, sets *all* the fields of each property from the array you send it. If they are missing from the array you send, they will either be saved blank or set to their default values. Worse yet, you can't send them because you don't have them.

The type field, for example defaults to textfield, so with the code above, every property of the snippet will have its type field set to textfield, including any Yes/No or List properties. Those properties will no longer work as expected in MODX.

Even if your property is the only one the snippet has and it's a textfield property, the code above will still cause problems because the description, lexicon, and area fields will be saved blank.

The Solution

Preventing this disaster is easy enough. You just need to send a second argument to the setProperties() method.

/* This code is fine */
$props = $snippet->getProperties();
$props['someKey'] = 'someValue';
$snippet->setProperties($props, true);

Sending true as the second argument in the setProperties() call tells MODX to merge the properties you are sending with the existing ones. That will prevent any of the current values from being trashed. It's easy to do, but also easy to forget.

What About Using get('properties')?

You can also solve the problem by using get('properties') instead of getProperties(), but it's a little less convenient. When you call get('properties'), MODX returns an array of arrays rather than a simple array of keys and values. With getProperties(), you get an array like this:

    'name1' => 'value1',
    'name2' => 'value2,

With get('properties'), you get an array like this:

array {
    'name1' = array( 
        'name' => 'name1'
        'value' => 'value1',
        /* more fields here */
    'name2' = array(
        'name' => 'name1'
        'value' => 'value1',
        /* more fields here */

Since each array member is a property with an array of fields, using get('properties') means that setting the value requires code like this:

$props['name1']['value'] = 'someValue'

Since you seldom want to set any field other than the value field, it's usually easier just to use getProperties() and setProperties($properties, true).

Comments (1)

  1. Susan OttwellNov 16, 2013 at 10:39 PM

    Good to know. Would you consider this a bug or a feature? I would think that the getProperties and setProperties should be symmectrical.

Please login to comment.