diff --git a/VDS/Protocols/FormFieldable.swift b/VDS/Protocols/FormFieldable.swift index 294f581c..9acc3e5a 100644 --- a/VDS/Protocols/FormFieldable.swift +++ b/VDS/Protocols/FormFieldable.swift @@ -18,57 +18,85 @@ public protocol FormFieldable { var value: ValueType? { get set } } -public struct AnyRule { +/// Protocol for FormFieldable that require internal validation. +public protocol FormFieldValidatable: FormFieldable { + /// Is there an internalError + var hasInternalError: Bool { get } + /// Internal Error Message that will show. + var internalErrorText: String? { get } + /// Validator that will run the Field Validation + var validator: (any FormFieldValidatorable)? { get set } +} + +/// 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] { 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 { + 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 Erased Rule for a specific ValueType. +public struct AnyRule: Rule { private let _isValid: (ValueType?) -> Bool + public let errorMessage: String - init(_ rule: R) where R.ValueType == ValueType { + public init(_ rule: R) where R.ValueType == ValueType { self._isValid = rule.isValid self.errorMessage = rule.errorMessage } - public func isValid(value: Any?) -> Bool { - guard let typedValue = value as? ValueType? else { - return false - } - return _isValid(typedValue) + public func isValid(value: ValueType?) -> Bool { + return _isValid(value) } } -public protocol Rule { - associatedtype ValueType - func isValid(value: ValueType?) -> Bool - var errorMessage: String { get } -} -public class FieldValidator{ +/// Generic Validator for a specific FormFieldable. +public class FormFieldValidator: FormFieldValidatorable{ public var field: Field - public var rules: [AnyRule]? + public var rules: [AnyRule] public var errorMessages = [String]() - - public init(field: Field, rules: [AnyRule]? = nil) { + public var isValid: Bool = true + + public init(field: Field, rules: [AnyRule]) { self.field = field self.rules = rules } public var errorMessage: String? { - errorMessages.joined(separator: "\r") + guard errorMessages.count > 0 else { return nil } + return errorMessages.joined(separator: "\r") } - public func validate() -> Bool{ + public func validate() { errorMessages.removeAll() - guard let rules else { - return true - } - for rule in rules { if !rule.isValid(value: field.value) { errorMessages.append(rule.errorMessage) - return false + isValid = false + return } } - return true + isValid = true } }