PHPackages                             mawsis/nebula-php - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Framework](/categories/framework)
4. /
5. mawsis/nebula-php

ActiveLibrary[Framework](/categories/framework)

mawsis/nebula-php
=================

A PHP 8 MVC framework built from scratch: DI container, router, ORM, migrations, middleware, validation, and JWT auth

v1.0.0(1y ago)021PHPPHP &gt;=8.0

Since Feb 12Pushed 1mo ago1 watchersCompare

[ Source](https://github.com/Mawsis/NebulaPHP)[ Packagist](https://packagist.org/packages/mawsis/nebula-php)[ RSS](/packages/mawsis-nebula-php/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (3)Versions (2)Used By (0)

Nebula PHP
==========

[](#nebula-php)

Nebula is a PHP 8 MVC framework written from scratch to understand how modern frameworks actually work under the hood (dependency injection, routing, an ORM, middleware, validation) without hiding any of it behind magic. The entire core is ~2,600 lines across 50 focused classes with only three runtime dependencies (dotenv, Monolog, firebase/php-jwt), so it is small enough to read in an afternoon and real enough to build a JSON API or a server-rendered app with. It is installable via Composer as [`mawsis/nebula-php`](https://packagist.org/packages/mawsis/nebula-php).

Features
--------

[](#features)

- **DI container**: `bind` / `singleton` / `instance` / `alias`, with reflection-based auto-wiring for constructors, controller methods, and route closures
- **Router**: static and `{param}` routes, closure or `[Controller::class, 'method']` callbacks, per-route middleware
- **ORM**: active-record style `DbModel` (`findOne`, `create`, `save`) on top of a fluent `QueryBuilder` (where / joins / groupBy / having / orderBy / limit / offset, all with bound parameters), plus `hasOne` / `hasMany` / `belongsTo` relationships and eager loading via `with()`
- **Migrations**: file-based migrations with an applied-migrations table and rollback support
- **HTTP layer**: `Request` with input sanitization, JSON body parsing, and helpers (`input`, `only`, `except`, `bearerToken`); `Response` with a consistent JSON envelope and `success` / `error` / `validationError` helpers
- **Validation**: Laravel-style form requests: declare `rules()` on a `Request` subclass, use string rules (`'min:8'`, `'unique:users:email'`) or rule objects, call `validated()`
- **Auth**: session-based authentication with a configurable user model, plus stateless JWT (HS256) via `JwtHelper`
- **Middleware**: Auth, JWT, CORS, CSRF, and JSON middleware included; custom middleware is a single `execute()` method
- **Error handling**: typed exceptions (`NotFoundException`, `UnauthorizedException`, `ForbiddenException`, `ValidationException`, ...) mapped by a central handler to JSON for API requests or rendered error views
- **Extras**: facades (`Route`, `DB`, `Auth`, `Session`, `Logger`), a `Transform` layer for shaping API resources, pagination, flash messages, Monolog logging, dotenv config

Requirements
------------

[](#requirements)

- PHP &gt;= 8.0
- Composer

Quick Start
-----------

[](#quick-start)

Scaffold a new application with the [Nebula Installer](https://github.com/Mawsis/Nebula-Installer):

```
composer global require mawsis/nebula-installer
nebula new my-app
```

Or pull the core into an existing project:

```
composer require mawsis/nebula-php
```

A minimal front controller looks like this:

```
// public/index.php
require_once __DIR__ . '/../vendor/autoload.php';

Dotenv\Dotenv::createImmutable(dirname(__DIR__))->safeLoad();
Nebula\Core\Config::load(dirname(__DIR__) . '/config');

$app = new Nebula\Core\Application(dirname(__DIR__));

require_once __DIR__ . '/../routes/main.php';

$app->run();
```

See [Nebula-Example](https://github.com/Mawsis/Nebula-Example) for a complete application skeleton (config, providers, routes, controllers, migrations, views, Docker setup).

Usage
-----

[](#usage)

### Routing

[](#routing)

Routes take a closure or a `[Controller::class, 'method']` pair, plus an optional list of middleware aliases:

```
use Nebula\Core\Facades\Route;
use App\Controllers\AuthController;
use App\Controllers\UserController;

Route::get('/users', [UserController::class, 'listUsers'], ['auth']);
Route::get('/users/{id}', [UserController::class, 'showUser'], ['auth']);
Route::post('/login', [AuthController::class, 'loginStore']);
```

Controller methods are resolved through the container, so dependencies are injected by type hint:

```
public function listUsers(Request $request, Response $response)
{
    $users = Paginator::paginate(User::query()->orderBy('id', 'ASC'), $response);

    return $response->json(['users' => $users]);
}
```

### Models and queries

[](#models-and-queries)

A model declares its table, attributes, and primary key; the base class does the rest:

```
namespace App\Models;

use Nebula\Core\DbModel;

class Post extends DbModel
{
    public static function tableName(): string  { return 'posts'; }
    public static function primaryKey(): string { return 'id'; }
    public static function attributes(): array  { return ['title', 'body', 'user_id']; }

    public function user()
    {
        return $this->belongsTo(User::class, 'user_id');
    }
}
```

```
$post = Post::findOne(['id' => 42]);

$posts = Post::query()
    ->where('user_id', '=', $userId)
    ->orderBy('created_at', 'DESC')
    ->limit(10)
    ->get();

$posts = Post::with(['user'])->where('title', 'LIKE', '%nebula%')->get(); // eager loading

Post::create(['title' => 'Hello', 'body' => '...', 'user_id' => 1]);
```

### Validation

[](#validation)

Declare rules on a `Request` subclass. String rules are resolved through `config/validations.php`, and anything after `:` is passed to the rule's constructor; you can also pass rule objects or write your own by extending `BaseValidation`:

```
namespace App\Requests;

use Nebula\Core\Request;

class RegisterRequest extends Request
{
    public function rules(): array
    {
        return [
            'username' => ['required', 'min:3', 'max:20'],
            'email'    => ['required', 'email', 'unique:users:email'],
            'password' => ['required', 'min:8'],
        ];
    }
}
```

Type-hint the request in a controller action and call `validated()`; on failure it throws a `ValidationException`, which the central handler turns into a `422` JSON response with per-field errors:

```
public function registerStore(RegisterRequest $request, Response $response)
{
    $data = $request->validated();

    User::create([
        'username' => $data['username'],
        'email'    => $data['email'],
        'password' => password_hash($data['password'], PASSWORD_DEFAULT),
    ]);

    return $response->success(['registered' => true], 201);
}
```

### Middleware

[](#middleware)

Middleware aliases are defined once in `config/middlewares.php` and referenced by name in routes:

```
return [
    'auth' => Nebula\Core\Middlewares\AuthMiddleware::class,
    'jwt'  => Nebula\Core\Middlewares\JwtMiddleware::class,
    'csrf' => Nebula\Core\Middlewares\CsrfMiddleware::class,
    'cors' => Nebula\Core\Middlewares\CorsMiddleware::class,
    'json' => Nebula\Core\Middlewares\JsonMiddleware::class,
];
```

A custom middleware is one class with one method; it halts the request by throwing a typed exception:

```
use Nebula\Core\Facades\Auth;
use Nebula\Core\Middlewares\BaseMiddleware;
use Nebula\Core\Exceptions\ForbiddenException;

class AdminMiddleware extends BaseMiddleware
{
    public function execute()
    {
        if (Auth::isGuest() || !Auth::user()->is_admin) {
            throw new ForbiddenException();
        }
    }
}
```

Design
------

[](#design)

Everything in Nebula is deliberately hand-rolled to expose the mechanics that larger frameworks abstract away:

- **Container** (`Container`): a static service container with `bind` / `singleton` / `instance` / `alias`. Auto-wiring uses reflection to resolve constructor, controller-method, and closure dependencies, with sensible fallbacks for defaults and nullable parameters.
- **Router** (`Router` + `Route` facade): routes are stored per HTTP method; `{param}` segments are compiled to regexes at match time. Route middleware is resolved from config aliases (or passed as instances) and executed before the action.
- **ORM** (`DbModel` + `QueryBuilder`): models describe their schema in three static methods; the query builder assembles parameterized SQL and hydrates results back into model instances. Relationships are plain methods built on the same query builder, and `with()` eager-loads them onto results.
- **HTTP + errors** (`Request`, `Response`, `Handler`): requests sanitize input and parse JSON bodies; responses emit a consistent `{success, status_code, data | error}` envelope. A central handler maps typed exceptions to JSON for API requests or rendered error views, and fatal errors get a dedicated error page.
- **Validation**: rule classes implement a two-method `BaseValidation` contract (`validate`, `getErrorMessage`); string rules map to classes through config, so applications can register their own rules the same way the built-ins work.
- **Auth**: a session-backed `Auth` service (`login`, `logout`, `user`, `isGuest`) with the user model class supplied via config, plus JWT issuance/verification for stateless APIs.
- **Facades**: a ~10-line `__callStatic` base class that proxies to container-resolved services, which is all a facade actually is.

Ecosystem
---------

[](#ecosystem)

RepositoryDescription[Nebula-Installer](https://github.com/Mawsis/Nebula-Installer)`nebula new` CLI for scaffolding new applications[Nebula-Example](https://github.com/Mawsis/Nebula-Example)Full example application built on the frameworkLicense
-------

[](#license)

Released under the [MIT License](LICENSE).

###  Health Score

33

—

LowBetter than 72% of packages

Maintenance69

Regular maintenance activity

Popularity6

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity43

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

551d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/121339373?v=4)[Mawsis](/maintainers/Mawsis)[@Mawsis](https://github.com/Mawsis)

---

Top Contributors

[![Mawsis](https://avatars.githubusercontent.com/u/121339373?v=4)](https://github.com/Mawsis "Mawsis (14 commits)")

### Embed Badge

![Health badge](/badges/mawsis-nebula-php/health.svg)

```
[![Health](https://phpackages.com/badges/mawsis-nebula-php/health.svg)](https://phpackages.com/packages/mawsis-nebula-php)
```

###  Alternatives

[laravel/framework

The Laravel Framework.

34.9k556.2M21.5k](/packages/laravel-framework)[tempest/framework

The PHP framework that gets out of your way.

2.3k37.6k21](/packages/tempest-framework)[lion/bundle

Lion-framework configuration and initialization package

132.4k5](/packages/lion-bundle)[pressbooks/pressbooks

Pressbooks is an open source book publishing tool built on a WordPress multisite platform. Pressbooks outputs books in multiple formats, including PDF, EPUB, web, and a variety of XML flavours, using a theming/templating system, driven by CSS.

45844.8k1](/packages/pressbooks-pressbooks)[doppar/framework

The Doppar Framework

4112.6k14](/packages/doppar-framework)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
