Handling Forms

The The Form class is used to create forms and to aslo handle all form data requests sent through the server. This class along with the Request class, are both able to set form validations, restrictions and saving of validated request data into the database. An introduction into the generation of forms through Form class using predefined methods was already discussed in Form helper class. Here, we will focus more on form validations in relation with the Request class.

Request Data
All form data request sent are be obtained by using the Request class which enables us to perform necessary form validations on data request sent. This class ensures that only request data that meets a certain requirements are obtained. These requirements are categorized under different level of strictness. which are strict and non-strict levels. These levels are then applied on form input request validations. We can initialize the request class as shown below:

  use spoova/mi/core/class/Request;

  $Request = new Request;
    

Fetching Request Data : Non-Strict Type
Request data are strictly advised to be obtained using the $Request->data() method. This method ensures that only request data forwarded with a CSRF request token are obtainable. If a request data is fowarded without a request token, an empty array will be returned. When working within the template files, the @csrf template directive is used to add CSRF tokens input fields to forms. The sample below reflects the syntax of obtaining request data:

  $Request = new Request;

  $Formdata = $Request->data(); // returns the request data sent
    
Although the $Request->data() is expected to return the form data sent from request by default, if the @csrf directive is not supplied, the data returned will be an empty array. In order to ensure that all data supplied are accepted, each form must have a @csrf directive attached to it.

Fetching Request Data : Strict Type
Setting request data as a strict type resolves to an error page if the means by which a request data was sent is not permitted. This is mostly caused when a CSRF token is not added to a form or the forwarded CSRF token is rejected. A csrf token may become reject if it does not match the token set at run-time or the token has expired if timed. We can set a data to strict type using the strict() method. If a token is rejected, rather than for data() method to return an empty array, an error page will be displayed instead based on the type of error that occured.

  $Request = new Request;

  $Request->strict(); //set request data as strict type

  $Formdata = $Request->data(); //display error page if data was sent without valid CSRF
    
Although the $Request->data() is expected to return form data sent from request or an empty array if no csrf token is set, if the strict method is applied, the request page will return a csrf default error page preventing any further action.

Checking Request Data
An empty data may be returned due to an invalid token, this does not mean that data sent cannot be checked to see if it contains a particular key. The has() method allows the checking of data forwarded before it is returned. This is useful in cases when we may want to detect the type of button clicked. An example is shown below:

  $Request = new Request;

  if($Request->has('submit')){

      $Request->strict();
      $Formdata = $Request->data();

  }
    
In the above, assuming that our form has a button with the name "submit", then we can check if the data forwarded has a "submit" key before setting the strict type or obtaining the data. Also notice, that the strict() method comes after the has() function. This is because setting the strict type affects the has() method too and prevents it from checking any data if the token is not valid.

Timing Request Data - Timed Token
A request can be timed by using the expires() method. This tells the request the number of seconds required in order for a data to be sent. If a request data is not sent within the required number of seconds, the data sent is not accepted hence, it returns an empty array or displays error message. It should be noted that even if a csrf token has expired leading to an empty data, the has() method will still allow the checking of data forwarded as long as the strict() method is not applied before it. However, unlike the strict() method, the expires() method alone has no effect on the has() method if used before it unless a strict() method is declared along with it. The example below is the best way to declare the strict type along with the expires() method:

  $Request = new Request;

  if($Request->has('submit')){

      $Request->strict()->expires(5);
      $Formdata = $Request->data();

  }
    
In the above, the csrf token expires in "5 seconds". This pushes the data to return empty data but because the strict method is set upon it, the request returns an error page if the token expires or becomes invalid.

