flickphp / migrate
Migration tool for converting Formr to Flick.
Fund package maintenance!
Requires
- php: ^8.3
- composer-runtime-api: ^2.0
Requires (Dev)
- laravel/pint: ^1.30
- pestphp/pest: ^4.0|^5.0
README
A CLI tool that automatically converts Formr PHP code to Flick.
When to Use
Use this tool when you have an existing codebase using the Formr library and want to upgrade to Flick. The tool handles:
- Namespace and class name conversions
- 60+ method name mappings
- Validation rule syntax transformation
- Property-to-config migrations
Installation
Install it as a dev dependency in the project you're migrating — the tool only rewrites source files, so it is not needed at runtime:
composer require --dev flickphp/migrate
Usage
# Migrate a single file ./vendor/bin/migrate-formr /path/to/file.php # Migrate an entire directory (recursive) ./vendor/bin/migrate-formr /path/to/directory # Preview changes without modifying files ./vendor/bin/migrate-formr /path/to/file.php --dry-run
Configuration
There is nothing to configure — the tool is a one-shot CLI. Its behavior is controlled entirely by flags:
| Flag | Description |
|---|---|
--dry-run, -n |
Preview the changes without writing any files |
--help, -h |
Show help |
--version, -v |
Show the version |
By default the tool rewrites files in place, writing a sibling *.bak next to each file before overwriting it so a bad run is recoverable. Only files that contain a real Formr class reference are processed; everything else is skipped. The command exits non-zero if any file could not be read or written.
What Gets Converted
Namespaces
Formr\Formr→Flick\Flicknew Formr()→new Flick()new Formr('bootstrap')→new Flick(['views' => 'bootstrap'])
Methods (60+ mappings)
| Formr | Flick |
|---|---|
create_form() |
create() |
form_open() |
open() |
form_close() |
close() |
input_text() |
text() |
input_email() |
email() |
input_password() |
password() |
input_hidden() |
hidden() |
input_checkbox() |
checkbox() |
input_radio() |
radio() |
checkbox_inline() |
checkboxInline() |
radio_inline() |
radioInline() |
input_select() |
select() |
error_message() |
errorMessage() |
in_errors() |
hasError() |
submit() |
submitted() (only inside an if/while/elseif condition) |
submit_button() |
submit() |
input_submit() |
submit() (arguments reordered, see below) |
input_button_submit() |
submit() (arguments reordered, see below) |
post() |
request() |
get() |
request() |
validate() |
request() |
send_email() |
$form->mail->send() |
send_html_email() |
$form->mail->send(..., ['html' => ...]) |
textarea()andok()keep the same name in Flick, so they are left unchanged.
Submit buttons move their arguments. Formr's input_submit($name, $label, $value, $id, $string) carries the button text in $value; Flick's
submit($text, $attributes) carries it first. The tool moves it, and passes
$string through as the attributes:
$form->input_submit('submit', '', 'Send', '', 'class="btn"'); // becomes $form->submit('Send', 'class="btn"');
$name, $label and $id have nowhere to go — Flick's submit() renders no
label and hard-codes name="submit" / id="submit" — so anything other than
Formr's own defaults is flagged with a TODO rather than dropped. That includes
the one-argument form: input_submit('Send') sets the name, not the text
(Formr renders a button that still says "Submit"), so it becomes submit()
plus a TODO about the lost name.
submit_button($value) already leads with the text, so it converts straight
across.
Validation Rules
| Formr | Flick |
|---|---|
required|min[5]|max[50] |
required, min:5, max:50 |
valid_email |
email |
valid_url |
url |
alpha_numeric |
alphaNumeric |
min_length[5] |
min:5 |
max_length[50] |
max:50 |
greater_than[0] |
greaterThan:0 |
less_than[100] |
lessThan:100 |
is_numeric |
numeric |
valid_ip |
ip |
matches[field] |
matches:field |
Inline Validation Syntax
// Formr uses pipes and parentheses $form->validate('Name(required|min[2]), Email(valid_email)'); // Flick uses commas and brackets $form->request('Name[required, min:2], Email[email]');
A single rule converts too —
Email(valid_email)becomesEmail[email]. What the tool will not touch is a parenthesized value it doesn't recognise as rules:Category(electronics)is left alone, because in Flick that syntax means a prebuilt dropdown, and guessing wrong either way breaks the form. Rules are converted, never invented: nothing gains arequiredit didn't have.
What Gets Flagged with TODOs
The tool inserts // TODO: FLICK MIGRATION comments for items requiring manual attention:
Pro-Required Features
Some methods map to Flick Pro services. Mail methods are rewritten; reCAPTCHA calls are only flagged (the method name is kept):
| Formr Method | Result | Notes |
|---|---|---|
send_email($to, $subj, $body) |
$form->mail->send($to, $subj, $body) |
Rewritten; configure the mail service in the constructor |
send_html_email($to, $subj, $html) |
$form->mail->send($to, $subj, '', ['html' => $html]) |
Rewritten; HTML body moved to the options array |
recaptcha_*() |
(name kept) | Not rewritten — flagged with a Pro TODO; convert to $form->recaptcha->scripts()/->passed() by hand |
upload($field) |
$form->file($field) |
Rewritten to the core file() method (no Pro TODO); switch to $form->upload->image() if you want Pro image processing |
Mail service configuration required:
$form = new Flick([ 'services' => [ 'mail' => [ 'fromAddress' => 'noreply@example.com', 'mailer' => [ 'transport' => 'smtp', 'host' => 'smtp.example.com', // ... other options ] ] ] ]);
Validation Rules That Become Modifiers
| Formr Rule | Flick Modifier |
|---|---|
hash |
bcrypt modifier |
sanitize_string |
stripTags modifier |
sanitize_email |
sanitizeEmail modifier |
Properties With No Direct Equivalent
| Property | Migration Notes |
|---|---|
required = '*' |
Use CSS to style required fields |
inline_errors |
Configure in view templates |
custom_validation_messages |
Use per-field messages |
Complete Before/After Examples
Example 1: Contact Form
Before (Formr):
<?php use Formr\Formr; $form = new Formr('bootstrap'); $form->action = '/contact'; $form->method = 'post'; $form->required = '*'; if ($form->submit()) { $name = $form->post('name', 'Name', 'required|min[2]'); $email = $form->post('email', 'Email', 'required|valid_email'); $message = $form->post('message', 'Message', 'required|min[10]'); if ($form->ok()) { $form->send_email('admin@example.com', 'Contact Form', $message); echo 'Thank you for your message!'; } } echo $form->form_open(); echo $form->input_text('name', 'Name'); echo $form->input_email('email', 'Email'); echo $form->textarea('message', 'Message'); echo $form->submit_button('Send'); echo $form->form_close();
After (Flick):
<?php use Flick\Flick; $form = new Flick(['views' => 'bootstrap', 'action' => '/contact', 'services' => [ 'mail' => [ // TODO: FLICK MIGRATION - Update these mail settings for your environment 'fromAddress' => 'noreply@example.com', 'fromName' => 'Your App Name', 'mailer' => [ 'transport' => 'smtp', // smtp, ses, mailgun, sendgrid, postmark, mailjet, mailtrap 'host' => 'localhost', 'port' => 587, 'encryption' => 'tls', 'username' => '', 'password' => '' ] ] ]]); // TODO: FLICK MIGRATION - 'method' has no direct Flick equivalent // $form->method = 'post'; // TODO: FLICK MIGRATION - 'required' has no direct Flick equivalent // $form->required = '*'; if ($form->submitted()) { $name = $form->request('name', 'required, min:2'); $email = $form->request('email', 'required, email'); $message = $form->request('message', 'required, min:10'); if ($form->ok()) { /* TODO: FLICK MIGRATION - Mail service requires configuration in constructor (services.mail) */ $form->mail->send('admin@example.com', 'Contact Form', $message); echo 'Thank you for your message!'; } } echo $form->open(); echo $form->text('name', 'Name'); echo $form->email('email', 'Email'); echo $form->textarea('message', 'Message'); echo $form->submit('Send'); echo $form->close();
Note: The mail config block and the commented-out
method/requiredproperties are injected automatically with TODOs for you to review.
Example 2: Registration Form
Before (Formr):
<?php use Formr\Formr; $form = new Formr(); if ($form->submit()) { $data = $form->validate(' username(required|alpha_numeric|min[3]|max[20]), email(required|valid_email), password(required|min[8]|hash), password_confirm(required|matches[password]) '); if ($form->ok()) { // Save user to database } } echo $form->create_form('Username, Email, Password|password, Confirm Password|password');
After (Flick):
<?php use Flick\Flick; $form = new Flick(); if ($form->submitted()) { $data = $form->request(' username[required, alphaNumeric, min:3, max:20], email[required, email], password[required, min:8, bcrypt], password_confirm[required, matches:password] '); if ($form->ok()) { // Save user to database } } echo $form->create('Username, Email, Password|password, Confirm Password|password');
Example 3: File Upload
Before (Formr):
<?php use Formr\Formr; $form = new Formr(); $form->upload_dir = '/uploads/'; $form->upload_max_filesize = 5000000; $form->upload_accepted_types = 'jpg,png,gif'; if ($form->submit()) { $file = $form->upload('photo'); if ($form->ok()) { echo "File uploaded: " . $file; } }
After (Flick):
<?php use Flick\Flick; $form = new Flick(); // TODO: FLICK MIGRATION - 'upload_accepted_types' is now set per-upload via 'mime' option // TODO: FLICK MIGRATION - Add services.upload config to constructor // $form->upload_dir = '/uploads/'; // TODO: FLICK MIGRATION - Add services.upload config to constructor // $form->upload_max_filesize = 5000000; // TODO: FLICK MIGRATION - 'upload_accepted_types' is now set per-upload // $form->upload_accepted_types = 'jpg,png,gif'; if ($form->submitted()) { $file = $form->file('photo'); if ($form->ok()) { echo "File uploaded: " . $file; } }
Note: File upload needs the most hand-finishing. The migrator maps
upload()to the corefile()method and comments out every upload property with a TODO, so nothing is silently carried over — but it does not build aservices.uploadblock into an emptynew Flick(). Flick's key for the size limit ismaxFileSize. Add the upload config yourself:$form = new Flick([ 'services' => [ 'upload' => [ 'directory' => '/uploads/', 'maxFileSize' => '5MB', ] ] ]);Then use the Pro image handler with a
mimeTypesrule:$form->upload->image('photo', ['mimeTypes:image/jpeg,image/png,image/gif']).
After Migration
-
Search for TODOs: Find all migration comments in your codebase
grep -r "TODO: FLICK MIGRATION" /path/to/project -
Address each TODO: Review and fix each flagged item manually
-
Install Flick Pro (if needed): If you use email, uploads, or reCAPTCHA. Requires a license and the Flick Pro repository entry in composer.json — see flickphp.com/pro for setup.
composer require flickphp/pro
-
Test thoroughly: Run your application and test all forms
-
Remove migration package:
composer remove flickphp/migrate
Troubleshooting
"Method not found" errors after migration
The migration tool maps common methods, but some custom or less common Formr methods may not have direct equivalents.
Solution: Check the Flick documentation for the equivalent method, or use the generic input() method with type attributes.
Validation rules not working
Flick uses different syntax for validation rules:
- Commas instead of pipes:
required, emailnotrequired|valid_email - Colons for parameters:
min:5notmin[5]
Solution: Review your validation rules and ensure they use Flick syntax.
Form values not persisting
Formr automatically persisted values; Flick asks you to opt in.
Solution: Add 'persistToSession' => true to your Flick config:
$form = new Flick(['persistToSession' => true]);
Not 'session' — that key takes a session adapter (a SessionInterface
instance), and a true there is ignored.
CSRF token errors
Flick has CSRF protection enabled by default, which Formr did not.
Solution: Ensure your forms include the hidden token fields (automatic with create() or open()), or disable CSRF if needed:
$form = new Flick(['csrf' => false]);
Upload methods not working
File uploads require Flick Pro's upload service.
Solution: Install Flick Pro and configure the upload service, or handle uploads manually with PHP's native $_FILES.
reCAPTCHA not working
reCAPTCHA requires Flick Pro's recaptcha service.
Solution: Install Flick Pro and configure reCAPTCHA with your site/secret keys.
Limitations
The migration tool cannot automatically handle:
- Custom Formr extensions or subclasses
- Complex conditional logic around Formr methods
- JavaScript integrations that reference Formr-specific attributes
- Database queries that store Formr-specific data formats
These require manual review and migration.
Requirements
- PHP 8.3+
See Also
- Flick Documentation - Full Flick documentation
- Flick Core - Main Flick package
- Flick Pro - Premium services
License
MIT License. See LICENSE for details.