π¬ Proof of Concept of the MVC in PHP
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.
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:
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:
Registration.php
file.BundleManager
class.SessionManager
.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:
app/Controllers/HomeController.php
<?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:
public/index.php
<?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:
app/Config/Registration.php
<?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']);
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:
Once the application is running:
/
will display the Home Page./about
will display the About Us page.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.
Root Directory
is set to the project root (leave this blank).public/
, since this is where the index.php
resides.To ensure that Vercel handles your PHP app properly, you need to add a vercel.json
configuration file in your projectβs root directory:
vercel.json
{
"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:
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 the nginx
directory:
The NGINX configuration is required for routing PHP requests to PHP-FPM. The file should be located at nginx/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.