Validations¶
Data Dictionary validations guard the boundary between UI buffers and adapter/database operations by checking or adjusting data before save and find workflows use it.
Related links:
Validation model¶
cDataDictionary composes validation mixins and owns local record buffers. Validation runs against those Data Dictionary buffers before code continues with save, find, or field-specific workflows.
Request_Validate validates the current Data Dictionary and required parent path. Request_Validate_All collects validation across the DDO structure. Validate_Field validates one field.
Validation functions return True when invalid and False when valid. FieldError hField eErrNr sErrText raises the validation error and records the current validation field for extended error information.
Call validation explicitly when code needs a validation pass before save or before continuing after a field edit.
Running validation¶
Use Db\cDataDictionary.pkg
Boolean bInvalid
Send Clear of oCustomerDD
Set Field_Option of oCustomerDD (RefTable(oCustomerDD.Name)) DD_Required to True
Get Request_Validate of oCustomerDD to bInvalid
If (bInvalid) Begin
Procedure_Return
End
Set Field_Changed_Value of oCustomerDD (RefTable(oCustomerDD.Name)) to "Data Access"
Get Validate_Field of oCustomerDD (RefTable(oCustomerDD.Name)) to bInvalid
Explicit validation is useful before save or when code needs to validate a single user-edited field before continuing.
Built-in field options¶
| Option | Behavior |
|---|---|
DD_Required |
Attaches required-field validation. Strings and wstrings fail when the trimmed value is empty; numbers fail when zero. Raises DFERR_ENTRY_REQUIRED with Field value required. |
DD_FindReq |
Requires an active related parent record for relation fields or matching foreign-field categories. Raises DFERR_ENTER_VALID_REC_ID with Please enter a valid record ID. |
DD_Capslock |
Adjusts field values written to the Data Dictionary buffer to uppercase. This is value-adjustment behavior, not a validation failure. |
Set Field_Option (RefTable(Self.Name)) DD_Required to True
Set Field_Option (RefTable(Self.State)) DD_Capslock to True
Set Foreign_Field_Option DD_KEYFIELD DD_FindReq to True
Validation events¶
| Level | Methods | Payload | Use |
|---|---|---|---|
| DD-level | OnValidate_Add, OnValidate_Del, OnValidate_Has |
tDD_OnValidate |
Whole-record or cross-field checks. |
| Field-level | OnFieldValidate_Add, OnFieldValidate_Del, OnFieldValidate_Has |
tDD_OnFieldValidate |
One field's validation rule. |
| Foreign-field-level | OnForeignFieldValidate_Add, OnForeignFieldValidate_Del, OnForeignFieldValidate_Has |
tDD_OnForeignFieldValidate |
Parent/child relation validation such as find-required behavior. |
| Field-value-change | OnFieldValueChange_Add, OnFieldValueChange_Del, OnFieldValueChange_Has |
tDD_OnFieldValueChange |
Adjustments such as capslock before a value reaches the DD buffer. |
Payload fields:
| Payload | Fields |
|---|---|
tDD_OnValidate |
hoDD, bInValid |
tDD_OnFieldValidate |
hoDD, hField, bInvalid |
tDD_OnForeignFieldValidate |
hoDD, hoParentDD, hField, bInvalid |
tDD_OnFieldValueChange |
hoDD, hField, vValue |
Handler signature:
Procedure HandlerName <PayloadType> ByRef details Boolean ByRef bCancel
For validation failures, set the invalid flag and call FieldError. Set bCancel=True only when a handler intentionally stops later handlers.
Mixin-style validators¶
Built-in field options are implemented as mixins that register field-option handlers globally and attach or detach event handlers when a field option is set.
Define DD_UsernameRequired for "USERNAME_REQUIRED"
Class cDD_UsernameRequired_mixin is a Mixin
Procedure Validate_DD_UsernameRequired tDD_OnFieldValidate ByRef details Boolean ByRef bCancel
String sValue
Get Field_Current_Value of details.hoDD details.hField to sValue
If (Trim(sValue) = "") Begin
Send FieldError of details.hoDD details.hField DFERR_OPERATOR "Username is required"
Move True to details.bInvalid
End
End_Procedure
Procedure Set_DD_UsernameRequired tDD_OnSetFieldAttribute ByRef details Boolean ByRef bCancel
If (DD_MetaValueIsTrue(details.vValue)) Begin
Send OnFieldValidate_Add of details.hoDD details.hField (RefProc(Validate_DD_UsernameRequired)) Self
End
Else Begin
Send OnFieldValidate_Del of details.hoDD details.hField (RefProc(Validate_DD_UsernameRequired)) Self
End
Move True to details.bStored
End_Procedure
Procedure Get_DD_UsernameRequired tDD_OnGetFieldAttribute ByRef details Boolean ByRef bCancel
Move (OnFieldValidate_Has(details.hoDD, details.hField, (RefProc(Validate_DD_UsernameRequired)), Self)) to details.vValue
End_Procedure
End_Class
Send OnSetFieldAttribute_Add of ghoGlobalDDMetaDataHandlers DD_UsernameRequired (RefProc(Set_DD_UsernameRequired)) C_UnresolvedObject
Send OnGetFieldAttribute_Add of ghoGlobalDDMetaDataHandlers DD_UsernameRequired (RefProc(Get_DD_UsernameRequired)) C_UnresolvedObject
Use this style when the behavior belongs in a reusable Data Dictionary subclass or mixin package.
Object-style field validators¶
cDD_Field_Validator is the shorter object-oriented pattern for reusable field validators.
Contract:
Use Db\cDD_Field_Validator.pkg.- Define a field option id such as
Define DD_EmailAddress for "CUSTOM_EMAILADDRESS". - Create an object based on
cDD_Field_Validator. - Set
psOptionIdbeforeEnd_Construct_Object. - Override
Procedure Validate_DD_Field tDD_OnFieldValidate ByRef details Boolean ByRef bCancel. - Read the value with
Get Field_Current_Value of details.hoDD details.hField to sValue. - On failure,
Send FieldError of details.hoDD details.hField DFERR_OPERATOR "..."andMove True to details.bInvalid. - Enable per field with
Set Field_Option ... DD_EmailAddress to True; disable withFalse.
Use Db\cDD_Field_Validator.pkg
Define DD_EmailAddress for "CUSTOM_EMAILADDRESS"
Object oEmailValidator is a cDD_Field_Validator
Set psOptionId to DD_EmailAddress
Procedure Validate_DD_Field tDD_OnFieldValidate ByRef details Boolean ByRef bCancel
Integer iAt iDot
String sValue
Get Field_Current_Value of details.hoDD details.hField to sValue
If (Trim(sValue) <> "") Begin
Move (Pos("@", sValue)) to iAt
Move (RightPos(".", sValue)) to iDot
If (not(iAt > 1 and iDot > 0 and iDot > iAt + 1 and iDot < Length(sValue))) Begin
Send FieldError of details.hoDD details.hField DFERR_OPERATOR "Please enter a valid email address"
Move True to details.bInvalid
End
End
End_Procedure
End_Object
Class cCustomerDataDictionary is a cDataDictionary
Procedure Construct_Object
Forward Send Construct_Object
Set phEntity to (RefEntity(Customer))
Set Field_Option (RefTable(Self.EMail_Address)) DD_EmailAddress to True
End_Procedure
End_Class
The same object can be enabled on matching fields in multiple Data Dictionary classes, so rules such as email format or username policy stay centralized.
Choosing a validator style¶
| Style | Best for |
|---|---|
| Mixin-style | Shipping a reusable DD subclass or mixin package, or when the rule must also provide custom option get/set behavior. |
Object-style cDD_Field_Validator |
One reusable field validation rule that should be globally available and enabled by field option across many DDs. |
Value-adjustment rules such as capslock should use field-value-change handlers. Validation failures should use validation handlers and FieldError.
API checklist¶
- Choose a unique field option id string, e.g.
CUSTOM_EMAILADDRESS. - Register option handlers globally through
cDD_Field_Option,cDD_Field_Validator, or explicitOnSetFieldAttribute_Add/OnGetFieldAttribute_Addcalls. - Attach/detach event handlers when the option value changes.
- Use
DD_MetaValueIsTruefor option truthiness. - Read values from
details.hoDDanddetails.hField, not from a global table buffer. - On validation failure, call
FieldErrorand set the payload invalid flag. - Verify
Field_Optionreturns the expected state through the matching*_HasAPI. - Keep event handlers reusable and side-effect-light; value transformation belongs in
OnFieldValueChange, while rejection belongs in validation events.