webx / routes
Requires
- defuse/php-encryption: ^2.2
- webx/ioc: 2.0.0
Requires (Dev)
- php: >=5.5.0
- phpunit/phpunit: 4.8.16
- twig/twig: v1.24.0
Suggests
- twig/twig: For template views
- dev-master
- 2.0.14
- 2.0.13
- 2.0.12
- 2.0.11
- 2.0.10
- 2.0.9
- 2.0.8
- 2.0.7
- 2.0.6
- 2.0.5
- 2.0.4
- 2.0.3
- 2.0.2
- 2.0.1
- 2.0.0
- 0.6.9
- 0.6.8
- 0.6.7
- 0.6.6
- 0.6.5
- 0.6.4
- 0.6.3
- 0.6.2
- 0.6.1
- 0.6.0
- 0.5.11
- 0.5.10
- 0.5.9
- 0.5.8
- 0.5.7
- 0.5.6
- 0.5.5
- 0.5.4
- 0.5.3
- 0.5.2
- 0.5.1
- 0.5.0
- 0.4.11
- 0.4.10
- 0.4.9
- 0.4.8
- 0.4.7
- 0.4.6
- 0.4.5
- 0.4.4
- 0.4.3
- 0.4.2
- 0.4.1
- 0.4.0
- 0.3.11
- 0.3.10
- 0.3.9
- 0.3.8
- 0.3.7
- 0.3.6
- 0.3.5
- 0.3.4
- 0.3.3
- 0.3.2
- 0.3.1
- 0.3.0
- 0.2.0
- 0.1.2
- 0.1.1
- 0.1.0
- dev-rework
This package is not auto-updated.
Last update: 2024-11-09 19:51:05 UTC
README
Main features and design goals of webx-routes:
- Simplicity - Easy to follow request/response routes to business logic in a natural hierarchical model.
- Scalability - never load unnecessary files
- Dependency injection (IOC) everywhere.
- Testability - clear separation of view- and business objects by glueing it all together.
Getting started
In composer.json
add:
{ "require" : { "webx/routes" : "major.minor.patch" } }
Writing your first Routes index.php public/index.php
use WebX\Routes\Api\RoutesBootstrap; use WebX\Routes\Api\Response; require_once "../vendor/autoload.php"; // $_SERVER["DOCUMENT_ROOT"] points to 'public' folder. RoutesBootstrap::run(function(Response $response) { $response->typeJson([ "user" => ["name" => "Mr. Andersson"] ] ]); $response->data(1998,"user.popular"); //Merges the data into 'user.popular' });
Will generate JSON response:
{ "user" : { "name" => "Mr. Andersson", "popular" => 1998 } }
Built-in ResponseTypes in Routes
Routes supports the following ResponseTypes out of the box
JsonResponse
Renders data as Json (Default ResponseType).TemplateResponseType
Renders data with a template (Twig)RawResponseType
Renders data as is.DownloadResponseType
Renders data as a downloadable file.RedirectResponseType
301 or 302 redirect to a different url.FileContentResponseType
Sends a file's content to browser with auto detecting content-type.
Routing in Routes
use WebX\Routes\Api\RoutesBootstrap; use WebX\Routes\Api\Routes; use WebX\Routes\Api\Response; RoutesBootstrap::run(function(Routes $routes) { $routes->onSegment("api",function(Routes $routes) { $routes->onMatch("v(?P<version>\d+)$",function(Routes $routes,$version) { $routes->load("api_v{$version}"); // $version from RegExp })->onAlways(Response $response) { $response->typeJson(["message"=>"Not a valid API call"]); }); })->onAlways(function(Response $response){ $response->typeRaw(); $response->data("Sorry, page not found."); $response->status(404); }) });
Routing in Routes - with url parameters example
use WebX\Routes\Api\RoutesBootstrap; use WebX\Routes\Api\Routes; use WebX\Routes\Api\Response; RoutesBootstrap::run(function(Routes $routes) { $routes->onAlways(function(Response $response, $myParam="default") { $response->typeRaw($myParam); } });
Will render:
hello
for request on/hello
default
for request on/
Route switches:
Route switches are evaluated top-down. If a route-switch is executed no further switches, in same the scope, are evaluated and executed.
The following route switches are supported
onAlways($action)
Executes without evaluation.onTrue($expression,$action)
Executes if$expression
evaluates totrue
onSegment("url-segment",$action)
Evaluates the current url segment (complete url exploded by/
). Within a route-switch match the current url-segment will advance one position.onMatch("reg-exp",$action)
Evaluates the reg-exp against a string (url is default). Matched parameters in the reg-exp will be used if the same variable name is used in the$action
;
Using Twig
page.twig
<html> <body> <h1>Welcome {{user.name}}</h1> Your input was {{input}} </body> </html>
use WebX\Routes\Api\RoutesBootstrap; use WebX\Routes\Api\Response; use WebX\Routes\Api\Request; RoutesBootstrap::run(function(Response $response, Request $request) { $response->typeTemplate()->id("page"); $response->data(["name"=>"Mr. Andersson"],"user"); $response->data($request->parameter("input"), "input"); });
Reading input
Routes provides a unified and type-safe way to read request input from query parameters and json- form-encoded requests.
use WebX\Routes\Api\RoutesBootstrap; use WebX\Routes\Api\Response; use WebX\Routes\Api\Request; RoutesBootstrap::run(function(Response $response, Request $request) { $reader = $request->reader(Request::INPUT_AS_JSON); $response->typeJson(["greeting"=>"Hello, {$reader->asString("user.name")}"]); });
Configuring Twig
Load a configuration changetwig
(can be any name) at Bootstrap time.
Example: To change Twigs tag-delimeters to {{{
and }}}
(To simplify mixed Angular and Twig in the same page).
use WebX\Routes\Api\RoutesBootstrap; use WebX\Routes\Api\Routes; use WebX\Routes\Api\Response; RoutesBootstrap::run([function(Routes $routes) { $routes->onAlways(function(Response $response) { $response->templateType()->id("page"); $response->data(["name"=>"Mr. Andersson"],"user"); }) },"changetwig"]);
Override the setting for TemplateResponseType
to add a configurator for Twig
config/changetwig.php
:
return [ "responseTypes" => [ "WebX\\Routes\\Api\\ResponseTypes\\TemplateResponseType" => [ "config" => [ "configurator" => function(Twig_Environment $twig) { $lexer = new Twig_Lexer($twig, array( 'tag_variable' => array('{{{', '}}}') )); $twig->setLexer($lexer); }, "options" => [ // Passed as second argument to Twig_Environment "cache" => "/tmp/twig_cache" ] ] ] ] ]
Loading configurations and the IOC container
All logic, in Routes, is executed in actions
. An action can be either a:
\Closure
string
(In format "ControllerClass#method")
To support lazy loading of configurations Routes allows actions to be defined as an array
in the format:
[$action,"config1","config2","configN"]
src/MyBusiness/Impl/Services/AdminService.php
use MyBusiness\Api\Services\IAdminService; class AdminService implements IAdminService { public function __construct() {} public function countAdmins() { return 3; } }
config/admin.php
:
use MyBusiness\Impl\Services\AdminService; return [ "ioc" => [ "register" => [ [AdminService::class] ] ] ]
use WebX\Routes\Api\RoutesBootstrap; use WebX\Routes\Api\Routes; use WebX\Routes\Api\Response; use MyBusiness\Api\Services\IAdminService; RoutesBootstrap::run(function(Routes $routes) { $routes->onSegment("admin",[function(Response $response, IAdminService $adminService) { $response->data($adminService->countAdmins(),"count"); },"admin"]); // The admin-configuration is only loaded if routes matched the `admin` segment. });
#Config file anatomy
The config files, that may be loaded at any level, are normal php files that are expected to return an array
.
Minimal config file (that does nothing):
<?php return []; ?>
Ioc container
The WebX-Ioc container is embedded in the WebX-Routes framework. WebX-Routes supports dynamic registration / static invokation of services in the config ioc
section.
Dynamically register a service with the WebX-Ioc container.
config/someconfig.php
<?php return [ "ioc" => [ "register" => [ // The classes will be scanned for all their implemented interfaces. [MyClass:class], [MyOtherClass:class] ], "initStatic" => [ // [MyValueObject::class,"initMethod"] // The static "initMethod" will be invoked with declared dependencies. ] ], "mappings" => [ "closureParameterName" => "iocInstanceId" ] ]
#Working with Controllers Routes support a more traditional controller structure as well. Controllers are simple classes with their methods and constructors invoked with IOC support.
Routes supports $action
to be defined as a string
in the format ControllerClass#method
use WebX\Routes\Api\RoutesBootstrap; use WebX\Routes\Api\Routes; RoutesBootstrap::run(function(Routes $routes) { $routes->onSegment("admin",['MyBusiness\\Controllers\\AdminCtrl','adminConfig'] // The admin-configuration is only loaded if routes matched the `admin` segment. Methods on the // controller will automatically be mapped by the next available segment // If no next segment exist Routes will map the request to `index()` of the controller instance });
src/MyBusiness/Controllers/AdminController.php
namespace MyBusiness\Controllers; class AdminController { private $logService; public function __construct(ILogService $logService) { $this->logService = $logService; } public function countAdmins(Response $response, RawResponseType $responseType, IAdminService $adminService) { $response->type($responseType); $response->data("Hello there " + $adminService->countAdmins() + " admin(s)"); } } #Controller functions can be invoked with user parameters. Parameters, taking precedence over IOC injected ones, #can be defined in the last arguemnt `$parameters` array or with parametes defiend in the `onMatch` switch.
Defining default namespaces for loading controllers
Full class names can be skipped by adding namespaces in the namespaces
section of a dynamic configuration.
config/admin.php
:
return [ "namespaces" => ["MyBusiness\\Controllers"] ]
Creating your own ResponseType
To implement your own ResponseType simply create an interface that extends ResponseType
with an implementation configure it with ioc/register
in a config file. See bootstrap_config.php
of how to configure.
Configuring your own ResponseType
in your config file:
return [
"responseTypes" => [
"YourNamespace\\YourResponseTypeInterface" => [
"class" => "YourNamespace\\YourResponseTypeClass",
"config" => [
"yourSetting" => false // Will be available by Configuration to ResponseType.
]
]
]
]
Configuring Routes
Standard configuration in Routes is based on the applications directory relativly to the $_SERVER['DOCUMENT_ROOT']
.
Configuring RoutesBootstrap
RoutesBootstrap::run($action,[ "home" => "../" // Default. // Use '/' to have application in same directory // as public files (not recommended). ]);
The default directory structure for a Routes application:
/
/config (Config files loaded by [$action, "someconfig"]
someconfig.php
/routes (Files loaded by Routes->load("someroute")
someroute.php
/templates (Templates loaded by TemplateResponse->setTemplate("sometemplate")
sometemplate.twig
/public ($_SERVER['DOCUMENT_ROOT'])
index.php
/vendor (Composer)
/webx
/routes
/ioc
Tests
Execute in root directory
phpunit -c tests