Skip to content

module Athena::Validator::Constraints::GroupSequence::Provider #

AVD::Constraints::GroupSequences can be a good way to create efficient validations. However, since the sequence is static, it is not a very flexible solution.

Group sequence providers allow the sequence to be dynamically determined at runtime. This allows running specific validations only when the object is in a specific state, such as validating a "registered" user differently than a non-registered user.

class User
  include AVD::Validatable

  # Include the interface that informs the validator this object will provide its sequence.
  include AVD::Constraints::GroupSequence::Provider

  property name : String

  # Only validate the `email` property if the `#group_sequence` method includes "registered"
  # Which can be determined using the current state of the object.
  @[Assert::Email(groups: "registered")]
  @[Assert::NotBlank(groups: "registered")]
  property email : String?

  def initialize(@name : String, @email : String); end

  # Define a method that returns the sequence.
  def group_sequence : Array(String | Array(String)) | AVD::Constraints::GroupSequence
    # When returning a 1D array, if there is a vaiolation in any group
    # the rest of the groups are not validated.  E.g. if `User` fails,
    # `registered` and `api` are not validated:
    return ["User", "registered", "api"]

    # When returning a nested array, all groups included in each array are validated.
    # E.g. if `User` fails, `Premium` is also validated (and you'll get its violations),
    # but `api` will not be validated
    return [["User", "registered"], "api"]

See AVD::Constraints::Sequentially for a more straightforward method of applying constraints sequentially on a single property.

Direct including types

Athena::Validator::Spec::EntityGroupSequenceProvider Athena::Validator::Spec::EntitySequenceProvider


abstract #group_sequence : Array(String | Array(String)) | AVD::Constraints::GroupSequence #

View source