Data Validation
The first level of authentication encountered is the csrf token validation which determines if data forwarded is accepted or rejected. When data fowarded is accepted having passed through the first stage of csrf token validation successfully, then it proceeds to validate each form input data required to be validated. This is done through a Model class. The Model class not only enables us to authenticate form data but it also allows us to save the data into the database. Other features of this class include input-column mapping which allows the form input name to properly select its relative database column field where the data is expected to be inserted. Consider the following Model class structure:
  <?php 

  namespace spoova\mi\windows\Models;
  
  use spoova\mi\core\classes\Model;
  
  class Signup extends Model {
  
      protected $firstname;
      protected $lastname;
      protected $usermail;
      protected $password;

      public function __construct(){
  
          //your code here...
  
      }
  
      /**
       * Validation rules
       *
       * @return array
       */
      public function rules(): array {
  
          return [
              'firstname' => [SELF::RULE_REQUIRED, SELF::RULE_MIN => 2, SELF::RULE_MAX => 20],
              'lastname'  => [SELF::RULE_REQUIRED, SELF::RULE_MIN => 2, SELF::RULE_MAX => 20],
              'usermail'  => [SELF::RULE_REQUIRED, SELF::RULE_EMAIL]
              'password'  => [SELF::RULE_REQUIRED, SELF::RULE_MIN => 2]
          ];
  
      }
  
      /**
       * Determines if a form authentication is completed 
       *
       * @return bool
       */
      public static function isAuthenticated(): bool {
  
          return true; //some validation test code is expected here.
  
      }  

      /**
       * set table name where data is inserted
       *
       * @return string
       */
      public static function tablename(): string {
  
          return 'users'; //default table name

      }

      /**
       * input field names mapped with relative database column name 
       *
       * @return string
       */
      public static function mapform(): array {
  
          return [
              'usermail' => 'email',
              'password' => 'pass'
          ];
  
      }
  
  }
    

The code above simulates a Signup model format that validates a firstname, lastname, usermail and password form field. When a form request data is expected to be authenticated, each request data attribute expected to be authenticated must be added as a property into the Model defined. This makes it easier for the Model class to pull out only needed data from the request data. The following list explains each method and their functions

  • The rules() method defines the authentication needed for each field. The Model class ensures that only defined authentication rules are applied on the relative property defined.
  • The mapform() maps the input field names with their respective field names. For example, in the Model above, the request data attribute name of "usermail" will be mapped to "email" field in database. This means that if the input field name sent in request is "usermail", when inserting data, the data will be inserted into the "email" field in the database table. This makes it easier to protect database names.
  • The tableName() method is used to set a database table name where authenticated data is expected to be inserted.
  • The isAuthenticated() method by default only returns true if all authentication rules applied to a form request are successfully passed and no error was found. Redefining this method above in Signup provides an enviroment to apply more custom rules we require our form data to match. For example, if all authentication rules applied was met by a request data, then the root Model::isAuthenticated() method will return true which means that Signup::isAuthenticated() will also return true by default. However, if more tests are done within the child Signup::isAuthenticated() above and the test fails, then Signup::isAuthenticated() will return false. Note that in Form class, when Form::isValidated() is called, it automatically calls the Signup::isAuthenticated() method. This process is explained below


Data Processing
The Form class is used for further processing and submission request data after csrf validation. This class performs its internal validation using the instance of a Model class. Once the Model class is validated, then data can be submitted into the database table defined. The sample of this is shown below:

  <?php
    
    use spoova\mi\core\classes\Request;
    use Form;

    $Request = new Request;

    if($Request->has('submit')){

        $Request->strict();
        $Request->expires(30);

        Form::model(new Signup);

        Form::loadData($Request->data());

        (Form::isValidated() && Form::isSaved());

    }

    $errors = Form::errors($inputErrors);
    
    
In few lines above we've been able to perform several operations such as checking for button submission, restricting invalid forms, validating form data and saving the data into database. This operation is explained in steps below

  • $Request->has('submit'): This checks if the request data forwarded has a "submit" key
  • $Request->strict(): This ensures that an error page is shown if csrf token is rejected
  • $Request->expires(30): This ensures the csrf token generated can only be valid for 30 second
  • Form::model(new Signup): Sets up a model class used for form data authentication
  • Form::loadData($Request->data()): Sets data to validated by the form and the supplied model
  • Form::isValidated(): By default, this calls the Signup::isAuthenticated() method to check if data is valid
  • Form::isSaved(): This method saves data into the database.
  • Form::errors(): This returns all errors encountered during data validation including those related with csrf token. When a variable is supplied, only errors relating to form inputs will be saved into the variable.

