Jump to main content Jump to doc navigation

Overview

Your XML schema can define validation rules with nodes that follow this pattern:

<validation>
    <rule
        field="$name_of_field"
        name="$name_of_rule"
        type="callable|preg_match|xPDOValidationRule"
        rule="$various"
        value="$optional_parameter"
        message="string"
    />
</validation>

The rule element may use these attributes:

  • field: field name (required)
  • name: unique name for this rule. You can attach several rules to one field (required)
  • type: must be callable, preg_match, or xPDOValidationRule (required). Use callable, not callback. Older docs and samples sometimes said callback; xPDO’s validator only recognizes callable (see xPDOValidator in Revolution 3.x under core/vendor/xpdo/.../Validation/)
  • rule: depends on type. For callable, the PHP function or Class::method name. For preg_match, the regular expression. For xPDOValidationRule, a class that extends xPDOValidationRule (required)
  • value: optional argument for some xPDOValidationRule classes (optional)
  • message: failure message (required). In MODX 2+, this is often a lexicon key for translated strings
<rule
    field="category"
    name="preventBlank"
    type="xPDOValidationRule"
    rule="xPDOMinLengthValidationRule"
    value="1"
    message="category_err_ns_name"
/>

Regex Validation

Example from the modChunk schema:

<object class="modChunk" table="site_htmlsnippets" extends="modElement">
    <field key="name" dbtype="varchar" precision="50" phptype="string" null="false" default="" index="unique" />
    <!-- ... more fields ... -->
    <validation>
        <rule
            field="name"
            name="invalid"
            type="preg_match"
            rule="/^(?!\s)[a-zA-Z0-9\x2d-\x2f\x7f-\xff_-\s]+(?!\s)$/"
            message="chunk_err_invalid_name"
        />
    </validation>
</object>

Callable Validation

Set type="callable" to run your own PHP function through call_user_func_array(). The name lives in XML, so you cannot reference an object instance. Use a global function (my_function) or a static method (MyClass::myFunction). See also The callable Rule.

xPDOValidationRule Validation

Built-in rules ship with xPDO under core/vendor/xpdo/xpdo/src/xPDO/Validation/ (Revolution 3.x). Common classes:

  • xPDOMinLengthValidationRule
  • xPDOMaxLengthValidationRule
  • xPDOMinValueValidationRule
  • xPDOMaxValueValidationRule
  • xPDOObjectExistsValidationRule
  • xPDOForeignKeyConstraint

Example from modContentType:

<object class="modContentType" table="content_type" extends="xPDOSimpleObject">
    <field key="name" dbtype="varchar" precision="255" phptype="string" null="false" index="unique" />
    <!-- ... more fields ... -->
    <validation>
        <rule
            field="name"
            name="name"
            type="xPDOValidationRule"
            rule="xPDOMinLengthValidationRule"
            value="1"
            message="content_type_err_ns_name"
        />
    </validation>
</object>

Using xPDOValidator

You can pre-validate an xPDOObject with the validator, or let save() validate when xPDO::OPT_VALIDATE_ON_SAVE is enabled.

Pre-validation pattern from Revolution’s modObjectCreateProcessor:

if (!$this->object->validate()) {
    /** @var modValidator $validator */
    $validator = $this->object->getValidator();
    if ($validator->hasMessages()) {
        foreach ($validator->getMessages() as $message) {
            $this->addFieldError($message['field'], $this->modx->lexicon($message['message']));
        }
    }
}

After a failed save():

if (!$this->object->save()) {
    /** @var modValidator $validator */
    $validator = $this->object->getValidator();
    if ($validator->hasMessages()) {
        foreach ($validator->getMessages() as $message) {
            $this->addFieldError($message['field'], $this->modx->lexicon($message['message']));
        }
    }
}

Writing Your Own Validation Rules

For a custom xPDOValidationRule subclass, add one PHP class file per rule under your package model folder, for example core/components/my_pkg/model/my_pkg/normalparents.class.php. Use a lowercase filename with a .class.php extension so xPDO can find the class.

Schema snippet for a Custom Resource Class that only allows built-in parents:

<object class="MyCRC" extends="modResource">
    <composite alias="Things" cardinality="many" class="Things" foreign="parent" local="id" owner="local"></composite>
    <validation>
        <rule
            field="parent"
            message="Invalid parent"
            name="parent"
            rule="NormalParents"
            type="xPDOValidationRule"
        />
    </validation>
</object>

Matching rule class:

<?php
/**
 * @param mixed $value candidate value
 * @param array $options from the XML schema
 * @return boolean false on failed validation, true on pass
 */
class NormalParents extends xPDOValidationRule
{
    public function isValid($value, array $options = array())
    {
        parent::isValid($value, $options);
        $result = false;
        $obj = &$this->validator->object;
        $xpdo = &$obj->xpdo;
        $xpdo->log(xPDO::LOG_LEVEL_INFO, 'Running NormalParents validation rule');
        $validParentClasses = array('modDocument', 'modWebLink', 'modSymLink', 'modStaticResource');
        if ($obj->get('parent') === 0 || ($obj->Parent && in_array($obj->Parent->class_key, $validParentClasses))) {
            $result = true;
        }
        if ($result === false) {
            $this->validator->addMessage($this->field, $this->name, $this->message);
        }

        return $result;
    }
}

See Also

Support the team building MODX with a monthly donation.

The budget raised through OpenCollective is transparent, including payouts, and any contributor can apply to be paid for their work on MODX.

Backers

  • modmore
  • STERC
  • Digital Penguin
  • Jens Wittmann – Gestaltung & Entwicklung
  • CrewMark
  • Fabian Christen
  • Sepia River Studios
  • Dannevang Digital
  • Alex
  • A. Moreno
  • Chris Fickling
  • Stéphane Jäggi
  • Murray Wood
  • Anton Tarasov
  • JT Skaggs
  • deJaya
  • Lefthandmedia
  • eydolan
  • Following Sea
  • Guido Gallenkamp
  • YJ
  • Raffy
  • Snow Creative
  • Nick Clark
  • Guest
  • Helen
  • krisznet
  • Yanni
  • Richard

Budget

$194 per month—let's make that $500!

Learn more