PHPackages                             robertwesner/simple-mvc-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. robertwesner/simple-mvc-php

ActiveLibrary[Framework](/categories/framework)

robertwesner/simple-mvc-php
===========================

A small library for creating PHP web servers.

v0.11.2(1y ago)01075MITPHPPHP &gt;=8.4CI passing

Since Aug 26Pushed 7mo ago1 watchersCompare

[ Source](https://github.com/RobertWesner/simple-mvc-php)[ Packagist](https://packagist.org/packages/robertwesner/simple-mvc-php)[ RSS](/packages/robertwesner-simple-mvc-php/feed)WikiDiscussions main Synced yesterday

READMEChangelog (10)Dependencies (5)Versions (26)Used By (5)

Simple MVC for PHP
===================

[](#simple-mvc-for-php)

[![](https://github.com/RobertWesner/simple-mvc-php/actions/workflows/tests.yml/badge.svg)](https://github.com/RobertWesner/simple-mvc-php/actions/workflows/tests.yml/badge.svg)[![](https://raw.githubusercontent.com/RobertWesner/simple-mvc-php/image-data/coverage.svg)](https://raw.githubusercontent.com/RobertWesner/simple-mvc-php/image-data/coverage.svg)[![](https://camo.githubusercontent.com/9034893adf44568c3ec8e4ac9510645f47bc4093ca97ffdd2f6c38678e922c4d/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f526f626572745765736e65722f73696d706c652d6d76632d706870)](https://camo.githubusercontent.com/9034893adf44568c3ec8e4ac9510645f47bc4093ca97ffdd2f6c38678e922c4d/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f526f626572745765736e65722f73696d706c652d6d76632d706870)[![License: MIT](https://camo.githubusercontent.com/136888fb50da97dcd9d07841e3842dd86d504ed8a1eb1eb64ae389316f7138a7/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f526f626572745765736e65722f73696d706c652d6d76632d706870)](../../raw/main/LICENSE.txt)

A small library for creating PHP web servers.

Initially created for private use in place of Node-JS when creating very simple websites. Now able to run more complex applications. Feel free to use if it fits your needs.

Websites using this:

-
-
-

Features
--------

[](#features)

- Request handling (`GET`, `POST`, `PUT`, `PATCH`, `DELETE`)
    - Query parameters
    - JSON parameters
    - URI parameters
- Intuitive Syntax
- Simple to use composer template
- Integrated Twig templating engine
- \[Optional\] Autowiring of controller dependencies
- \[Optional\] Ability to load external bundles

Installation
------------

[](#installation)

### New Docker project

[](#new-docker-project)

This creates a Docker PHP-FPM + Nginx Project and is the preferred way of use.

```
composer create-project robertwesner/simple-mvc-php-docker-template
```

### New project

[](#new-project)

This creates a new project with the required folder structure.

```
composer create-project robertwesner/simple-mvc-php-template
```

### Existing project

[](#existing-project)

If you already have a project, require the package and migrate your files manually.

```
composer require robertwesner/simple-mvc-php
```

Usage
-----

[](#usage)

### Project structure

[](#project-structure)

```
PROJECT_ROOT
|-- public
|   '-- any publicly accessible data like JS, CSS, images, ...
|-- routes
|   '-- PHP routing scripts
|-- views
|   '-- twig views
|-- src
|-- vendor
'-- route.php

```

### Routing scripts

[](#routing-scripts)

You can create any amount of routing scripts. They define a mapping between a URL and a controller function or method.

Example:

```
PROJECT_ROOT
'-- routes
|   |-- api.php
|   '-- view.php
'-- views
    '-- main.twig

```

api.php

```
Route::post('/api/login', function (Request $request) {
    // Reads either Query or JSON-Body Parameter
    $password = $request->getRequestParameter('password');
    if ($password === null) {
        return Route::response('Bad Request', 400);
    }

    // ...

    return Route::json([
        'success' => $success,
    ]);
});

Route::post('/api/logout', function () {
    // ...
});

// Also able to read URI parameters
Route::get('/api/users/(?\d+)', function (Request $request) {
    $userId = $request->getUriParameter('userId'); // Returns numeric userId from capture group

    // ...
});

// 404 page, FALLBACK will be called when no other route matches
Route::get(Route::FALLBACK, function (Request $request) {
    return Route::render('404.twig');
});
```

view.php

```
Route::get('/', function () {
    // ...

    return Route::render('main.twig', [
        'loggedIn' => $loggedIn,
    ]);
});
```

### Using Controller Classes

[](#using-controller-classes)

More complex Logic can be handled with class controllers.

Resolving the controller requires [robertwesner/dependency-injection](https://github.com/RobertWesner/dependency-injection).

See: [demo class](./tests/Route/Class/Controller/UserController.php) and [demo routing](./tests/Route/Class/routes/user.php)

```
final class UserService
{
    // ...
}

readonly class UserController
{
    public function __construct(
        private UserService $userService,
    ) {}

    public function all(): ResponseInterface
    {
        // ...
    }

    public function get(Request $request): ResponseInterface
    {
        // ...
    }

    public function create(Request $request): ResponseInterface
    {
        // ...
    }

    public function delete(Request $request): ResponseInterface
    {
        // ...
    }
}
```

```
// Note: this requires robertwesner/dependency-injection
Route::get('/api/users', [UserController::class, 'all']);
Route::get('/api/users/(?\d+)', [UserController::class, 'get']);
Route::post('/api/users', [UserController::class, 'create']);
Route::delete('/api/users/(?\d+)', [UserController::class, 'delete']);
```

### Autowiring

[](#autowiring)

Installing [robertwesner/dependency-injection](https://github.com/RobertWesner/dependency-injection) allows for automatic resolution of Route dependencies:

```
// Autowired service class (AuthenticationService) inside Route
// Note: this requires robertwesner/dependency-injection
Route::post('/api/admin/some-endpoint', function (Request $request, AuthenticationService $authenticationService) {
    // ...
});
```

### Configuration

[](#configuration)

Configurations are optional and stored in `$PROJECT_ROOT$/configurations`, written in PHP.

You can run this server with zero configuration if you do not need the following features.

#### Container

[](#container)

File: `container.php`

Configures additional autowiring steps if you intend to use `robertwesner/dependency-injection` in complex use cases. You can manually define container instances with this configuration.

```
Configuration::CONTAINER
    // Either let the container do all the heavy lifting via class names,
    // MySQLEntityManager would be automatically instantiated by the container.
    // This is necessary for usage of interfaces, rather than implementations.
    ::instantiate(EntityManagerInterface::class, MySQLEntityManager::class)
    // Or pass your own instance when necessary, since Bar is not to be autowired.
    ::register(FooInterface::class, new Bar('SOME VALUE'));
```

#### Bundles

[](#bundles)

File `bundles.php`

Loads external bundles (implementing [BundleInterface](./src/Bundles/BundleInterface.php)) which may configure their own Container values.

> Feel free to store configurations for your bundles in a **subfolder** inside `$PROJECT_ROOT$/configuration`.
>
> Example: `$PROJECT_ROOT$/configurations/database/database.yml`

```
Configuration::BUNDLES
    ::load(FooBundle::class)
    // Optionally with additional configuration of any type, depending on the bundle.
    ::load(BarBundle::class, ['faz' => 'baz']);
```

### Error handling

[](#error-handling)

Requires the use of configuration files, refer to the previous section for mor information.

Use your preferred ThrowableHandler by instantiating it as `ThrowableHandlerInterface`. By default, without registering a handler, no exception information will be stored or printed.

Example: PrintThrowableHandler outputs directly to the browser

```
Configuration::CONTAINER
    ::instantiate(ThrowableHandlerInterface::class, PrintThrowableHandler::class);
```

Example: StderrThrowableHandler outputs into the server stderr and doesn't leak to the browser

```
Configuration::CONTAINER
    ::instantiate(ThrowableHandlerInterface::class, StderrThrowableHandler::class);
```

You can implement your own handler quite easily for additional tasks like sending automated mails.

###  Health Score

36

—

LowBetter than 79% of packages

Maintenance56

Moderate activity, may be stable

Popularity9

Limited adoption so far

Community13

Small or concentrated contributor base

Maturity57

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

Every ~15 days

Recently: every ~2 days

Total

20

Last Release

379d ago

PHP version history (2 changes)v0.1.0PHP ^8.3

v0.8.0PHP &gt;=8.4

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/155840994?v=4)[Robert Wesner](/maintainers/RobertWesner)[@RobertWesner](https://github.com/RobertWesner)

---

Top Contributors

[![RobertWesner](https://avatars.githubusercontent.com/u/155840994?v=4)](https://github.com/RobertWesner "RobertWesner (36 commits)")

###  Code Quality

TestsPHPUnit

Code StylePHP\_CodeSniffer

### Embed Badge

![Health badge](/badges/robertwesner-simple-mvc-php/health.svg)

```
[![Health](https://phpackages.com/badges/robertwesner-simple-mvc-php/health.svg)](https://phpackages.com/packages/robertwesner-simple-mvc-php)
```

###  Alternatives

[symfony/symfony

The Symfony PHP framework

31.4k87.2M2.2k](/packages/symfony-symfony)[drupal/core

Drupal is an open source content management platform powering millions of websites and applications.

21866.0M1.7k](/packages/drupal-core)[shopware/platform

The Shopware e-commerce core

3.4k1.5M3](/packages/shopware-platform)[drupal/core-recommended

Locked core dependencies; require this project INSTEAD OF drupal/core.

6942.5M421](/packages/drupal-core-recommended)[shopware/core

Shopware platform is the core for all Shopware ecommerce products.

585.6M574](/packages/shopware-core)[oro/platform

Business Application Platform (BAP)

645143.5k115](/packages/oro-platform)

PHPackages © 2026

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