The Signup model defines the database table and columns the validated data is inserted in the database. In the above, the request data returned by $Request->data() is loaded directly into the Form class using Form::loadData() method. The Form::isValidated() will validate each property using their respective keys defined within the model's rule() method and return true by default. If more custom tests are done within the supplied model's isAuthenticated() method, this will further determine if the Form::isAuthenticated() will return a true or false value. Lastly, the Form::isSaved() will try to save the data the database table "users" defined within the tableName() method of Signup model. When an error occurs in the execution of these process, we can obtain the all errors using the Form::errors() method which allows us to fetch all required errors depending on the stage where the error occurred. This method also makes it easier to fetch only errors that occur in input validation by supplying a variable e.g $inputErrors, which acts as reference for errors that occurs for a property when its specified validation rule is not passed. To obtain the entire errors, the Form::errors() method returns the entire error that occured which may be from database connection, operation or input validation.

Lastly, since the Form::isAuthenticated() can naturally call the model's isAuthenticated() method, we can easily add the Form::isSaved() into the current model's isAuthenticated() method. Hence, The code line (Form::isValidated() && Form::isSaved()) can both be replaced with a single Form::isAuthenticated(). The Signup model's isAuthenticated() method will resemble the format below:

   /**
    * Determines if a form authentication is completed 
    *
    * @return bool
    */
    public static function isAuthenticated(): bool {

        return Form::isSaved(); //save and return true of data is saved

    } 
                                    
The code line that manages the request will resemble the format below:
  <?php
    
    use spoova\mi\core\classes\Request;
    use Form;

    $Request = new Request;

    if($Request->has('submit')){

        $Request->strict();
        $Request->expires(30);

        Form::model(new Signup);

        Form::loadData($Request->data());

        if(Form::isAuthenticated()) {
            
            if(Form::errors()) var_dump(Form::errors);

        }
    }

    $errors = Form::errors($inputErrors);
    
    
Some other useful and important form methods are listed and discussed below:

Form::datakey()
This method is used to retrieve a form data key from the Form class after the Form::loadData() has been used to load a request data.
Syntax: datakey()
  Form::datakey($key)
    
    where $key: a key in the request form data
                                            

Form::dataval() v2.5+
This method is similar to Form::datakey() method. as it returns the value of a key in database but it can also be made to throw an error if the specified key does not exist.
Syntax: dataval()
  Form::dataval($key, $strict)
    
    where:
    
      $key    : a key in the request form data
      $strict : when set as true throws an error if key does not exist.
    
                                            

Form::loadedData() v2.5+
This method returns the data supplied into the Form::loadData() method. It takes no argument and returns an array.
Sample: loadedData()
  Form::loadData(['name' => 'foo']);

  prnt_r( Form::loadedData() ); // ['name' => 'foo'] 
                                            

Form::haskey() v2.5+
This method is similar to Request::has() method. The only difference is that the Form::haskey() method check the key from the loaded form data.
Sample: haskey()
  Form::loadData(['name' => 'foo']);

  vdump( Form::haskey('name') ); // true 
                                            

Form::onpost() v2.5+
This method is used to run a callback function only when the forwarded request method is post.
Sample 1: onpost()
  Form::onpost(function(){

    echo "request is post";

  });
                                            
In the code above, the callback function will only run when the request is post. We can also ensure that the callback function runs only when a request key exists in the form request that is sent. This is done by specifying the required request key as shown below:
Sample 2: onpost()
  Form::onpost('login', function(){

    echo "request is post";

  });
                                            
In the code sample above, the callback function will be called only if the "login" key exists in the request key forwarded. This option can also be good when testing for submission buttons. It is however important the the Request class must not be set as strict before this method is used.

Form::register() v2.5+
The version 2.5 introduces a new method for registering a session which is Form::register() method. The syntax of this method is displayed below:
  Form::register($userid_key, $callback);
  
    where:
     
     $userid_key : user id key in request data

     $callback    : callback function
  
                                
