PHP without a framework: Difference between revisions
No edit summary |
|||
(9 intermediate revisions by the same user not shown) | |||
Line 2: | Line 2: | ||
* How to inject a request and eject a response. | * How to inject a request and eject a response. | ||
* How to create a database connection based on config. | |||
* How to upgrade the framework without touching the rest of the application. | |||
* How to access the rest of the application from the vendor tree. | |||
== Limitations == | == Limitations == | ||
Line 15: | Line 18: | ||
* '''PSR-15 middleware dispatcher:''' [https://route.thephpleague.com/ Route] | * '''PSR-15 middleware dispatcher:''' [https://route.thephpleague.com/ Route] | ||
* '''PSR-7 implementation:''' [https://docs.laminas.dev/laminas-diactoros/ laminas-diactoros] | * '''PSR-7 implementation:''' [https://docs.laminas.dev/laminas-diactoros/ laminas-diactoros] | ||
* '''Error handling:''' [https://github.com/filp/whoops whoops] | * '''Error handling:''' [https://github.com/filp/whoops whoops] with symfony/var-dumper | ||
* '''Templates:''' [https://twig.symfony.com/ Twig] | * '''Templates:''' [https://twig.symfony.com/ Twig] | ||
* '''Logging:''' monolog/monolog | * '''Logging:''' monolog/monolog | ||
Line 48: | Line 51: | ||
== Instructions == | == Instructions == | ||
=== Add dependencies === | === Add dependencies === | ||
Line 57: | Line 56: | ||
composer require php-di/php-di | composer require php-di/php-di | ||
composer require filp/whoops | composer require filp/whoops | ||
composer require laminas/laminas-diactoros | composer require laminas/laminas-diactoros | ||
composer require laminas/laminas-httphandlerrunner | |||
composer require league/route | composer require league/route | ||
Create skeleton directory structure: | Create skeleton directory structure: | ||
mkdir public | mkdir public src | ||
== Bootstrap file == | == Bootstrap file == | ||
Line 106: | Line 105: | ||
echo 'Hello World'; | echo 'Hello World'; | ||
} | } | ||
} | |||
== Static Page Controller == | |||
<?php | |||
declare(strict_types = 1); | |||
namespace WebApp\Controllers; | |||
use Psr\Http\Message\ResponseInterface; | |||
use Psr\Http\Message\ServerRequestInterface; | |||
use Laminas\Diactoros\Response; | |||
use MicroFramework\Config; | |||
use MicroFramework\View; | |||
class StaticPageController extends \MicroFramework\Controller | |||
{ | |||
public function index(ServerRequestInterface $request): ResponseInterface | |||
{ | |||
$response = new Response; | |||
$config = Config::getInstance()->getData(); | |||
$html = View::render($config['views']['templates_path'], 'index.html'); | |||
$response->getBody()->write($html); | |||
return $response; | |||
} | |||
} | } | ||
Latest revision as of 13:57, 4 April 2021
Things to think about
- How to inject a request and eject a response.
- How to create a database connection based on config.
- How to upgrade the framework without touching the rest of the application.
- How to access the rest of the application from the vendor tree.
Limitations
- MySQL/MariaDB the only supported RDBMS.
- UTF-8 everywhere.
Dependencies
The following dependencies are all actively maintained and available via Composer:
- Dependency injection: PHP-DI
- PSR-15 middleware dispatcher: Route
- PSR-7 implementation: laminas-diactoros
- Error handling: whoops with symfony/var-dumper
- Templates: Twig
- Logging: monolog/monolog
- Date/Time manipulation: nesbot/carbon
For configuration variables, use a simple PHP script which returns an array and is brought in using require_once
. This should work across all versions of PHP and if anyone accesses the file directly they will be shown a blank page (but it is still a good idea to keep it outside the document root and not in version control).
Databases
Use PDO for everything, as this gives the maximum flexibility.
- Set the charset in the DSN.
- Exceptions as the error mode (you should never get an SQL error in normal operation, so an exception is appropriate).
- Always use
bindValue
and set the data type (third parameter). - Set fetch mode to
PDO::FETCH_ASSOC
. - Remember
beginTransaction
andcommit
are available.
Testing
Iñtërnâtiônàlizætiøn is a good test string.
PHP built-in server
The PHP built-in server is sufficient for most purposes. Create a configuration file, local.ini
:
error_reporting = E_ALL display_errors = On
Start the server:
php -S localhost:8000 -t public -c local.ini
Instructions
Add dependencies
composer require php-di/php-di composer require filp/whoops composer require laminas/laminas-diactoros composer require laminas/laminas-httphandlerrunner composer require league/route
Create skeleton directory structure:
mkdir public src
Bootstrap file
Create Bootstrap file at src/Bootstrap.php
:
<?php declare(strict_types = 1); error_reporting(E_ALL); date_default_timezone_set('Europe/London'); require_once __DIR__ . '/../vendor/autoload.php'; $whoops = new Whoops\Run; $whoops->pushHandler(new \Whoops\Handler\PrettyPageHandler); $whoops->register();
Front controller
Create skeleton front controller at public/index.php
:
<?php declare(strict_types = 1); require_once __DIR__ . '/../vendor/autoload.php';
Create HelloWorld
class in src/HelloWorld.php
:
<?php declare(strict_types = 1); namespace MyApp; class HelloWorld { public function hello() : void { echo 'Hello World'; } }
Static Page Controller
<?php declare(strict_types = 1); namespace WebApp\Controllers; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Laminas\Diactoros\Response; use MicroFramework\Config; use MicroFramework\View; class StaticPageController extends \MicroFramework\Controller { public function index(ServerRequestInterface $request): ResponseInterface { $response = new Response; $config = Config::getInstance()->getData(); $html = View::render($config['views']['templates_path'], 'index.html'); $response->getBody()->write($html); return $response; } }
Logins and registration
password_hash
password_verify
password_needs_rehash