vtapp / vtphp
VTPHP - Virtual Tech PHP Framework: A modern, feature-rich PHP framework inspired by Laravel
Requires
- php: ^8.4
- ext-json: *
- ext-mbstring: *
- ext-pdo: *
- doctrine/dbal: ^4.4
- eftec/bladeone: ^4.0
- illuminate/database: ^11.0 || ^12.0
- monolog/monolog: ^3.12
- nyholm/psr7: ^1.8
- nyholm/psr7-server: ^1.1
- psr/clock: ^1.0
- psr/container: ^2.0
- psr/event-dispatcher: ^1.0
- psr/http-factory: ^1.1
- psr/http-message: ^2.0
- psr/http-server-handler: ^1.0
- psr/http-server-middleware: ^1.0
- psr/log: ^3.0
- psr/simple-cache: ^3.0
- symfony/cache: ^7.4.1
- symfony/console: ^7.4
- symfony/dotenv: ^7.4
- symfony/mailer: ^7.4
- symfony/process: ^7.4
- symfony/routing: ^7.4
- vlucas/phpdotenv: ^5.6
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.64
- phpstan/phpstan: ^1.12
- phpunit/phpunit: ^11.5
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
An independent, API-first PHP framework with a Laravel-inspired developer experience —
built on PSR standards plus Symfony/Doctrine/Monolog components, with illuminate/database
(Eloquent ORM), eftec/bladeone (Blade templating), and symfony/mailer (Mail) as
opt-in, well-isolated dependencies for the features that benefit most from them.
#[Route(method: 'GET', path: '/users/{id}', name: 'users.show')] public function show(int $id): UserResource { return UserResource::make($this->service->find($id)); }
Documentation
In-depth, per-topic guides live in docs/: routing,
controllers, middleware, validation, resources, models, migrations, sessions
& cookies & cache, authentication, views, mail, exceptions, the container,
and the forge CLI.
Requirements
- PHP ^8.4
- ext-json, ext-mbstring, ext-pdo (+ the PDO driver for your database)
Getting started
composer install copy .env.example .env php forge key:generate php forge migrate php forge db:seed php forge serve
Then visit http://127.0.0.1:8000/health or http://127.0.0.1:8000/api/v1/users.
By default DB_CONNECTION=sqlite, so php forge migrate creates
database/database.sqlite automatically — no external database server needed to
try the framework. php forge db:seed populates it with two sample users via
Eloquent. Swap in mysql/pgsql in .env for a real database.
Project layout
app/ Your application code (Controllers, Services, Models, Resources, ...)
bootstrap/ Application bootstrap (builds the container, config, providers)
config/ Configuration files (env-driven)
database/ Migrations
public/ Web server document root (public/index.php is the front controller)
routes/ Route definition files, loaded by App\Providers\RouteServiceProvider
src/ The framework itself, namespace VtPhp\ (Container, HTTP, Routing, ...)
stubs/ Templates used by `forge make:*` generators
storage/ Logs, cache, and file storage (private/public disks)
tests/ PHPUnit tests
src/ is the framework core (VtPhp\ namespace) and app/ is your application
(App\ namespace) — both ship in this one repository for now. Per the framework's
own "avoid overbuilding v1" principle, src/ can be extracted into standalone
Composer packages later (see the multi-package layout described in the blueprint)
once the contracts stabilize.
forge CLI
php forge about # application info php forge serve # run the PHP built-in server php forge route:list # list all registered routes php forge key:generate # generate APP_KEY php forge make:controller UserController php forge make:model Product php forge make:resource ProductResource php forge make:middleware EnsureTokenIsValid php forge make:migration create_products_table php forge make:seeder ProductSeeder php forge make:mail OrderShipped php forge migrate php forge migrate:status php forge migrate:rollback php forge db:seed
Architecture
Application Code (app/)
↓
VtPhp Framework (src/) — contracts, HTTP kernel, router, container, exceptions
↓
PSR Standards + Vendor Components (Symfony Routing/Console/Dotenv, Doctrine DBAL, Monolog)
- Container —
src/Container/Container.php: PSR-11 container with reflection-based autowiring. - HTTP — PSR-7 (via
nyholm/psr7) with a convenienceVtPhp\Http\Requestwrapper and a fluentJsonResponse. - Routing —
symfony/routingunderneath, plus a#[Route]attribute for controller-based routing. - Middleware — PSR-15 pipeline (
VtPhp\Middleware\Pipeline). - Exceptions — centralized
ExceptionHandlermapping exceptions to a structured{"success":false,"error":{...}}JSON envelope. - Database —
doctrine/dbalbehindVtPhp\Database\DatabaseManager, with a small file-based migration runner.illuminate/database(Eloquent) runs alongside it viaVtPhp\Database\EloquentManager, reading the sameconfig/database.php, for applications that want ActiveRecord-style models. - Validation — a dependency-free rule-string validator (
required|string|max:100) that throwsValidationException. - Resources —
JsonResource/ResourceCollectionfor shaping API output and pagination envelopes. - Views —
eftec/bladeonebehindVtPhp\View\BladeEnginefor Blade-syntax templates (e.g. email bodies), resolved fromresources/views/. - Mail —
symfony/mailerbehindVtPhp\Mail\Mailer, with a Laravel-styleMailablebase class (app/Mail/) and alogtransport for local dev (no SMTP server needed). - Logging —
monolog/monologbehindPsr\Log\LoggerInterface. - CLI —
symfony/consolebehind theforgebinary, with stub-basedmake:*generators (controllers, models, resources, middleware, migrations, seeders, mailables).
Sample API endpoints
routes/api.php registers a sample User CRUD resource plus password-recovery
and email-verification endpoints under the /api/v1 prefix:
| Method | URI | Description |
|---|---|---|
| GET | /api/v1/users |
List users |
| POST | /api/v1/users |
Create a user (name, email, password, password_confirmation) |
| GET | /api/v1/users/{id} |
Show a user |
| PATCH | /api/v1/users/{id} |
Update a user (name, email — both optional) |
| DELETE | /api/v1/users/{id} |
Delete a user (204 No Content) |
| POST | /api/v1/password/forgot |
Request a password reset email (email) |
| POST | /api/v1/password/reset |
Reset a password (email, token, password, password_confirmation) |
| POST | /api/v1/email/verification-notification |
(Re)send the email verification link (email) |
| GET | /api/v1/email/verify/{id}/{hash} |
Verify an email address via the emailed link |
Notes:
- User creation requires a
password(min 8 chars) confirmed viapassword_confirmation, matching theconfirmedvalidation rule. forgot()and the verification-notification endpoint respond with the same generic success message whether or not the email exists (or is already verified), to avoid leaking account existence.- Reset tokens are single-use, hashed at rest (
password_reset_tokenstable), and expire after 60 minutes. - Since
MAIL_MAILER=logby default, reset/verification links are written tostorage/logs/app.loginstead of being emailed — copy the link/token from there when testing locally.
Sessions, cookies & cache
In addition to the stateless api token guard, the framework ships
Laravel-style session-based auth, cookie handling, and a pluggable cache
layer (symfony/cache under the hood).
| Method | URI | Description |
|---|---|---|
| POST | /api/v1/login |
Log in (email, password) — sets a session cookie |
| POST | /api/v1/logout |
Log out — invalidates the session |
| GET | /api/v1/me |
Current authenticated user (requires the session cookie) |
- Sessions —
VtPhp\Session\SessionManagerstarts aSessionper request (bound into the container by theStartSessionmiddleware), backed by aSessionStoreInterfacedriver:file(default,storage/framework/sessions/, serialized withallowed_classes: falseto avoid PHP object-injection) orarray(non-persistent, tests/CLI only). Configure viaconfig/session.php/SESSION_DRIVER,SESSION_LIFETIME,SESSION_COOKIE,SESSION_SECURE_COOKIE,SESSION_SAME_SITEenv vars. - Cookies — outgoing cookies are queued via the
cookie()helper (VtPhp\Cookie\CookieJar) and attached to the response asSet-Cookieheaders by theAddQueuedCookiesToResponsemiddleware. Incoming cookies can be read with$request->cookie('name')or$psrRequest->getCookieParams(). - Auth guards —
config/auth.phpnow has awebguard (driver: session) alongside the existingapiguard. Use theauth()helper:auth('web')->attempt([...]),->user(),->check(),->logout(). Protect routes with theAuthenticatemiddleware via the#[Route(middleware: [...])]attribute parameter (seeAuthController::me()). - Cache — the
cache()helper (VtPhp\Cache\CacheManager) exposesget/put/has/forget/remember/flush, resolving a PSR-16 store perconfig/cache.php. Supported drivers:array(in-memory),file(storage/framework/cache/data), andredis. - Redis is an optional adapter, not a hard dependency —
symfony/cacheis always installed, but actually selectingCACHE_DRIVER=redisrequires the app to additionally installext-redisorpredis/predis. Configure the connection viaREDIS_HOST,REDIS_PORT,REDIS_PASSWORD,REDIS_CACHE_DB.
Database, seeding & Eloquent
app/Models/User.php is an Eloquent model (Illuminate\Database\Eloquent\Model),
and app/Repositories/EloquentUserRepository.php is the default binding for
UserRepositoryInterface. Migrations still use the Doctrine DBAL-based
php forge migrate runner (database/migrations/); seeders are plain classes
extending VtPhp\Database\Seeder (database/seeders/):
php forge make:migration create_products_table php forge make:seeder ProductSeeder php forge migrate php forge db:seed
Blade views & Mail
Render a Blade view (from resources/views/) with the view() helper:
echo view('emails.welcome', ['user' => $user]);
Define a Mailable and send it through the Mailer:
// app/Mail/WelcomeEmail.php final class WelcomeEmail extends Mailable { public function __construct(private readonly User $user) {} public function build(): void { $this->to($this->user->email) ->subject('Welcome to VtPhp!') ->view('emails.welcome', ['user' => $this->user]); } } app(\VtPhp\Mail\Mailer::class)->send(new WelcomeEmail($user));
MAIL_MAILER defaults to log (writes the rendered email to the app log instead
of sending it) so mail works out of the box with no SMTP server configured. Set
it to smtp and configure MAIL_HOST/MAIL_PORT/MAIL_USERNAME/MAIL_PASSWORD
in .env for real delivery.
What's not included yet
Following the blueprint's own v0.1 → v1.0 roadmap, this build covers Phases 1–9
(foundation, HTTP, routing, controllers, middleware, exceptions, database,
validation, API resources) plus the CLI, Eloquent ORM, Blade templating, and
mail. Authentication/authorization, cache, rate limiting, events, queues,
filesystem drivers, and OpenAPI generation are the next phases — the config
files and .env keys for most of them are already scaffolded in config/ to
make that work additive rather than a rewrite.
Testing
composer test # phpunit composer stan # phpstan analyse composer fmt # php-cs-fixer fix