When the Form::register() method is used, the first argument $userid_key that is expected to be supplied is usually a key in the form request data that corresponds to the configured database USER_ID_FIELDNAME. For example, if the database table column where the userid is stored is email, then the $userid_key should also be email and it should exist as a key in the form request data. Since the mapform() method can hide database field names, it does not necessarily mean that the form input field should have the "email" field, we just have to specify the input field which is a placeholder for the real userid column in the user database table. Assuming we have a signup form as shown below
    <form method="post">

        @csrf <!--apply csrf-->
    
        <div> @error(':mod', 'signup-failed') </div> 
        <div> @error('firstname') </div> 
        <div> <input name="firstname"> <br> </div> 

        <div> @error('lastname') </div>       
        <div> <input name="lastname"> <br> </div> 

        <div> @error('usermail')  </div>          
        <div> <input type="email" name="usermail"> <br> </div> 

        <div> @error('userpass') </div> 
        <div> <input type="password" name="userpass"> <br> </div> 

        <div> <button name="signup">button<button> </div> 
    
    </form>
                                
Assuming that the usermail field corresponds to the database column "email" where the collected input will be inserted in the predefined user database table, we can continue to create our form authentication model as shown below
    <?php 

    namespace spoova\mi\windows\Models;

    class SignupModel {

        function rules(): array {

            //set form validation rules

            return [
                
             'firstname' => [SELF::RULE_REQUIRED, SELF::RULE_MIN => 2],   
             'lastname'  => [SELF::RULE_REQUIRED, SELF::RULE_MIN => 2],   
             'usermail'  => [SELF::RULE_REQUIRED, SELF::RULE_EMAIL],   
             'userpass'  => [SELF::RULE_REQUIRED, SELF::RULE_MIN => 8],   
                
            ];

        }

        static function mapform() : array {

            return [
                'usermail' => 'email' //set the usermail field in form data back to email
            ];

        }

        static function tablename() {
            return "users";
        }

        static function isAuthenticated() : bool {

            return self::isSaved(); //try to save data into database

        }

    }
                                
In the above, we successfully set some validation rules which are meant to be used to authenticate the form data. However, notice that the usermail field was internally renamed back to email which is expected to be where the data is inserted in the database table "users". Since we intend to use the "usermail" field's value as the userid, we can set up the form authentication frame as shown below:
    <?php 

    namespace spoova\mi\windows\Frames\AccessFrame;

    class AccessFrame extends Windows{

        static function onSubmit($Request Request) {

            if($Request->isPost()) {

                Form::model(new SignupModel); 
                
                if(Form::haskey('signup')) {

                    Form::loadData($Request->data());

                    Form::register('usermail', function($data){

                        if($data !== false) {

                            // form saved successfully 
                            User::login($data);

                        }else{

                            // set error that something is wrong ... 

                            Form::setError('signup-failed', 'signup failed due to some error');

                        }

                    })

                }

            }

        }

    }
                                
