tavo1987/mini-framework
tavo1987/mini-framework is a lightweight, minimal PHP framework for small projects and prototypes, offering a simple structure to organize routes, controllers, and views without the overhead of a full-stack framework. Best suited for tiny apps and learning.
Read this first: v5 is not a Laravel package. The headline item is Nuevo core - Slim 3, and everything after it (Phinx instead of Eloquent migrations, its own auth/session/CSRF middlewares, Laravel Mix only for asset compilation, SwiftMailer) describes a standalone Slim 3 application skeleton. Treat this release as a framework swap, not a version bump. The only Laravel-adjacent thing left in the stack is Mix.
Minimal path to a running app:
composer install
cp .env.example .env # settings/keys live here or in config/
npm install
npm run dev # Laravel Mix 2 → webpack 3
vendor/bin/phinx migrate # NOT php artisan migrate
vendor/bin/phinx seed:run # if seeders ship
php -S localhost:8080 -t public # or your nginx/apache vhost
Where to look, in order:
public/index.php — bootstrap and middleware registration (this is your new "kernel").routes/ or wherever the Slim route definitions live — the whole HTTP surface is here, no controllers auto-discovery.phinx.php / phinx.yml — connection config is separate from your app config; both must agree.webpack.mix.js + tailwind.js/tailwind.config.js — asset pipeline and PurgeCSS content globs.src/ (or app/) — auth module, middleware, validators, mail service.First use case to validate the whole stack: build one CRUD form for a person with a cédula field, using the new custom validation rule, a Phinx migration for the table, the auth middleware to protect the route, CSRF on the form, and a flash message on success. If that round-trips, you've touched sessions, CSRF, migrations, validation, views, and the middleware stack — which is basically everything v5 introduces.
Middleware ordering is the contract. Sessions must be registered before CSRF, and CSRF before your route handlers. In Slim 3 (which is not PSR-15 native — it uses its own callable($request, $response, $next) signature) the LIFO behaviour of $app->add() trips people up:
$app->add(new \App\Middleware\CsrfViewMiddleware($container)); // expose token to views
$app->add(new \App\Middleware\ValidationErrorsMiddleware($container)); // pull flash errors
$app->add(new \App\Middleware\OldInputMiddleware($container)); // repopulate forms
$app->add($container->get('csrf')); // LAST added = FIRST run
$app->add(new \Slim\Middleware\Session($settings['session'])); // session must precede CSRF
Flash messages are session-backed and read-once. Follow the three-middleware pattern above: write to $_SESSION['flash'] in the controller, read it in the view layer before rendering the base template, and clear it in the same request. Don't cache the rendered flash outside the request — it will stick.
Custom cédula validation — register the rule with whatever validator the package uses (respect the container, not statics):
$container->get('validator')->extend('cedula', function ($value) {
if (!is_string($value) || !preg_match('/^\d{10}$/', $value)) {
return false;
}
$province = (int) substr($value, 0, 2);
if (!(($province >= 1 && $province <= 24) || $province === 30)) {
return false;
}
$sum = 0;
for ($i = 0; $i < 9; $i++) {
$d = (int) $value[$i] * ($i % 2 === 0 ? 2 : 1);
$sum += $d > 9 ? $d - 9 : $d;
}
return (10 - ($sum % 10)) % 10 === (int) $value[9];
});
Apply it per-field ('cedula' => 'required|cedula') and always normalize trim/length before it — Ecuadorians paste IDs with spaces and dashes.
Phinx migrations are the day-to-day replacement for php artisan make:migration. Create with vendor/bin/phinx create CreatePeopleTable, then use the fluent $this->table('people') API. Keep change() reversible so phinx rollback works in CI; anything with raw SQL should use up()/down() explicitly. Remember Phinx tracks state in phinxlog, not migrations — do not point it at a table that already holds Laravel migration rows.
Mail goes through SwiftMailer injected from the container; wrap it in your own Mailer service so the Swift dependency is one file deep when you eventually swap to Symfony Mailer. SwiftMailer has no queue — if a send is slow, you're blocking the request; do it after the response or in a worker.
Asset pipeline: Tailwind + PurgeCSS means your CSS is derived from usage. Keep classes literal in PHP/JS ('bg-red-500', 'text-white') — never string-concatenated. npm run production should be the only command that touches the deploy artifact; dev builds are large and unpurged.
artisan, no Eloquent models, no Blade, no Hash::make (use password_hash/password_verify), no session() helper, no facades. This is the single biggest onboarding cost — budget a day for anyone coming from L4/L5 muscle memory.ERR_OSSL_EVP_UNSUPPORTED. Use nvm use 8 (or 10) in a .nvmrc, or set NODE_OPTIONS=--openssl-legacy-provider. Do not upgrade Mix in place inside this package — fork it or move to Vite.purgecss.whitelist (Mix 2-era config) or you will ship unstyled states that only appear in production builds.fetch/axios calls need the token forwarded manually from the view middleware. Also scope CSRF middleware away from webhook/API route groups, or they'll 400.phinx.php reading a hardcoded host while .env points elsewhere.9999999999-style test data fails the province check (good), but the rule can't tell you the ID is issued or belongs to the holder. Treat it as format validation and keep your real identity verification elsewhere.displayErrorDetails for local dev only, and set up file logging early — debugging an unhandled exception in a Slim 3 app with displayErrorDetails=false is a blank 500 page.vendor/ — anything you patch, patch via your own class extending it, or the next composer update wipes it.How can I help you explore Laravel packages today?