Structure of a Modddel
A Modddel typically looks like this :
1. Imports and Part statements
If you're using freezed for making the failures sealed classes, also import it and add the part statement filename.freezed.dart
, where filename
is the name of the file.
2. The @Modddel
Annotation
@Modddel
AnnotationThe @Modddel
annotation is where you can define the validationSteps of your modddel.
Example :
As you can see, inside the validationSteps
parameter, you provide a list of ValidationStep
s in the order that you want them to be processed.
For each ValidationStep
, you provide its name
, as well as the list of validations
it contains (the order doesn't matter here). The name
is mainly used to make the name of the invalid-step union-case class name (Ex : 'Form' → 'InvalidUsernameForm'). It must begin with an uppercase letter, and it must be made of valid dart identifier characters (alphanumeric, underscore and dollar sign).
For each Validation
, you provide its name
, as well as the failureType
. The name
is used to make the name of the validation method (Ex : 'size' → 'validateSize'), as well as the name of the failure (Ex : 'size' → 'sizeFailure'). It must begin with a lowercase letter, and it must be made of valid dart identifier characters. The failureType
is the type of the failure of the validation. You can either provide it as a typeArg : FailureType<UsernameSizeFailure>()
, or you can provide it as a string : FailureType('UsernameSizeFailure')
(the latter takes precedence).
3. The class declaration
When declaring your modddel class, you should extend the appropriate modddel kind, such as SingleValueObject
, MultiValueObject
, SimpleEntity
... , and provide two type arguments. The first type argument should be 'Invalid' followed by the modddel name, and the second type argument should be 'Valid' followed by the modddel name.
Your modddel class should also mix in a mixin with the name of your modddel prefixed by _$
(Like freezed).
4. The private empty constructor
The modddel should only contain one generative constructor, which should be private and empty. Example : Age._()
. You should never use this constructor to create an instance of the Modddel.
5. The factory constructor
The parameters of the factory constructor will be the list of properties the modddel contains. Parameters can be positional or named, optional or required, and can have default values.
The factory constructor should always return the result of calling the mixin's _create
static method. This method is generated by the modddels generator, and you should pass to it all the parameters of the factory.
Example :
Decorators and comments
You can document/decorate a field by documenting/decorating its parameter inside the factory constructor.
Example : Documenting firstName
and annotating lastName
with @Deprecated
:
Asserts & Sanitization
The factory constructor allows you to do all sorts of data manipulation or sanitization before effectively creating the modddel.
Example :
6. The validate methods
After running the generator, your IDE will prompt you to override the "validate" method(s) :
This is the place where you can implement your validation logic. For example :
The age
parameter contains all the fields of the Modddel. You can omit its type for a cleaner look :
You should NEVER access an instance member (property, method, getter...) from within the "validate" methods. Doing so will throw a runtime error.
7. The Failure(s)
In the example, the Failure is created using freezed.
Note that the failure should always extend ValueFailure
if the modddel is a ValueObject, and it should extend EntityFailure
if the modddel is an Entity.