vds_ios/VDS/Protocols/FormFieldable.swift
Matt Bruce d02ca3eebd added ruleType so outside sources can know the type for this rule
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2024-07-30 11:06:03 -05:00

131 lines
3.7 KiB
Swift

//
// FormFieldable.swift
// VDS
//
// Created by Matt Bruce on 7/22/22.
//
import Foundation
/// Protocol used for a FormField object.
public protocol FormFieldable {
associatedtype ValueType = AnyHashable
/// Unique Id for the Form Field object within a Form.
var inputId: String? { get set }
/// Value for the Form Field.
var value: ValueType? { get }
}
/// Protocol for FormFieldable that require internal validation.
public protocol FormFieldInternalValidatable: FormFieldable, Errorable {
/// Rules that drive the validator
var rules: [AnyRule<ValueType>] { get set }
/// Is there an internalError
var hasInternalError: Bool { get }
/// Internal Error Message that will show.
var internalErrorText: String? { get }
var validator: (any FormFieldValidatorable)? { get set }
func validate()
}
extension FormFieldInternalValidatable {
/// Whether or not to show the internal error
public var hasInternalError: Bool {
guard let validator, !showError else { return false }
return !validator.isValid
}
public var internalErrorText: String? {
guard let validator, !validator.isValid else { return nil }
if let errorText, !errorText.isEmpty {
return errorText
} else {
return validator.errorMessage
}
}
}
/// Struct that will execute the validation.
public protocol FormFieldValidatorable {
associatedtype FieldType: FormFieldable
/// FormFieldable to be validated.
var field: FieldType { get set }
/// Rules that will be applied against the FormFieldable
var rules: [AnyRule<FieldType.ValueType>] { get set }
/// Error Message that will show.
var errorMessage: String? { get }
/// Is the FormField valid.
var isValid: Bool { get }
/// Run the rules against the FormFieldable.
func validate()
}
/// Rule that will be executed against a specific ValueType.
public protocol Rule<ValueType> {
associatedtype ValueType
/// Determines if this rule valid for the value passed.
func isValid(value: ValueType?) -> Bool
/// Error Message to be show if the value is invalid.
var errorMessage: String { get }
/// type of rule
var ruleType: String { get }
}
extension Rule {
public var ruleType: String { "\(Self.self)" }
}
/// Type Erased Rule for a specific ValueType.
public struct AnyRule<ValueType>: Rule {
private let _isValid: (ValueType?) -> Bool
public var ruleType: String
public let errorMessage: String
public init<R: Rule>(_ rule: R) where R.ValueType == ValueType {
self._isValid = rule.isValid
self.ruleType = rule.ruleType
self.errorMessage = rule.errorMessage
}
public func isValid(value: ValueType?) -> Bool {
return _isValid(value)
}
}
/// Generic Validator for a specific FormFieldable.
public class FormFieldValidator<Field:FormFieldable>: FormFieldValidatorable{
public var field: Field
public var rules: [AnyRule<Field.ValueType>]
public var errorMessages = [String]()
public var isValid: Bool = true
public init(field: Field, rules: [AnyRule<Field.ValueType>]) {
self.field = field
self.rules = rules
}
public var errorMessage: String? {
guard errorMessages.count > 0 else { return nil }
return errorMessages.joined(separator: "\r")
}
public func validate() {
errorMessages.removeAll()
for rule in rules {
if !rule.isValid(value: field.value) {
errorMessages.append(rule.errorMessage)
isValid = false
return
}
}
isValid = true
}
}