A simple stack based framework that's easy to use and extend. Flex uses PSR-7 requests and responses, the PSR-11 container, and other community libraries like Fast Route, Zend Diactoros, League Container, and Whoops.
Flex is a micro framework that stays out of your way and provides a minimal wrapper that allows you to write simple framework agnostic application code. Routing is based on a simple stack of application code whose only interaction with the framework is through PSR-7 request and response object.
All framework components can be replaced to suit the needs of the application by modifying the dependency injection container that is passed to Flex.
todo
todo
todo
todo
todo
todo
Getting started with Flex is as simple as creating an instance of the Flux App and calling
the run method. If you don't need to modify the container you can simply call the
App::create()
method to setup the application with a default container.
<?php
use MattColf\Flex\App;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
$config = [];
$config['debug'] = true;
$config['routes'] = [
'index' => [
'method' => 'GET',
'path' => '/',
'stack' => [
function (ServerRequestInterface $request, ResponseInterface $response) : ResponseInterface
{
$response->getBody()->write('<h1>Hello World!</h1>');
return $response;
}
]
]
];
$app = App::create($config);
$app->run();
In Flex, routes are defined through the routes
configuration key. Each entry in the routes
array represents either a single route or group of routes (more below) where the key is the name
of the route and the value is an array of the following route options.
method
: The HTTP method, or methods, that this route should match. Can be a string ('GET'
) or an array of strings (['GET', 'POST']
). Must be a valid HTTP method (GET
,POST
, etc.).path
: The relative path that the route should match. Should start with a/
, like/homepage
.stack
: An array ofmiddleware
andcontroller
references that should be run when the route matches. See Stack Definition below for more details.
When a group of routes should all have the same path prefix or middleware, you can group those
routes to simplify your configuration. Groups are configured the same as routes, but also have
the routes
option.
path
: The relative path that all routes in this group must start with.stack
: An array of middleware that should be added to each route in this group. This stack will be run before each member route's stack.routes
: An array of routes that are part of this group.
Note that groups may not have a method
option.
Route paths may contain parameters. When the application is run, these are provided to the stack
as an array in the request object route_params
attribute. Parameters are included in the path
as a curly bracket wrapped string. Here's an example.
$routes = [
'user-details' => [
'method' => 'GET',
'path' => '/users/{id}',
'stack' => [
'user.controller'
]
]
];
By default, Flex uses the Fast Route router. For more details, review the documentation on how to use route parameters there.
Each route's stack defines what should be run when the route matches. It is made up of references to middleware and controller functions that use PSR-7 request and response objects.
Each stack may have any number of middleware functions.
function (ServerRequestInterface $request, ResponseInterface $response, callable $next) : ResponseInterface
{
// your code that should run before the rest of the stack
// you are responsible for calling the next item in the stack
$response = $next($request, $response);
// your code that shiuld run after the rest of the stack
return $response;
}
Each stack must have a single controller which must also be the last item in the stack.
function (ServerRequestInterface $request, ResponseInterface $response) : ResponseInterface
{
// your controller code
return $response;
}
Flex uses a reference to lookup each middleware and controller function that you add to the stack. These references are generally either callable functions or keys to invokeavble classes in the dependency injection container, but more types are supported. Here are some examples.
Container Class Invoke
class Controller
{
public function __invoke(ServerRequestInterface $request, ResponseInterface $response) : ResponseInterface {
return $response;
};
}
$container->set('controller', new Controller());
$reference = 'controller';
Container Class Method
class Controller
{
public function run(ServerRequestInterface $request, ResponseInterface $response) : ResponseInterface {
return $response;
};
}
$container->set('controller', new Controller());
$reference = 'controller::run';
Anonymous Function
$reference = function (ServerRequestInterface $request, ResponseInterface $response) : ResponseInterface {
return $response;
};
Object Invoke
class Controller
{
public function __invoke(ServerRequestInterface $request, ResponseInterface $response) : ResponseInterface {
return $response;
};
}
$reference = [new Controller()];
Object Method Callable
class Controller
{
public function run(ServerRequestInterface $request, ResponseInterface $response) : ResponseInterface {
return $response;
};
}
$reference = [new Controller(), 'run'];
Static Method Callable
class Controller
{
public function run(ServerRequestInterface $request, ResponseInterface $response) : ResponseInterface {
return $response;
};
}
$reference = [Controller::class, 'run'];
The following configuration values are available.
debug
routes
middleware