Skip to content

fix: surface silently skipped custom validators in the log - #313

Open
Ibochkarev wants to merge 1 commit into
Sterc:3.xfrom
Ibochkarev:fix/custom-validator-silent-skip
Open

fix: surface silently skipped custom validators in the log#313
Ibochkarev wants to merge 1 commit into
Sterc:3.xfrom
Ibochkarev:fix/custom-validator-silent-skip

Conversation

@Ibochkarev

Copy link
Copy Markdown

Validator::validate() requires any validator that isn't a built-in method (custom snippet validators, and anything like reCAPTCHA that runs through the same path) to be listed in &customValidators. That's intentional: it stops a &validate entry from brute-forcing arbitrary snippets on the site.

When a validator isn't on that list, FormIt skips it and treats the field as valid, with zero error message. The only trace is a LOG_LEVEL_INFO log line, which sits below MODX's default log_level and never actually gets written. From the template author's side, this looks identical to "my custom validator's error message isn't showing", because nothing tells them the validator never ran.

Reproduced the full path with a standalone script that stubs modX/modSnippet and exercises the real Validator::validateFields()/validate() against the docs' custom-validator example ($validator->addError($key, ...) + return a bool). With customValidators unset, fi.error.<field> stays empty and nothing in the default MODX log explains why. With customValidators correctly set, the same snippet populates the placeholder as expected, so the addError/placeholder plumbing itself is fine, only the "why did nothing happen" signal was missing.

Bumped that log call to LOG_LEVEL_WARN and spelled out the fix in the message (add the type to &customValidators).

While in there, also hardened the customValidators normalization a few lines up: $this->config['customValidators'] can arrive as an array (the constructor already explodes it from formit->config) or as a raw string (when the config passed into the Validator's constructor still carries the unprocessed scriptProperty, which overrides the constructor's array default via array_merge). The old code unconditionally called explode() on it, which throws a TypeError if it's already an array. Now it only explodes when it's actually a string.

Fixes #273

When a &validate entry names a type that isn't a built-in method and
isn't listed in customValidators, Validator::validate() skips it and
treats the field as valid with no error message. That's by design
(customValidators is an allowlist to stop brute-forcing arbitrary
snippets), but the only trace was a LOG_LEVEL_INFO log entry, which
sits below MODX's default log_level and never shows up. From the
outside this looks exactly like "the custom validator's error message
isn't showing", including for validators like reCAPTCHA that run
through the same customValidators-gated snippet path.

Bump that log line to LOG_LEVEL_WARN and spell out the fix (add the
type to &customValidators) so the actual cause is visible without
digging into FormIt's source.

Also hardened the customValidators normalization above it:
$this->config['customValidators'] can arrive as an array (the
constructor already explodes it from formit->config) or as a raw
string (when the config passed to the Validator's constructor
carries the unprocessed scriptProperty). The old code always called
explode() on it, which throws a TypeError if it's already an array.
Reproduced both paths with a standalone script exercising
Validator::validateFields()/validate() against a stub custom
validator snippet.

Fixes Sterc#273
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Custom validator messages not showing

1 participant