In the sample above, the AccessFrame will be used as a middleware to validate the form data. In the above, the Form::haskey('signup') checks that a the request data has a signup key equivalent to the signup button. The Form::loadData() is used to load the request form data into the Form class for authentication. Lastly, the Form::register assumes that the "usermail" key in request data contains the value intended to be used for userid. The callback function will return the userid data if the form is successfully authenticated and saved. This array data can then be used to login (i.e. create the user's new session). In order to apply this middleware, we can use any shutter method in our route but we need to declare a session first which can be used for logging in. Let's create a new root session frame below:
    <?php 

    namespace spoova\mi\windows\Frames; 

    use Window;

    class SessionFrame extends Window {

        static function frame() {

            new Session('user', 'usercookie');

        }

    }
                                
We also need to create a session for the signup route as shown below
    <?php 

    namespace spoova\mi\windows\sessions; 

    use spoova\mi\windows\Frames\SessionFrame;

    class GuestSession extends SessionFrame {

        static function frame() {

            Session::auto('login', 'home'); redirect after the session becomes active

        }

    }
                                
The session created above will be linked to the Signup route. You can learn more about sessions from sessions page. The GuestSession above will be used for all guest pages that requires the use of session auto redirection. Now, we can proceed to create the Signup route as shown below:
                                
    <?php
    
    namespace spoova\mi\windows\Routes;

    use spoova\mi\windows\sessions;

    class Signup extends GuestSession {

        function __construct() {

            self::call($this, [ window() => 'root' ]);

        }

        function root() {

            Accessframe::onSubmit(); // apply middleware

            self::load('signup', fn() => compile() ); // load template

        }

    }
                                
Model Form Rules
There are several rules that can be applied for form input validation in a model class rules() method. Once these rules are defined within a Model, the model uses such rules to validate form inputs based on their attributes. The following rules can be applied on form inputs:

  RULE_REQUIRED  // Defines an attribute that must be filled
  
  RULE_NOSPACE  // Defines an attribute that cannot contain spaces
  
  RULE_TEXT  // Defines an attribute that can only contain alphabets
  
  RULE_MIN  // Sets a minimum length of characters accepted on a form input
  
  RULE_MAX  // Sets a maximun length of characters accepted on a form input
  
  RULE_UNIQUE  // Sets an attribute that must not exist more than once in the database
  
  RULE_MATCHES  // Sets an attribute that must match another attribute and must not be empty

  RULE_ISOLATE  // Sets an attribute that cannot be closely matched by any other attribute's value
  
  RULE_EMAIL  // Defines an attribute and must be of email format
  
  RULE_NOT  // Defines an attribute that must not be exactly the same as another form attribute(s) value(s)
  
  RULE_UNLIKE  // Defines an attribute that must not look like another attribute(s) whose names must be set
  
  RULE_NUMBER  // Defines an attribute that must be numeric
  
  RULE_INTEGER  // Defines an attribute that must be a valid integer

  RULE_PHONE  // Defines an attribute that must have a phone numer format
  
  RULE_URL  // Defines an attribute that must have a url address format
  
  RULE_RANGE  // Defines an attribute that must have its value within a specified range or list only 

  RULE_NOT_CHARS  // Defines an attribute that must not have a character exisiting in a list of defined characters that is set       

A sample rule returned by a model is shown below
    ... 

    public function rules(): array {

      return  [

        'field1' => [
             
            SELF::RULE_REQUIRED,    // field is required

            SELF::RULE_NOSPACE,     // allow no space character

            SELF::RULE_TEXT,        // allow only alphabets [A-Z]

            SELF::RULE_MIN => '10', // allow only a minimum of 10 characters

            SELF::RULE_MAX => '12', // allow only a maximum of 12 characters

            SELF::RULE_UNIQUE,      // value must not exist more than once in database

            SELF::RULE_EMAIL,       //value must resemble email format

            SELF::RULE_PHONE,       //value must resemble phone number format

            SELF::RULE_NUMBER       //value must be a numeric value

            SELF::RULE_URL          //value should be a url format

            SELF::RULE_MATCH => 'field2', // field1 value must match field2 value

            SELF::RULE_UNLIKE  => ['field3', 'field4'], // field1 must not resemble field3 and field4
            
            SELF::RULE_NOT_CHARS  => ['*', ':'], // value must not contain character * and :
            
            SELF::RULE_RANGE  => ['yes', 'no'], // value must be within the range of options yes or no
            
            SELF::RULE_PATTERN  => "A-Za-z0-9", // value must match the specified pattern
                
                ]

      ];

    }
                                

Managing Errors
Errors management include error modification through custom ways and error fetching. Errors returned by the Form class are classified into four forms:
  • CSRF errors
  • Input errors
  • Database errors
  • Custom errors
The last type of error is defined through a flash message:
  • User id error notice
CSRF Errors
Csrf errors are errors that are returned when a token is not valid. These errors are returned by the Form::errors() into an array key specified as :csrf which contains only two subkeys title and info which contains the type of error and the description of that error respectively. The title and info returned is determined by the kind of error that occured. Under this subheading, errors are classified as default, invalid and session. When a token is missing, a default error is returned. When a token does not match an invalid error is returned while the session error only returnes when a token has expired. In order to access the :csrf errors, an helper function error() makes this easy shown below:
    <?php
    
    error(':csrf', 'title'); // return the csrf last error title 
    error(':csrf', 'info');  // return the csrf last error info 
    
    
Remember that error displayed are determined on the type of error that occured. Also, the error returned for each type can be customized as revealed below:

    <?php
    
    use spoova\mi\core\classes\Request;
    use Form;
    use Csrf;

    $Request = new Request;

    if($Request->has('submit')){

        Csrf::setError('default', 'csrf request failed');   // set custom message
        Csrf::setError('invalid', 'csrf token mismatched'); // set custom message
        Csrf::setError('session', 'csrf session expired');  // set custom message

        Csrf::setError('default', ['title' => 'some title', 'info' => 'some info']);// set custom title and info using array

        $Request->strict()->expires(5);

        Form::loadData($Request->data());

        (Form::isValidated() && Form::isSaved());

    }

    $errors = Form::errors();      //return all validation errors 

    print_r( $errors[':csrf'] );     // return only csrf last error (both title and info) 
    print_r( error(':csrf') );      // same as above 

    print error(':csrf', 'title'); // return only csrf last error title 
    print error(':csrf', 'info');  // return only csrf last error info 
    
    
In the above, the Csrf::setError() is used to set a custom modified message. It stores its keys and value into a ":mod" space where the values can be retrieved later. Once a key and a message value is defined, we can access the custom message through its key. For example, error(':mod','invalid') will return a message of "csrf token mismatched". The second argument of Csrf::setError() sets a custom error message. Also, The error() helper function by default has internal access to Form::errors() method which usually returns the error encountered after a form validation fails. Rather than use a variable to obtain the form errors, we can easily use the error() helper function to pull the error specific error from the Form::errors(). The errors accessible by the error() function are discussed below:

Input Errors
Input errors occurs when form input validation fails. These errors are also stored within the form errors and can be accessed using the relative attribute's name. The error() helper function only returns the first error encountered by each attribute, that is , the topmost error index. An example of this is shown below:
    <?php
    
    error('username'); // return first error encountered for a username field 
    
    
The equivalent of the error() function is the @error() template directive. When no errors exists for the defined attribute error() function just returns empty without throwing any errors.

Database Errors
Database errors occurs when database operation fails due to one reason or the other. This could prevent saving of data into database. The Form::error() also allows fetching of these errors using reserved key names such as :dbi, :dbe and :dbm The named keys can be supplied into error() to obtain their respective values.
    <?php
    
    error(':dbm'); // something is wrong 
    error(':dbe'); // database error: something is wrong 
    error(':dbi'); // sql error (fully stated according to type of error) 
    
    
The :dbi is the only key that displays the full information about the type of database error that occurred. Other keys are just a shorthened form of message to keep the message simple and easy to read. In template engines, the @error() directive can be used to obtain these errors.

Custom Errors
Custom errors are errors that are defined using the Form::setError() method. This method stores the last defined error into an array key ":mod". Hence, by calling the error(':mod') function, we can retrieve the last defined error. Example is shown below:
    <?php
    
    Form::setError('something is wrong');

    echo error(':mod'); // something is wrong 
    
    
    Form::setError('name', 'foo');

    echo error(':mod', 'name'); // foo 
    
The sample above best explains how the error() function can access a message defined by Form::setError(). It is mostly important that the value returned by the error() function is a string rather than an array for an easy access through template files.

Session user id error notice
The Session class security system ensures that a fake user id is not authenticated. In the core/init file, we configured the user table along with user id field (or column) name . Assuming a user session id was roughly set which does not exist in the column "USER_ID_FIELDNAME" of the "USER_TABLE_NAME" defined, such an invalid id will be nullified. This means that if the user id detected does not exist in the configured column, then even if a session id is faked, because that id does not exist in the database, such session will automatically be rejected. This behaviour only works under a secured session defined by setting the third argument of Session class to the value of true during initialization. Once a session is nullified, a flash message is usually stored with the reserved key ":user-error". This means that if we call the function flash(':user-error') immediately the session is nullified, we will get a response of User error: user id mismatch . This makes it easier to understand why a session was nullified even if a session id was supplied.

Improvements on retrieving errors v2.5+
In version 2.5, a new way has been added to make it easier to fetch errors through a formerror() function. This function was introduced to separate error encountered where there are multiple forms on a page which may result in conflicting errors most especially when a form may have an input field with a name that that exists in another form's input field. An example is shown below:
    <form method="post" class="form1">
        <input name="email" >
        <input name="password" >
        <button name="login">Login</button>
    </form>

    <form method="post" class="form2">
        <input name="firstname" >
        <input name="lastname" >
        <input name="email" >
        <input name="password" >
        <button name="login">Signup</button>
    </form>
                                    
In the sample html above, both of the forms have an email and password field. This can result in conflicting error message because the Form::error() method is not aware of the form whose error is returned. With can however, specify the field whose error is returned through a new method Form::castError(). This new method takes an error key which is used to store the error. Once the error is stored, we can then obtain the error back through the use of Form::castedError() method, formerror() helper function or the @formerror() template directive. In order to fetch a particular error, the cast name must first be supplied into as first argument of the formerror() function This is shown below:
    <?php
    
    use spoova\mi\core\classes\Request;
    use Form;
    use Csrf;

    $Request = new Request;

    if($Request->isPost()){

        if($Request->has('submit')){

            Form::model(new SomeModel); // add a model to be used for authentication

            Form::loadData($Request->data());

            if(!Form::isValidated()){

                if($Request->has('login')){

                    // if login button was clicked

                    Form::castError('login');

                    print_r(formerror('login')) // return errors stored in login

                }else{

                    Form::castError('signup');
                    
                    print_r(formerror('signup')) // return errors stored in signup
                    
                }

                

            }

        }

    }
                                
In the sample above, although, the Form::error() has no idea of the form which error is returned, we took the advantage of the form buttons to cast the errors into their own unique space which can then be accessed through formerror('login') or formerror('signup'), depending on the unique name used for storing the data. Aside from the form input errors The Form::castError() stores other special error in a slightly different way through the use of special access keys. These keys include flash:, csrf:, index:, any: and mod:. These keys are explained below with the assumption that castname key is used to store each data.

formerror('castname', 'flash:')
The flash: key is used to obtain flash notices. In most cases, it is used to obtain the :user-error message returned when a session id is nullified. For example, the formerror('flash:user-error') is equivalent to flash(':user-error') Other flash errors can be obtained by first calling the flash: access key identifier followed by the key of the flash name. An example is shown below:
    <?php

    if(!Res::hasFlash('flash_name')){

        Res::setFlash('flash_name', 'flash message');

    } else {

        echo formerror('castname','flash:flash_name'); // flash message
    }
    
                                    
The example above uses the formerror() function to print the flash message. This is similarly done in template files through the use of @formerror('castname','flash:flash_name').

formerror('castname', 'csrf:')
The csrf: key is used to obtain errors that may occur when a form that does not have csrf token is submitted. The formerror('castname','csrf:title') is equivalent to error(':csrf', 'title') while the formerror('castname','csrf:info') is similary equivalent to the error(':csrf', 'info'). We can also use the relative template directive to fetch the value of such errors.

formerror('castname', 'mod:')
The mod: key is used to obtain custom errors defined by the Form::setError() method just like the error(':mod') helper function. A sample of this is shown below
    <?php

    Form::setError('name', 'foo');

    echo formerror('castname', ':mod', 'name'); // foo
                                    

formerror('castname', 'index:')
The index: key is used to obtain the first error encountered in a form validation. This is mostly dependent on the request data sent. The first error encountered from the the list input fields data is returned after input authentication. In most cases, this is useful at the topmost part of a form field in template files.

formerror('castname', 'any:')
The any: key is similar to the index: key. The only difference is that when this key is used, errors returned will include all errors from flash notices, csrf token validation, custom errors and any input validation error. The first error encountered is usually returned. This key is also useful at the top of the form field. Any error encountered after the form is