This project is a Proof of Concept (PoC) for a custom-built PHP MVC framework that adheres to several PHP-FIG standards, including PSR-1, PSR-2, PSR-4, and PSR-11. It demonstrates how to build a lightweight MVC structure with custom routing and dependency injection (IoC/DI) while following best practices for modern PHP development.
- PoC PHP MVC Framework with Custom Router, IoC/DI Container (PSR-compliant)
In this PoC, we will build a small MVC application from scratch using PSR-compliant components. This includes a custom router, a basic dependency injection container, and an organized controller/view structure.
The goal of this PoC is to demonstrate the importance of clean, maintainable architecture by implementing industry-standard interfaces and coding practices. We will also use Composer to handle autoloading, complying with the PSR-4 standard.
The project complies with the following PSRs:
- PSR-1: Basic coding standards, ensuring a consistent code style.
- PSR-2: Coding style guide, which helps maintain a consistent structure across files. (deprecated - view PSR-12)
- PSR-4: Autoloading standard using Composer, mapping namespaces to file directories.
- PSR-11: Container interface for dependency injection, enabling a service-based architecture. PSR-12: Coding style guide, which helps maintain a consistent structure across files.
The project follows a clear structure that separates concerns into Controllers, Views, and configuration:
/project-root
β
ββββapp
β ββββConfig
β β BundleRegistration.php # Handles the registration of static bundles (CSS, JS, etc.)
β β Registration.php # Registers application services and controllers
β β
β ββββControllers # Contains all application controllers
β β AboutController.php # Controller for the About page
β β ApiController.php # Handles general API endpoints
β β AuthController.php # Handles authenticationβrelated actions
β β ContactController.php # Manages the Contact form
β β HomeController.php # Handles the home and sandbox pages
β β UsersApiController.php # API Controller for userβrelated endpoints
β β UsersController.php # Controller for user management
β β
β ββββModels # Contains the application's models
β β ContactModel.php # Model representing the contact form data
β β UserModel.php # Model representing a user
β β
β ββββViews # Contains the views rendered in response to requests
β ββββAbout
β β index.php # About page view
β β
β ββββAuth
β β login.php # Login page view
β β
β ββββContact
β β index.php # Contact form view
β β
β ββββHome
β β docs.php # API documentation view
β β index.php # Home page view
β β sandbox.php # Sandbox view for testing API requests
β β sections.php # View demonstrating the use of sections in layouts
β β
β ββββShared
β β layout.php # Shared layout file for consistent structure
β β
β ββββUsers
β index.php # View listing all users
β show.php # View showing user details
β
ββββnginx # NGINX configuration for running the application
β Dockerfile # Dockerfile to build NGINX environment
β nginx.conf # NGINX configuration file
β
ββββpublic # Publicly accessible directory (web root)
β β index.php # Application entry point
β β
β ββββassets # Static assets
β scripts.js # Custom JS for the application
β styles.css # Custom styles for the application
β
ββββsrc # Core application logic
β ββββContainer
β β DIContainer.php # Dependency Injection Container
β β
β ββββController
β β ApiBaseController.php # Base controller for API endpoints
β β BaseController.php # Main base controller for all standard controllers
β β
β ββββCore
β β Application.php # Main Application class that bootstraps the framework
β β BundleManager.php # Manages static asset bundles (CSS, JS)
β β SessionManager.php # Manages session functionality
β β
β ββββRouter
β Router.php # Router class for handling routes
β
ββββtests # Unit and integration tests for the framework
β β phpunit.xml # PHPUnit configuration file
β β
β ββββIntegration
β β FullAppTest.php # Integration test covering full application behavior
β β HomeControllerTest.php # Integration test for HomeController
β β
β ββββUnit
β DIContainerTest.php # Unit test for DI Container
β RouterTest.php # Unit test for Router
β
ββββvendor # Composer dependencies
βββcomposer.json # Composer configuration file
βββREADME.md # Project documentation
We will build a minimalistic PHP framework with the following components:
- Routing: A custom router that maps incoming HTTP requests (GET, POST, etc.) to controllers and actions.
- Dependency Injection: A basic IoC container (compliant with PSR-11) that resolves controller dependencies.
- MVC Pattern: We will adhere to the MVC (Model-View-Controller) architecture, separating logic into Controllers and Views.
- PSR-4 Autoloading: The project structure is set up for PSR-4 compliant autoloading using Composer.
-
Routing:
- Custom router that supports dynamic routes with parameters.
- Automatic route registration using attributes.
- Handles static files and supports trailing slashes.
-
Dependency Injection (DI):
- Custom DI container to manage class dependencies.
- Services and controllers are registered through the
Registration.php
file.
-
Static Bundling:
- Bundles CSS, JS, and other assets using the
BundleManager
class.
- Bundles CSS, JS, and other assets using the
-
Session Management:
- Custom session handling using the
SessionManager
.
- Custom session handling using the
The project also includes a simple REST API for user management, located at /api/v1/users/
. You can find detailed documentation for this API in the API Docs view.
The example below is a simple HomeController that renders a view:
<?php
namespace GuiBranco\PocMvc\App\Controllers;
class HomeController
{
public function index()
{
return $this->view('home', ['title' => 'Home Page']);
}
public function about()
{
return $this->view('home', ['title' => 'About Us']);
}
}
The front controller dispatches incoming HTTP requests:
<?php
use GuiBranco\PocMvc\App\Config\BundleRegistration;
use GuiBranco\PocMvc\App\Config\Registration;
use GuiBranco\PocMvc\Src\Core\Application;
require_once __DIR__ . '/../vendor/autoload.php';
$app = new Application(); // The core/main application class.
$registration = new Registration($app); // The user-defined registration class. Register routes, add services (DI/IoC), register API controllers.
$registration->addServices();
$registration->registerRoutes();
$registration->registerApiControllers();
$bundleRegistration = new BundleRegistration(); // The user-defined bundle registration. Use this to register assets in bundles to be rendered in the views.
$bundleRegistration->registerBundles();
$app->run(); // Run the application. Accept requests.
Finally, the IoC container and Router registration resolves the controller dependencies and the routes:
<?php
use GuiBranco\PocMvc\App\Controllers\HomeController;
use GuiBranco\PocMvc\Src\Container\DIContainer;
use GuiBranco\PocMvc\Src\Router\Router;
$container = new DIContainer();
$container->set(HomeController::class, function() { return new HomeController(); });
$router = new Router();
$router->add('GET', '/', [HomeController::class, 'index']);
$router->add('GET', '/about', [HomeController::class, 'about']);
- PHP 8.3 or higher (it can work with 7.4 or higher, but not tested).
- Composer (for dependency management)
-
Clone the Repository:
git clone https://github.com/GuilhermeStracini/poc-php-mvc.git cd poc-php-mvc
-
Install Dependencies: Run the following command to install the required dependencies via Composer:
composer install
-
Run the Application: Start the built-in PHP server:
php -S localhost:8000 -t public
-
Access the Application: Open your browser and navigate to:
- http://localhost:8000 to view the home page.
- http://localhost:8000/about to view the about page.
Once the application is running:
- Visiting
/
will display the Home Page. - Visiting
/about
will display the About Us page. - Both pages will use the MVC pattern, with the controller handling logic and views rendering the HTML.
- The application will follow PSR-1, PSR-2/PSR-12, PSR-4, and PSR-11, ensuring a scalable and maintainable codebase.
You can deploy this project to Vercel with just one click! Vercel is a great platform for hosting PHP projects with zero configuration. Follow the steps below to deploy this example to Vercel.
- Click the "Deploy to Vercel" button above or go to Vercel Import.
- Import your GitHub repository by linking your GitHub account.
- Configure your project settings:
- Ensure the
Root Directory
is set to the project root (leave this blank). - Set the Output Directory to
public/
, since this is where theindex.php
resides.
- Ensure the
- Deploy your project and your PHP MVC framework will be live in a few seconds.
To ensure that Vercel handles your PHP app properly, you need to add a vercel.json
configuration file in your projectβs root directory:
{
"version": 2,
"builds": [
{
"src": "public/index.php",
"use": "@vercel/php"
}
],
"routes": [
{
"src": "/(.*)",
"dest": "public/index.php"
}
]
}
This project can be run using Docker, and we provide two variants for running the PHP 8.3 environment:
- Apache
- NGINX with PHP-FPM
Ensure you have Docker and Docker Compose installed on your machine.
To run the project with PHP 8.3 and Apache, follow these steps:
-
Build and run the containers:
docker compose up --build
-
Access the application: After the container is up and running, you can access the application in your browser at http://localhost:8080.
-
Stopping the containers: To stop the running containers, use:
docker compose down
To run the project with PHP 8.3, NGINX, and PHP-FPM, follow these steps:
-
Ensure you have the
nginx.conf
file in thenginx
directory: The NGINX configuration is required for routing PHP requests to PHP-FPM. The file should be located atnginx/nginx.conf
. -
Build and run the containers:
docker compose -f docker-compose-nginx.yml up --build
-
Access the application: Once the containers are up and running, access the application in your browser at http://localhost:8080.
-
Stopping the containers: To stop the running containers, use:
docker compose -f docker-compose-nginx.yml down
Unit and integration tests are provided to validate the core functionality. Run the tests with PHPUnit:
vendor/bin/phpunit tests
Tests are organized into two directories:
tests/Unit
: Contains unit tests for individual components.tests/Integration
: Contains integration tests for full application functionality.