Chapter 4: The Bootstrap Process and Request Lifecycle
Introduction: From Request to Response
With our server environment fully configured, we now move into the heart of the PHP application. The architecture we designed ensures that all page requests are funnelled into a single entry point:
index.php
. This is the start of the request lifecycle. This chapter provides a step-by-step tour, tracing a request from bootstrap to routing and finally to dispatching.
The Bootstrap and Routing Process
The journey of a request begins in earnest inside
mainController.php
. This file is the actual starting point for every page load and API call across all sites. Its purpose is to perform the initial setup and make the first critical routing decision.
The Code (mainController.php
)
<?php
global $ev;
// 1. Define core constants and load the environment variables from Apache
include_once('/var/www/oophp.uk/models/base/constants.php');
include_once(BASE_MODEL_DIRECTORY . 'getEnvironmentVariables.php');
// 2. Load the Composer autoloader for third-party libraries
require $ev['autoloadFile'];
// 3. Determine the request type (HTTP vs XHR/AJAX)
$isXHR = isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest';
$hasXhrParam = isset($_GET['xhr']) && $_GET['xhr'] == 1;
$finalController = ($isXHR || $hasXhrParam) ? 'xhrController.php' : 'httpController.php';
// 4. Hand off control to the base controller
require_once CONTROLLER_DIRECTORY.'baseController.php';
Code Breakdown
Initial Includes: The script starts by defining a global array, $ev, which will hold our environment configuration. It then includes constants.php to establish absolute file paths, followed by getEnvironmentVariables.php, which reads the SetEnv variables from Apache and populates the $ev array.
Autoloader: With the environment variables loaded, we can now include the Composer autoload.php file. This makes all our classes and vendor libraries available on demand.
Request Type Routing: Here we perform our first routing action, checking for the standard HTTP_X_REQUESTED_WITH header to identify an AJAX request. We also include a check for a ?xhr=1 query parameter for easy debugging. Based on this check, we decide which of our two main sub-controllers to load.
Dispatch to Base Controller: The final action is to hand over control to the baseController.php, where the application's core services will be instantiated.
The MainDispatcher: A Database-Driven Router
At the heart of our page-specific routing is a service class called MainDispatcher. Its job is to act as the application's central map, translating an incoming URL into a complete blueprint for building the page. All possible page requests are defined in a single database table: httpRequests. When a request comes in, the MainDispatcher performs a single, efficient query on this table to find the matching row, which contains the model(s) to execute and the view to render.
Dispatching to the Models
Once the MainDispatcher has done its job, the HttpController holds a complete blueprint for the page. The final step is to "dispatch" or execute the models listed in the plan. The controller iterates through the comma-separated list of model names and uses require_once to load and execute each file in sequence.
Conclusion: The Lifecycle Complete
We have now followed the complete journey of a single request. It is funnelled by Apache into our minimal index.php, which passes control to the mainController. This central gateway bootstraps the application, reads the site's configuration, and uses the database-driven MainDispatcher to create a plan. Finally, the HttpController executes that plan by dispatching to the necessary Models. This entire process happens on every single request, ensuring a consistent and secure foundation.