Flick for Laravel
Flick works inside Laravel with no wiring of your own. Install the integration
package and new Flick() picks up Laravel's request, session, CSRF token and
validator automatically.
composer require flickphp/laravel
That's the whole setup. The package is auto-discovered, so there is no provider to register and no alias to add.
Writing your own adapter?
You only need request adapters and session adapters for frameworks Flick has no package for. In Laravel, this package has already done it.
Configuration
The package ships working defaults. Publish the config file only when you want to change them:
php artisan vendor:publish --tag=flick-config
That writes config/flick.php:
return [ 'views' => env('FLICK_VIEWS', 'tailwind'), 'csrf' => false, // use Laravel's CSRF middleware 'honeypot' => 'website_url', 'sessionAutoStart' => false, // Laravel manages sessions 'echo' => false, // return strings for Blade ];
Whatever ends up in config('flick') becomes the default for every Flick
instance in the app, so a bare new Flick() honors it. Per-instance config
still wins:
$form = new Flick(['views' => 'bootstrap']); // this form only
Two of these defaults are not cosmetic:
echo => falsemakes form methods return their HTML instead of printing it, which is what Blade's{!! !!}needs.sessionAutoStart => falsekeeps Flick from callingsession_start()behind Laravel's session middleware.
In a controller
use Flick\Flick; class ContactController extends Controller { public function show() { return view('contact', ['form' => new Flick]); } public function store() { $form = new Flick; if ($form->submitted()) { $data = $form->request('Name[required], Email[required, email], Message[required, min:10]'); if ($form->ok()) { // send the mail, save the row... return redirect()->back()->with('success', 'Message sent!'); } } return view('contact', ['form' => $form]); } }
You do not need to pass config('flick') — the service provider already bridged
it into Flick's defaults at boot.
In a Blade view
Because echo is false, render each element with {!! !!}:
{!! $form->open('/contact', 'POST') !!}
{!! $form->text('name', 'Name', '', ['rules' => 'required']) !!}
{!! $form->email('email', 'Email', '', ['rules' => 'required,email']) !!}
{!! $form->textarea('message', 'Message', '', ['rules' => 'required']) !!}
{!! $form->submit('Send Message') !!}
{!! $form->close() !!}
CSRF protection
open() injects Laravel's CSRF token for you. Do not add @csrf — you would
render the field twice.
{!! $form->open('/contact', 'POST') !!}
{{-- the token is already here --}}
{!! $form->text('name', 'Name') !!}
{!! $form->submit() !!}
{!! $form->close() !!}
Keep form routes in the web group
The default 'csrf' => false is a trust, not a check: Flick renders Laravel's
token and assumes Laravel's middleware validated it. That holds for routes
inside the web middleware group. A form posted to a route outside that
group gets no CSRF check from either side.
Keep form routes in web, or set 'csrf' => 'strict':
| Value | What Flick does |
|---|---|
false (default) |
Renders Laravel's token; trusts Laravel's middleware to validate it |
'strict' |
Renders Laravel's token and validates the posted _token itself |
true or an integer |
Ignores Laravel's token; uses Flick's own session token, integer = timeout in seconds |
'strict' is opt-in rather than the default because a client that sends the
token only as a header posts no _token field — Axios sends X-XSRF-TOKEN
automatically — and Flick would reject that submission.
Method spoofing
Browsers only send GET and POST, so PUT, PATCH and DELETE need
Laravel's @method spoofing. Flick has no directive for it — write the tag
yourself and use Flick for the fields:
<form method="POST" action="/contact"> @csrf @method('PUT') {!! $form->text('name', 'Name') !!} {!! $form->submit() !!} </form>
Laravel validation rules
Flick checks its own rules first, then hands anything it doesn't recognize to Laravel's validator. Database rules work with no extra setup:
$form->text('email', 'Email', '', ['rules' => 'required,email,unique:users,email']); $form->select('category_id', 'Category', '', [ 'options' => ['1' => 'News', '2' => 'Sports'], 'rules' => 'required,exists:categories,id', ]);
Custom rules registered with Validator::extend() are picked up too.
Flick's own list is longer than it looks, so a rule you think of as Laravel's may
never reach it. confirmed is one: Flick has its own and it looks for
_confirmation exactly as Laravel's does, so the check behaves the same
either way — only the wording of the error message differs.
Custom messages work the same way:
$form->text('email', 'Email', '', [ 'rules' => 'required,unique:users,email', 'messages' => [ 'required' => 'Please enter your email address.', 'unique' => 'This email is already registered.', ], ]);
The facade
Optional, and it does exactly one thing:
use Flick\Laravel\Facades\Flick; $form = Flick::make(['views' => 'bootstrap']);
Flick::make($config) is identical to new Flick($config) — it returns a new
instance every time, because forms have their own error bags and must stay
independent.
Warning
make() is the only static call the facade supports. Anything else — say
Flick::addError(...) — throws a BadMethodCallException, because each
passthrough would build a different instance and silently lose your state. Call
methods on the object make() returns.
What the package wires up
The service provider binds three adapters as singletons and installs them as Flick's defaults:
| Adapter | Wraps |
|---|---|
LaravelRequest |
Illuminate\Http\Request — POST, GET, files, cookies, headers |
LaravelSession |
Laravel's session store, used for multistep forms and CSRF |
LaravelValidationDelegate |
Laravel's validator, for rules Flick doesn't know |
It also registers csrf_token() as Flick's token source and bridges
config('flick') into Flick's defaults.
Each adapter receives a resolver closure rather than the boot-time request or session, so it reads the current one on every request. That matters under Octane, where one adapter instance outlives a single request and would otherwise serve the first request's data to every later one.
Requirements
- PHP 8.3+
- Laravel 12.x or 13.x
- flickphp/flick ^1.0