Form Validation Introduction
In Trongate v2, form validation is handled by the validation module located at modules/validation/. The Trongate v2 validation module delivers enterprise-grade validation with zero configuration - handling everything from simple required fields to complex custom validation rules, complete with automatic CSRF protection and effortless multilingual support.
How It Works: The Three-Step Pattern
Every validation instance follows the same simple pattern:
- Set rules - Define what each field must satisfy
- Run validation tests - Check submitted data against your rules
- Handle the result - Display errors or process valid data
// 1. SET RULES
$this->validation->set_rules('username', 'username', 'required|min_length[3]|max_length[30]');
$this->validation->set_rules('email_address', 'email address', 'required|valid_email');
// 2. RUN VALIDATION
$result = $this->validation->run();
// 3. HANDLE RESULT
if ($result === true) {
// Validation passed - fetch posted data, save and redirect
$data = [
'username' => post('username', true),
'email_address' => post('email_address', true)
];
$this->db->insert($data, 'members');
redirect('members/manage');
} else {
// Validation failed - redisplay form with errors
$this->create();
}Displaying Errors: Three Scenarios
Trongate provides three distinct ways to display validation errors. The helper function plays a pivotal role by automatically selecting the appropriate output format based on its first argument.
| Scenario | How to Invoke | Best For | Clears Session? |
|---|---|---|---|
| General Errors | validation_errors() |
Simple forms, login pages, admin panels | Yes - all errors |
| Inline Errors | validation_errors('field_name') |
Long forms, multi-step forms, better UX | No - allows multiple field calls |
| JSON Response | validation_errors(422) |
API endpoints, AJAX forms, mobile apps | Yes + exits script |
How the helper decides: Pass nothing for general errors, a field name string for inline errors, or an HTTP status code (400-499) for JSON. The helper handles the rest automatically.
Scenario 1: General Errors
Display all errors at once, typically at the top of your form:
<h1>Create Account</h1>
<?= validation_errors() ?>
<?php
echo form_open('users/submit');
echo form_label('Email');
echo form_input('email', $email);
echo form_label('Password');
echo form_password('password');
echo form_submit('submit', 'Register');
echo form_close();
?>Scenario 2: Inline Errors
Display errors next to specific fields for better user experience:
<?php
echo form_open('users/submit');
echo form_label('Full Name');
echo validation_errors('full_name');
echo form_input('full_name', $full_name);
echo form_label('Email');
echo validation_errors('email');
echo form_email('email', $email);
echo form_submit('submit', 'Register');
echo form_close();
?>Pro tip: Inline errors don't clear the entire session. You can call validation_errors('field') for multiple different fields throughout your form.
Scenario 3: JSON Response (APIs)
Return structured JSON for API endpoints or AJAX requests:
public function api_create(): void {
$this->validation->set_rules('email', 'email', 'required|valid_email');
$this->validation->set_rules('name', 'name', 'required|min_length[2]');
if ($this->validation->run() === false) {
validation_errors(422); // Sets HTTP 422, returns JSON, exits
}
// Only executes if validation passed
echo json_encode(['success' => true, 'user_id' => $new_id]);
}JSON output:
[
{
"field": "email",
"messages": ["The email field must contain a valid email address."]
},
{
"field": "name",
"messages": ["The name field must be at least 2 characters long."]
}
]Important: JSON responses terminate script execution with exit(). No code after validation_errors(422) will run.
Setting Validation Rules
Trongate supports two syntax styles for defining rules. Choose the one that fits your needs.
Option 1: Pipe Syntax (Concise)
Ideal for simple forms and quick prototyping:
$this->validation->set_rules('username', 'username', 'required|min_length[3]|max_length[20]');
$this->validation->set_rules('email', 'email address', 'required|valid_email');
$this->validation->set_rules('age', 'age', 'required|integer|greater_than[0]');Option 2: Array Syntax (Organized)
Ideal for complex forms and programmatic rule building:
$rules = [
'username' => [
'label' => 'username',
'required' => true,
'min_length' => 3,
'max_length' => 20
],
'email' => [
'label' => 'email address',
'required' => true,
'valid_email' => true
],
'age' => [
'label' => 'age',
'required' => true,
'integer' => true,
'greater_than' => 0
]
];
$result = $this->validation->run($rules);Common Built-In Rules
| Rule | Description |
|---|---|
required | Field cannot be empty |
min_length[n] | Minimum character length |
max_length[n] | Maximum character length |
valid_email | Valid email format |
numeric | Must be a number |
integer | Must be an integer |
matches[field] | Must match another field (e.g., password confirmation) |
See Validation Rules Reference for the complete list including date/time and file upload rules.
Special Case: Checkbox Validation
Checkboxes behave differently because unchecked boxes submit nothing. An unchecked checkbox returns '' (empty string) from post().
// REQUIRED checkbox - user MUST check it
$this->validation->set_rules('terms', 'terms and conditions', 'required');
// OPTIONAL checkbox - no validation rule needed
// Simply convert the value for database storage
$data['newsletter'] = (int) (bool) post('newsletter', true); // 0 or 1Complete Working Example
Here's a full implementation using the create/update pattern:
class Users extends Trongate {
public function create(): void {
$update_id = segment(3, 'int');
$submit = post('submit');
// Load data from POST (new record or validation error) or DB (editing)
if (($update_id === 0) || ($submit === 'Submit')) {
$data = $this->model->get_data_from_post();
} else {
$data = $this->model->get_data_from_db($update_id);
}
$data['headline'] = ($update_id === 0) ? 'Create User' : 'Update User';
$data['form_location'] = str_replace('/create', '/submit', current_url());
$this->view('create', $data);
}
public function submit(): void {
// Set validation rules
$this->validation->set_rules('username', 'username', 'required|min_length[3]|max_length[20]');
$this->validation->set_rules('email', 'email address', 'required|valid_email');
$this->validation->set_rules('password', 'password', 'required|min_length[8]');
if ($this->validation->run() === true) {
// Success: save and redirect
$data = $this->model->get_data_from_post();
$update_id = segment(3, 'int');
if ($update_id === 0) {
$this->db->insert($data, 'users');
set_flashdata('User created successfully');
} else {
$this->db->update($update_id, $data, 'users');
set_flashdata('User updated successfully');
}
redirect('users/manage');
} else {
// Failure: redisplay form with errors
$this->create();
}
}
}Key Points
- Validation rules are set with and executed with
- Use lowercase field labels for natural error messages: "The email address field is required"
- Always use
post('field', true)to get cleaned, trimmed values - CSRF protection is automatic - every POST form is protected
- Errors survive redirects via session storage
- Optional fields skip validation when empty - only validate what matters
Validation lifecycle: Validation fails → errors stored in session → form redisplays with errors. Validation passes → data saves → flashdata set → redirect to success page.
What's Next
The following pages cover everything you need to master form validation:
- Validation Rules Reference - Complete list of built-in rules
- Custom Validation Rules - Write your own validation logic with callbacks
- Multilingual Validation - Display errors in multiple languages
- Styling Validation Errors - CSS, automatic field highlighting, and UX best practices
We're continually improving the Trongate documentation. If anything is incorrect, unclear, incomplete, or could be better, we'd genuinely appreciate your input.
Share your thoughts in the Documentation Feedback.