A lightweight, transparent PHP framework built on the principles of simplicity and clarity.
~15 MB · Lightweight Query Builder · No hidden dependencies · No magic · PHP 8.3 Attributes · Porto Architecture
Rudra follows the KISS principle — every tool is visible, every dependency is explicit, and every layer does exactly one thing. No "magic" happens behind the scenes: if you see it in the code, that's all there is.
- Transparency — no hidden behavior, no implicit side effects
- Simplicity — minimal surface area, easy to learn and extend
- Explicit over implicit — dependencies are declared, not guessed
- Modern PHP — built from the ground up on PHP 8.3+ features (attributes, typed constants, fibers)
Rudra is built for developers who:
- Prefer explicit code over framework magic — you want to see exactly what SQL is executed, what routes are registered, and what dependencies are injected
- Value cognitive clarity — you need a framework that stays out of your way and doesn't require memorizing hidden conventions
- Work on small-to-medium projects — you want structure and best practices without the overhead of enterprise-grade frameworks
- Want full control — you believe that understanding your tools is more important than having hundreds of features out of the box
If you're looking for a batteries-included framework with built-in ORM, pre-configured queue workers, and ready-made broadcast drivers — Rudra is not for you.
If you want a lightweight, transparent foundation with simple primitives that you can extend exactly as needed — you're in the right place.
composer create-project --prefer-dist rudra/framework newapp
cd newappcomposer create-project --prefer-dist --stability=dev rudra/framework newapp
cd newappThe fastest way to get a fully working local environment — containers, dependencies, SSL, and database included:
git clone git@github.com:Jagepard/Rudra-Framework.git
cd Rudra-Framework
ddev start # Start containers, install deps, set up SSL & DB
ddev launch # Open the site in your browserRun the built-in development server:
php rudra serveThen open http://127.0.0.1:8000 in your browser.
Rudra is built on a modular component architecture. Each component is a standalone Composer package — use only what you need, or install everything via rudra/framework.
| Component | Description | Package |
|---|---|---|
| 📦 Container | DI container with 5 binding patterns (string, object, factory string, factory object, closure) | rudra/container |
| 🧭 Router | HTTP router with PHP 8 attributes, middleware pipeline, REST resources, method spoofing | rudra/router |
| 🎯 Controller | MVC controller abstraction with lifecycle hooks (init, before, after) |
rudra/controller |
| 💾 Model | Lightweight Query Builder + Repository pattern (not a heavy ORM) | rudra/model |
| 🔐 Auth | Authentication, session management, RBAC, "Remember Me" | rudra/auth |
| 🔗 OAuthClient | OAuth 2.0 client (Yandex, VK, custom providers) | rudra/oauth-client |
| 🎧 EventDispatcher | Events system with Listeners (pub/sub) and Observers (stateless notifications) | rudra/event-dispatcher |
| ✅ Validation | Fluent validation with CSRF, sanitization, custom rules, field aliases | rudra/validation |
| 🖼️ View | Template engine (PHP + Twig support) with file-based caching | rudra/view |
| 🛡️ Exception | HTTP error handling with custom error pages and DebugBar integration | rudra/exception |
| 🔀 Redirect | HTTP redirection with status codes (1xx-5xx) | rudra/redirect |
| 📄 Pagination | SQL OFFSET/LIMIT calculator with page links generator | rudra/pagination |
| 📜 Annotation | Metadata reader for PHP 8 attributes + legacy docblock annotations | rudra/annotation |
| 🖥️ Cli | CLI component with command routing | rudra/cli |
| 📝 Docs | Auto-generates Markdown API documentation from source code | rudra/docs |
use Rudra\Auth\AuthFacade as Auth;
// Registration
$user = [
"email" => "user@email.com",
"password" => Auth::bcrypt("password")
];
// Authentication (plain password vs hash from DB)
Auth::authentication($user, "password", ["admin/dashboard", "login"]);
// Authorization check (redirects to 'login' if not authenticated)
if (!Auth::authorization(null, "login")) {
exit;
}
// Role-Based Access Control
if (!Auth::roleBasedAccess($currentRole, "editor", "error/403")) {
exit;
}use Rudra\EventDispatcher\EventDispatcherFacade as Dispatcher;
// Listeners — pub/sub with payload
Dispatcher::addListener('user.registered', [UserListener::class, 'onRegister']);
Dispatcher::dispatch('user.registered', ['id' => 1, 'email' => '...']);
// Observers — stateless notifications (no payload)
Dispatcher::attachObserver('before', [AuditObserver::class, 'onEvent']);
Dispatcher::notify('before');use Rudra\Container\Facades\Request;
use Rudra\Container\Facades\Session;
use Rudra\Validation\ValidationFacade as V;
$fields = Request::post()->all();
$processed = [
'name' => V::sanitize($fields ['name'])->required()->min(3)->max(50)->run(),
'email' => V::email($fields ['email'])->run(),
'age' => V::sanitize($fields ['age'])->integer()->between(18, 100)->run(),
'description' => V::set($fields['description'])->run(), // without validation
'csrf' => V::sanitize($fields['csrf'])->csrf(Session::get('csrf_token'))->run(),
];
if (V::approve($processed)) {
$data = V::getValidated($processed, ["csrf", "_method"]);
} else {
$errors = V::getErrors($processed);
}Registers standard CRUD routes with explicit plural and singular URL patterns. No magic pluralization — you define exactly what the URLs look like.
$router->resource('api/users', 'api/user', UserController::class);This creates the following routes:
| Method | URL | Controller Method | Description |
|---|---|---|---|
| GET | api/users | index | List all users |
| GET | api/user/:id | read | Get single user |
| POST | api/users | create | Create new user |
| PUT | api/user/:id | update | Full update user |
| PATCH | api/user/:id | update | Partial update user |
| DELETE | api/user/:id | delete | Delete user |
The default action names are [index, read, create, update, delete].
You can override the default action names by passing a custom array of 5 methods:
$router->resource('api/posts', 'api/post', PostController::class, [
'actionIndex', // GET api/posts — list all posts
'actionView', // GET api/post/:id — get single post
'actionAdd', // POST api/posts — create new post
'actionUpdate', // PUT/PATCH api/post/:id — update post
'actionDrop' // DELETE api/post/:id — delete post
]);The array order is fixed: [index, read, create, update, delete].
use Rudra\View\ViewFacade as View;
// Cache-first strategy with fallback
echo View::cache(['mainpage', "+1 day"]) ?? View::render(["layout", "mainpage"], [
'content' => View::cache(["page_{$slug}", "+1 day"])
?? View::view(["page", "page_{$slug}"], ['foo' => 'bar']),
]);
// Or with helpers
data(['content' => cache(['mainpage']) ?? view(['index', 'mainpage'])]);
render('layout', data());Rudra includes a lightweight, transparent data access layer — not a heavy ORM, but a simple Query Builder with Repository pattern.
A predictable delegation chain with automatic fallback:
- Entity — entry point, defines the table name
- Model — business logic layer (optional)
- Repository — data access layer (optional, falls back to base CRUD)
If you don't create a Model or Repository, the base Repository handles standard CRUD automatically.
namespace App\Containers\User\Entity;
use Rudra\Model\Entity;
class User extends Entity
{
public static ?string $table = 'users';
}
// Usage — no Model or Repository needed:
$users = User::getAll();
$user = User::find(1);
User::create(['name' => 'John', 'email' => 'john@example.com']);namespace App\Containers\User\Repository;
use Rudra\Model\Repository;
class UserRepository extends Repository
{
public function findActiveUsers(): array
{
return $this->qBuilder("SELECT * FROM {$this->table} WHERE active = 1");
}
}
// Automatically routed:
$activeUsers = User::findActiveUsers();use Rudra\Model\QBFacade as QB;
$query = QB::select('id, name, email')
->from('users')
->where('status = :status')
->and('role = :role')
->orderBy('created_at DESC')
->limit(10)
->get();
// Execute via Repository:
$results = User::qBuilder($query, ['status' => 'active', 'role' => 'admin']);use Rudra\Model\Schema;
Schema::create('users', function ($table) {
$table->integer('id', '', true) // auto-increment
->string('name')
->string('email')
->text('bio', 'NULL')
->created_at()
->updated_at()
->pk('id');
})->execute();Simple, reliable JSON file caching — no Redis/Memcached required:
// Cache query results
$users = User::cache(['getAll']);
// Cache with TTL
$posts = Post::cache(['findBy', ['category', 'news']], '+1 hour');
// Auto-clears on create/update/delete- No magic — no hidden queries, no lazy loading surprises
- No hidden dependencies — direct PDO access when needed
- Predictable — you see exactly what SQL is executed
- Fast — no reflection overhead, no entity hydration complexity
- Simple — if you know SQL, you know Rudra-Model
Rudra ships with a rich set of CLI utilities following the Porto architecture. Run php rudra help to see the full list.
| Command | Description |
|---|---|
php rudra serve |
Start the built-in dev server (alias: run) |
php rudra help |
List all available commands |
| Command | Description |
|---|---|
php rudra make:container |
📦 Scaffold a new Porto container |
php rudra make:controller |
🧭 Generate a controller class |
php rudra make:contract |
📜 Generate an interface (contract) |
php rudra make:factory |
🏭 Generate a factory class |
php rudra make:listener |
👂 Generate an event listener |
php rudra make:middleware |
🛡️ Generate a middleware class |
php rudra make:migration |
🗄️ Generate a database migration |
php rudra make:model |
🧱 Generate Entity + Repository pair |
php rudra make:observer |
👁️ Generate an event observer |
php rudra make:seed |
🌱 Generate a database seeder |
php rudra make:docs |
📝 Generate documentation from source |
| Command | Description |
|---|---|
php rudra migrate |
🛤️ Run pending migrations (with duplicate protection) |
php rudra seed |
🌾 Execute seeders (with duplicate protection) |
| Command | Description |
|---|---|
php rudra debug:router |
🗺️ List all registered routes |
php rudra debug:router:container |
🔍 List routes for a specific container |
php rudra debug:listeners |
🎧 List registered event listeners |
php rudra debug:observers |
🔭 List registered event observers |
| Command | Description |
|---|---|
php rudra bcrypt |
🔐 Hash a password with bcrypt |
php rudra secret |
🔑 Generate a cryptographic secret (APP_KEY) |
| Command | Description |
|---|---|
php rudra cache:clear |
🧹 Clear application cache |
php rudra convert:array-to-yml |
🔄 Convert a PHP array config to YAML (alias: to:yml) |
- PHP 8.3 Attributes for routing and middleware — clean, declarative syntax
- Automatic Dependency Injection with autowiring
- 5 container binding patterns: string, object, factory string, factory object, closure
- Event Dispatcher with both Listeners and Observers
- File-based caching — simple, reliable, no external dependencies
- Porto Architecture — clear separation between Ship (shared) and Containers (modules)
- DebugBar integration with custom collectors (Security, PDO, Config)
- Whoops for beautiful error pages in development
- Twig support — optional, via factory binding
- RESTful resources — one line registers all CRUD routes
- Method spoofing — PUT/PATCH/DELETE from POST forms via
_method - CSRF protection built into validation and controllers
This project is licensed under the Mozilla Public License 2.0 (MPL-2.0) — a free, open-source license that:
- ✅ Requires preservation of copyright and license notices
- ✅ Allows commercial and non-commercial use
- ✅ Requires that modifications to original files remain open under MPL-2.0
- ✅ Permits combining with proprietary code in larger works
📄 Full license text: LICENSE
🌐 Official MPL-2.0 page: https://mozilla.org/MPL/2.0/