robertwesner/simple-mvc-php

A small library for creating PHP web servers.

v0.5.0 2025-02-25 17:50 UTC

This package is auto-updated.

Last update: 2025-02-25 17:50:52 UTC


README

Simple MVC for PHP

License: MIT

A small library for creating PHP web servers.

Use case: Serving semi-static content; not intended for large scale sites with complex logic.

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

Websites using this:

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

Installation

New project

This creates a new project with the required folder structure and is the preferred way of use.

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

Existing project

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

composer require robertwesner/simple-mvc-php "*"

Configuration

nginx

All traffic except for "/public" should be redirected to "/route.php".

Below is a Nginx sample configuration running under Docker.

server {
    index index.php index.html;
    server_name ...;
    error_log  /var/log/nginx/error.log;
    access_log /var/log/nginx/access.log;
    root /var/www/html;

    proxy_intercept_errors on;

    location / {
        try_files /public$uri /public /route.php?$query_string;
    }

    location ~ /route\.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass php-fpm:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}

Usage

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

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

<?php

use RobertWesner\SimpleMvcPhp\Route;
use RobertWesner\SimpleMvcPhp\Routing\Request;

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/(?<userId>\d+)', function (Request $request) {
    $userId = $request->getUriParameter('userId'); // Returns numeric userId from capture group

    // ...
});

view.php

<?php

use RobertWesner\SimpleMvcPhp\Route;
use RobertWesner\SimpleMvcPhp\Routing\Request;

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

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

Using Controller Classes

More complex Logic can be handled with class controllers.

Note: This is not recommended. Complex applications should use more sophisticated frameworks.

See: demo class and demo routing

<?php

use RobertWesner\SimpleMvcPhp\Route;
use RobertWesner\SimpleMvcPhp\Tests\Route\Class\Controller\UserController;

$controller = new UserController();
Route::get('/api/users', $controller->all(...));
Route::get('/api/users/(?<userId>\d+)', $controller->get(...));
Route::post('/api/users', $controller->create(...));
Route::delete('/api/users/(?<userId>\d+)', $controller->delete(...));