Orango is a lightweight PHP micro framework designed for simplicity, extensibility, and explicit control over application flow focused into MVC environments. It is loosely inspired by Laravel, borrowing some of its elegance and developer experience, while intentionally avoiding its complexity and heavy structure.
I constantly build small projects, many of them run locally or on simple VPS environments.
I enjoy using Laravel a lot. It provides a great DX and a lot of great builtin features. However, for smaller projects, its size and complexity often feel excessive. It feels like using a bazooka to kill an ant.
Because of that, I wrote this repository that I called Orango (yes, from orangutan).
The goal was to create a micro framework that preserves some of Laravel’s elegance and practicality, while keeping a much lighter structure, reducing complexity, and allowing more direct extensibility.
Orango is built around a very small ecosystem of components:
- A central application (
Application) - A dependency injection container
- A routing system
- A request abstraction
- A pluggable view layer
Everything is explicitly wired together through the bootstrap process and container.
The flow is straightforward:
- The request enters through
public/index.php - Dependencies are registered via bootstrap
- Routes are loaded
- The request is matched against routes
- A handler is executed
- A response is returned
git clone https://github.com/matusal3m/orango.git your-project
cd your-project
composer installrm -rf .git && git init && git add . && git commit -m "initial commit"The Application class is responsible for orchestrating the request lifecycle.
- Loads routes
- Matches incoming requests
- Dispatches handlers
- Handles 404 responses
Entry point:
app()->handleRequest(Request::capture());The container is responsible for dependency resolution.
Features:
- Singleton registration
- Factory registration
- Automatic resolution via reflection
- Closure dependency injection
Example:
Container::singleton('config', new Config(...));
$config = Container::resolve('config');Automatic injection:
Router::get('/', function (Request $request, MyService $service) {
// dependencies resolved automatically
});Routes are defined using static methods:
Router::get('/', function () {
return 'Hello World';
});Dynamic routes:
Router::get('/users/{id}', function ($id) {
return "User {$id}";
});Controller usage:
Router::get('/users', [UserController::class, 'index']);The Request object encapsulates all HTTP input.
$request->input('name');
$request->get('id');
$request->all();
$request->file('avatar');
$request->header('authorization');Orango supports multiple handler types:
Router::get('/', fn () => 'Hello'); // Closures
Router::get('/', [HomeController::class, 'index']); // Controllers
Router::get('/', 'Hello world'); // Primitive valuesThe view system is driver-based and configurable.
Rendering:
return view('home', ['name' => 'Matusalem']);Configuration:
return [
'driver' => PlatesViewRenderDriver::class, // implements the Packages/View/ViewRenderDriver interface
'root' => 'client/views',
'extensions' => ['.html', '.php'],
];Drivers can be replaced without affecting application code.
Configuration files are stored in config/. The config can be getted by the config() helper, using dot notation. The first segment is the file name, the other ones are the array accessors.
config()->get('view.root');Supports:
- Dot notation
- Lazy evaluation via closures (in config files)
Path::fromDot('users.profile'); // users/profilefs()->read('file.txt');
fs()->root('client/views/home.php'); // uses the project root as referenceapp/
Controllers/
bootstrap/
bootstrap.php
singletons.php
config/
view.php
packages/
Core/
Container/
Http/
Support/
View/
routes/
web.php
client/
views/
public/
index.php
- app/: application-specific code (controllers, services etc.)
- bootstrap/: dependency registration and initialization
- config/: framework configuration
- packages/: framework core
- routes/: route definitions
- client/: view layer
- public/: entry point
Everything in this structure is intentionally customizable. You are not locked into these conventions.
Orango is intentionally minimal.
It does not include:
- ORM
- Middleware pipelines
- CLI tools
- Authentication systems
- Event system
The framework is meant to be extended based on actual needs. New features may be added either in the core repository or as separate modules, depending on their scope.
You are expected to decide what your application needs and build on top of the foundation.
// Basic route
Router::get('/', function () {
return 'Hello Orango';
});
// Controller example
class HomeController
{
public function index(): View
{
return view('home', ['message' => 'Hello']);
}
}
// Dynamic route
Router::get('/users/{id}', function ($id) {
return "User {$id}";
});
// Using dependency injection
Router::get('/test', function (Request $request, Config $config) {
return $config->get('app.name');
});MIT
Created by Matusal3m
Repository: https://github.com/matusal3m/orango