Framework Skeleton: Bootstrapping

The purpose of any web framework is to take control of request-response flow. To do so, it needs to reroute all requests, except those that point to physical files supposed to be accessed over the web (images, js, css), to itself. This process is called bootstrapping and in PHP applications it's achieved in two steps:

  1. setting up a directive on web server to reroute all requests to a single bootstrap file
  2. an index.php file (aka "bootstrap") where framework will be loaded and ran to handle request into response

How to configure web servers to reroute requests to bootstrap?

Currently, two web servers, together handling more than 99% of PHP applications worldwide, are officially supported by framework:

Regardless of web server and operating system used, after rerouting is setup, you must restart web server and make sure hosts file (/etc/hosts if Linux or Mac, C:\Windows\System32\drivers\etc\hosts if Windows) contains entry:
127.0.0.1 YOUR_SITE_DOMAIN_NAME

Rerouting using Apache2

Assuming you are using Apache2 web server, skeleton already comes with an .htaccess file installed on your site that does everything for you:

# informs Apache2 web server you are going to reroute requests RewriteEngine on # turns off directory listing Options -Indexes # makes 404 responses to public (images, js, css) files handled by web server ErrorDocument 404 default # redirects all requests, except those pointing to public files, to bootstrap RewriteCond %{REQUEST_URI} !^/public RewriteCond %{REQUEST_URI} !^/favicon.ico RewriteRule ^(.*)$ index.php # sets development environment (default is local) SetEnv ENVIRONMENT DEVELOPMENT_ENVIRONMENT

Then you only need to setup an Apache2 virtualhost that contains only this:

<VirtualHost *:80> # sets site domain name (eg: www.testing.local) ServerName YOUR_SITE_DOMAIN_NAME # sets location of site on disk (eg: /var/www/html/testing) DocumentRoot YOUR_SITE_ABSOLUTE_DISK_PATH # delegates rerouting to htaccess file above <Directory YOUR_SITE_ABSOLUTE_DISK_PATH> AllowOverride All Require all granted </Directory> </VirtualHost>

If .htaccess files are forbidden on your system, simply replace <directory> tag with contents of .htaccess file above!

Rerouting using NGINX

If you're using NGINX, .htaccess is ignored anyway, so all bootstrapping logic must be in virtual host:

server { listen 80; listen [::]:80 ipv6only=on; # sets location of site on disk (eg: /var/www/html/testing) root YOUR_SITE_ABSOLUTE_DISK_PATH; # sets location of bootstrap file index index; # sets site domain name (eg: www.testing.local) server_name YOUR_SITE_DOMAIN_NAME; # redirects all requests, except those pointing to public files, to bootstrap location / { rewrite ^/(.*)$ /index; } location /public/ { } location /favicon.ico { } # configures PHP-FPM to handle requests location ~ \$ { try_files $uri =404; fastcgi_split_path_info ^(.+\)(/.+)$; # location of PHP-FPM socket file (eg: /var/run/php/php7.0-fpm.sock) fastcgi_pass unix:SOCKET_FILE_LOCATION; fastcgi_index index; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param SERVER_ADMIN NA; fastcgi_param SERVER_SIGNATURE nginx/$nginx_version; include fastcgi_params; } }

To add development environment, you need to edit PHP-FPM configuration file (eg: /etc/php/7.2/fpm/php-fpm.conf) and add:
env[ENVIRONMENT] = DEVELOPMENT_ENVIRONMENT then restart PHP-FPM service.

How does bootstrap file work?

Bootstrap is just a small procedural PHP file whose purpose is merely to load and start STDERR framework that handles exception-response logic then STDOUT framework that handles request-response logic.

// performs development environment detection $environment = getenv("ENVIRONMENT"); if(!$environment) die("Value of environment variable 'ENVIRONMENT' could not be detected!"); define("ENVIRONMENT", $environment); // takes control of STDERR require_once("vendor/lucinda/errors-mvc/src/FrontController.php"); require_once("application/models/EmergencyHandler.php"); new Lucinda\MVC\STDERR\FrontController("stderr.xml", $environment, __DIR__, new EmergencyHandler()); // takes control of STDOUT require_once("vendor/lucinda/mvc/src/FrontController.php"); new Lucinda\MVC\STDOUT\FrontController("stdout.xml");

Detecting development environment

Development environment is detected first (based on "ENVIRONMENT" value setup above by statements SetEnv @ Apache2 or env @ Nginx), because it is a requirement of both STDERR and STDOUT frameworks. Value of development environment will be from now on available via ENVIRONMENT constant. If you don't like that constant, you can use native PHP function:
getEnv("ENVIRONMENT")

Starting STDERR framework

STDERR MVC API is started afterwards, because it will need to handle any exception that will be thrown as soon as STDOUT flow has started. To do so, it register itself as sole handler of uncaught exceptions and PHP errors (themselves redirected to an uncaught exception). For the unusual case when an error happens in STDERR flow, too, bootstrap feeds framework with an EmergencyHandler object whose behavior is up to developer to modify (by default it displays error details and trace).

Once started, this API remains in sleeping mode and will only load its dependencies when it will have an exception to handle. API behavior is configurable declaratively via an XML file fed by bootstrap. Its contents are preset by skeleton, but can be modified by developer whenever situation requires.

Starting STDOUT framework

STDOUT MVC API is started last and performs normal request-response flow using same MVC pattern as above. Framework behavior is configurable declaratively via an XML file fed by bootstrap. Its contents are preset by skeleton, but can be modified by developer whenever situation requires.

On any uncaught exception thrown (which usually happens when execution has stumbled on an error), response handling will be automatically transfered to STDERR MVC API, who is getting resurrected.


Share