@startuml abstract class Validator { + validate(name: string, val: mixed): array {abstract} + then(other: Validator): Validator } class ComposedValidator extends Validator { + __construct(first: Validator, then: Validator) + validate(name: string, val: mixed): array } ComposedValidator -->"- first" Validator ComposedValidator -->"- then" Validator class SimpleFunctionValidator extends Validator { - predicate: callable - error_factory: callable + __construct(predicate: callable, errorsFactory: callable) + validate(name: string, val: mixed): array } class ValidationFail implements JsonSerialize { - kind: string - message: string + __construct(kind: string, message: string) + getMessage(): string + getKind(): string + notFound(message: string): ValidationFail + unauthorized(message:string): ValidationFail + error(message:string): ValidationFail } class FieldValidationFail extends ValidationFail { - fieldName: string + __construct(fieldName: string, message: string) + getFieldName(): string + jsonSerialize() + invalidChars(fieldName: string): FieldValidationFail + empty(fieldName: string): FieldValidationFail + missing(fieldName: string): FieldValidationFail } class Validation { + validate(val: mixed, valName: string, failures: &array, validators: Validator...): bool } Validation ..> Validator class DefaultValidators { + nonEmpty(): Validator + shorterThan(limit: int): Validator + userString(maxLen: int): Validator + regex(regex:string, msg:string): Validator + hex(msg:string): Validator + name(msg:string): Validator + nameWithSpaces(): Validator + lenBetween(min:int, max:int): Validator + email(msg:string): Validator + isInteger(): Validator + isIntInRange(min:int, max:int): Validator + isURL(): Validator } DefaultValidators ..> Validator class FunctionValidator{ - validate_fn: callable + __construct(validate_fn:callable) + validate(name:string, val:mixed): array } Validator <|-- FunctionValidator @enduml