Prebuilt Forms
Flick includes 4 ready-to-use form templates for common scenarios. These forms come with fields, validation rules, and custom error messages already configured.
Quick Reference
| Form | Fields | Description |
|---|---|---|
/login |
username, password | Basic login form |
/shortContact |
name, email, body | Simple contact form |
/registration |
username, email, password, password-confirm, agree | User registration with password confirmation |
/example |
20+ fields | Comprehensive demo of all field types |
Usage
Loading a Prebuilt Form
Pass the form path to the create() method:
$form = new Flick\Flick(); echo $form->create('/login');
Overriding Attributes
You can override any form attribute by passing an array as the second parameter:
echo $form->create('/login', [ 'action' => '/auth/login', 'button' => 'Sign In', 'id' => 'my-login-form' ]);
Only the keys you name change; everything else comes from the form file.
Tip
Copying the file into your own assets/forms/ directory is the cleaner option when
you always want the same changes. See Customize.
Handling Submissions
Use the request() method to retrieve and validate form data:
if ($form->submitted()) { $data = $form->request('/login'); if ($form->ok()) { // Validation passed. File-loaded forms return a list of one-key arrays, // so flatten it before reaching in by name. $data = array_merge(...$data); $username = $data['username']; $password = $data['password']; } else { // Validation failed $errors = $form->getErrors(); // ['username' => 'Please enter your username', ...] } }
Warning
Check $form->ok(), not $data. request('/login') returns an array either way —
it's populated with whatever was posted even when validation failed, so a truthy
$data tells you nothing about validity.
Use getErrors() to read the error bag. errors() is a different method: it
prints an alert box and returns nothing.
Form id and submitted()
Each prebuilt form file sets its own form id (form-login, form-contact,
form-registration, form-example), and submitted() only returns true when
the posted _id matches the instance's current id. Calling create('/login')
updates the instance id, so either call create() before you check
submitted(), or pass the form's id in the config
(new Flick\Flick(['id' => 'form-login'])) when you handle the submission first.
With neither, submitted() stays false and the handler never runs.
Login Form (/login)
A simple two-field login form.
echo $form->create('/login');
Fields
| Field | Type | Validation | Error Message |
|---|---|---|---|
username |
text | required | "Please enter your username" |
password |
password | required | "Please enter your password" |
Form Attributes
| Attribute | Value |
|---|---|
| ID | form-login |
| Method | POST |
| Button | "Login" |
Full Definition
[
'action' => '/',
'method' => 'POST',
'attributes' => [
'id' => 'form-login'
],
'button' => [
'text' => 'Login'
],
'fields' => [
'username' => [
'type' => 'text',
'name' => 'username',
'label' => 'Username',
'rules' => ['required'],
'messages' => [
'required' => 'Please enter your username',
]
],
'password' => [
'type' => 'password',
'name' => 'password',
'label' => 'Password',
'rules' => ['required'],
'messages' => [
'required' => 'Please enter your password'
]
]
]
]
Common Customizations
Change the action and button text:
echo $form->create('/login', [ 'action' => '/auth/signin', 'button' => 'Sign In' ]);
Add a "Remember Me" checkbox:
You'll need to create a custom form or use field elements to add additional fields.
Contact Form (/shortContact)
A simple 3-field contact form with email validation.
echo $form->create('/shortContact');
Fields
| Field | Type | Validation | Error Message |
|---|---|---|---|
name |
text | required, min:5 | "Please enter your name" |
email |
required, email | "Please enter your email address" / "Please enter a valid email address" | |
body |
textarea | required | "Please enter your message" |
Form Attributes
| Attribute | Value |
|---|---|
| ID | form-contact |
| Method | POST |
| Button | "Submit form" |
Full Definition
[
'action' => '/',
'method' => 'POST',
'attributes' => [
'id' => 'form-contact'
],
'button' => [
'text' => 'Submit form'
],
'fields' => [
'name' => [
'name' => 'name',
'label' => 'Name',
'rules' => ['required', 'min:5'],
'messages' => [
'required' => 'Please enter your name',
]
],
'email' => [
'type' => 'email',
'name' => 'email',
'label' => 'Email',
'rules' => ['required', 'email'],
'messages' => [
'required' => 'Please enter your email address',
'email' => 'Please enter a valid email address'
]
],
'body' => [
'type' => 'textarea',
'name' => 'body',
'label' => 'Message',
'rules' => ['required'],
'messages' => [
'required' => 'Please enter your message',
]
],
]
]
Complete Example with Email
$form = new Flick\Flick([ // form files carry their own id ('form-contact' here); set it in the config // so submitted() recognizes the POST before create() has run 'id' => 'form-contact', 'services' => [ 'mail' => [ 'fromAddress' => 'noreply@example.com', 'mailer' => [ 'transport' => 'smtp', 'host' => 'smtp.example.com', 'port' => 587, 'encryption' => 'tls', 'username' => 'user@example.com', 'password' => 'secret' ] ] ] ]); // Handle submission first if ($form->submitted()) { // a list of one-key arrays, so flatten it before sending $data = array_merge(...$form->request('/shortContact')); if ($form->ok()) { $sent = $form->mail->sendFormData( 'admin@example.com', 'New Contact Form Submission', $data ); if ($sent) { $form->successMessage('Thank you for your message!'); } else { $form->errorMessage('Sorry, your message could not be sent.'); } } } // Create the form $form->create('/shortContact', ['action' => '/contact']);
Registration Form (/registration)
A complete user registration form with password confirmation and terms agreement.
echo $form->create('/registration');
Fields
| Field | Type | Validation | Error Message |
|---|---|---|---|
username |
text | required, min:3, max:20, slug | Various |
email |
required, email | "Please enter your email address" / "Please enter a valid email address" | |
password |
password | required, min:8, hash | "Please enter a password" / "Your password must be at least 8 characters" |
password-confirm |
password | required, matches:password | "Please confirm your password" / "Your passwords do not match" |
agree |
checkbox | required | "You must agree to the Terms" |
Form Attributes
| Attribute | Value |
|---|---|
| ID | form-registration |
| Method | POST |
| Button | "Sign Up" |
Full Definition
[
'action' => '/',
'method' => 'POST',
'attributes' => [
'id' => 'form-registration'
],
'button' => [
'text' => 'Sign Up'
],
'fields' => [
'username' => [
'type' => 'text',
'name' => 'username',
'label' => 'Username',
'rules' => ['required', 'min:3', 'max:20', 'slug'],
'messages' => [
'required' => 'Please enter a username',
'min' => 'Username must be at least 3 characters',
'max' => 'Username cannot be more than 20 characters'
]
],
'email' => [
'type' => 'email',
'name' => 'email',
'label' => 'Email',
'rules' => ['required', 'email'],
'messages' => [
'required' => 'Please enter your email address',
'email' => 'Please enter a valid email address'
]
],
'password' => [
'type' => 'password',
'name' => 'password',
'label' => 'Password',
'rules' => ['required', 'min:8', 'hash'],
'messages' => [
'required' => 'Please enter a password',
'min' => 'Your password must be at least 8 characters'
]
],
'confirm' => [
'type' => 'password',
'name' => 'password-confirm',
'label' => 'Confirm Password',
'rules' => ['required', 'matches:password'],
'messages' => [
'required' => 'Please confirm your password',
'matches' => 'Your passwords do not match'
]
],
'agree' => [
'type' => 'checkbox',
'name' => 'agree',
'label' => 'I agree to the Terms',
'value' => '1',
'rules' => ['required'],
'messages' => ['required' => 'You must agree to the Terms']
]
]
]
Important Notes
Password Hashing
The hash rule automatically hashes the password using PHP's password_hash() function. When you retrieve the form data, the password will already be hashed and ready to store in your database.
Slug Conversion
slug is a modifier, not a validation rule — it doesn't reject anything, it rewrites
the value. Spaces and hyphens become underscores, accented letters are transliterated
to ASCII (é → e), and anything else that isn't a letter, digit, or underscore is
dropped. Gern Blanston! is stored as Gern_Blanston. That keeps the username safe
for URLs and database queries, but the value you save is not always the value the
user typed.
Complete Example
$form = new Flick\Flick(); echo $form->create('/registration', ['action' => '/register']); if ($form->submitted()) { // a list of one-key arrays, so flatten it before reading fields by name $data = array_merge(...$form->request('/registration')); if ($form->ok()) { // $data['password'] is already hashed by the `hash` modifier $form->sql->save('users', [ 'username' => $data['username'], 'email' => $data['email'], 'password' => $data['password'] ]); echo 'Registration successful!'; } }
Tip
The confirmation field is named password-confirm with a hyphen, so it arrives as
$data['password-confirm'].
Example Form (/example)
A comprehensive form demonstrating all field types and features. Useful for testing and learning.
echo $form->create('/example');
Form Attributes
| Attribute | Value |
|---|---|
| ID | form-example |
| Method | POST |
| Multipart | Yes (for file uploads) |
| Class | needs-validation |
| Button | "Submit Me" (with btn-lg class) |
Field Inventory
This form includes the following field types:
Text Inputs:
text- Basic text input with help textemail- Email inputpassword- Password inputpassword-confirm- Password confirmation
Other Inputs:
textarea- Multi-line textnumber- Numeric inputtel- Telephone numberurl- URL inputdate- Date pickertime- Time pickercolor- Color pickerweek- Week pickermonth- Month pickerrange- Range slider (0-100)
File Uploads (in fieldset):
photo- Single file upload (image only)photos[]- Multiple file upload (images only)
Select Menus (in fieldset):
state- Uses prebuiltstatesdropdownfoobarBaz- Custom inline optionsfruit[]- Multiple select
Radio & Checkbox (in fieldset):
radio- Radio button groupradio-inline- Inline radio buttonsagree- Single checkbox
Full Definition
[
'action' => '/',
'method' => 'POST',
'attributes' => [
'id' => 'form-example',
'multipart' => true,
'class' => 'needs-validation',
'string' => 'novalidate'
],
'button' => [
'text' => 'Submit Me',
'attributes' => [
'class' => 'btn-lg'
]
],
'fields' => [
// ... (see source file for complete definition)
]
]
Using as a Learning Tool
The example form is a great way to see how different field types work:
// Render the form to see all field types echo $form->create('/example'); // Inspect the submitted data if ($form->submitted()) { $data = $form->request('/example'); var_dump($data); // a list of one-key arrays var_dump(array_merge(...$data)); // flattened into name => value }
The example form includes file-upload fields, so submitting it requires the Upload
service to be configured with a directory — add
'services' => ['upload' => ['directory' => 'uploads']] to your config, or
submitting will throw a "please specify an upload directory" exception.
Tip
You can find the complete form definition in vendor/flickphp/flick/lang/en/forms/example.php or view it in the GitHub repository.
Creating Custom Forms
Need a form that isn't included? You have two options:
- Create a custom form file - See the Customize documentation
- Build forms with field elements - See Creating Forms
Custom Form File Structure
Create a PHP file that returns an array:
// myFlickAssets/forms/myForm.php return [ 'action' => '/submit', 'method' => 'POST', 'attributes' => [ 'id' => 'my-custom-form' ], 'button' => [ 'text' => 'Submit' ], 'fields' => [ 'field_name' => [ 'type' => 'text', 'label' => 'Field Label', 'rules' => ['required'], 'messages' => [ 'required' => 'This field is required' ] ] ] ];
Then load it with:
echo $form->create('/myForm');