# InforRoutes A simple and dependency free routing system providing: - Non blocking dispatch of system `WEB` and `CLI` functionalities - Parameters detection on the URL segments - Route grouping based on namespaces - Error handling and 404 detection - Attachable and global middlewares ## Usage ### Installation First install the package with `composer require inforsistemas/routes`. You might need to add a custom repository on the composer.json ```json "repositories": [{ "type": "composer", "url": "https://satis.domain.com" }], ``` #### Hello World With the dependencies and the server with the correct configuration, create a index.php with the content ```php submit(); ``` ### Registering routes #### The simple API to register routes ```php notBlock()->doIgnore(); ``` **This snippet create menus and submenus** ```php ", ['class' => 'nav-link'] ); }, -11)->doIgnore(); RouteCollection::get('*', function () { Output::addOnSubmenu('menuname', '/url', 'SubItem name', "", ['class' => 'nav-link']); }, -10)->doIgnore(); ``` ## Routes Properties The routes can have some properties configured on them. This section will Describe them ### Blocking The routing system will iterate over all the registered routes, when a Route is matched and it's not configured to block the execution, more routes on the chain might match and be executed. The default behavior of a Route is **TO BLOCK** the executions when it is executed, but this behavior can be changed with the `notBlock()` method ```php notBlock(); ``` ### Ignore If during the Routing process, the library didn't match any Route, a fallback `404` route will be executed. If you want a specific Route not to count on this process, you can ignore it with the function `doIgnore()`. The default behavior of routese is to **NOT IGNORE** the route. Routes with this property assigned, will not prevent a `404` code. It is usefull for Setup/Service Routes. ```php doIgnore(); ``` ### Weight When adding a Route, you can define it's weight. Before dispatching the routing process, the route set will be sorted and the routes will be checked on the specified order. The library will execute all routes until it get blocked, so the Route order might matter on the execution. The weight is the third argument on `get|post|put|patch|delete` functions and the fouth on the `add` method. You can also mannually define the weight with the `setWeight(int $weight)` function. ```php setWeight(-1); ``` ### Name (#ToDo) You can name your routes with the `name(string $name)` function ```php name('routeName'); ``` ### Tag (#ToDo) You can tag your routes with the `setTag(string|array $key, string $value)` function ```php setTag('group', 'value'); // Not implemented yet RouteCollection::get("*", function () { })->setTag( [ ['group', "value1"], ["group2", "value2"] ] ); ``` ## Middlewares The library provides a simple Middleware functionality. You can register * Named Middlewares * AdHock Middlewares * Global Middlewares This middlewares can be attached or removed from the Routes ### General Middlewares A general Middlewares can be created with the API `RouteCollection::registerMiddleware(string $name, callable $function)` and will be stored as available on the `RouteCollection` Singleton. ```php middlewareAdd("myMiddleware", Array("someValue")); // #ToDo - Group Middlewares are not receaving parameters RouteCollection::group("/group", function(){ })->middlewareAdd("myMiddleware", Array("someValue")); ``` ### AdHock Middlewares You can simply attach a function to be executed before the Route/Group execute with the `middlewareAppend(string $name, callable $callback)` function ```php middlewareAppend("myMiddleware", Array("someValue")); // #ToDo Refactor the middleware API for the RouteGroup RouteCollection::group("/group", function(){ })->middlewareAppend("myMiddleware", Array("someValue")); ``` ### Default Middleware Default middlewares can be registered on the `RouteCollection` with the function `addDefaultMiddleware(string $name, callable $function)` Singleton and will be executed before all Routes ```php middlewareIgnore("auth"); ``` ## Extending functionality This library allows you to change and customize some behaviors ### Content Parser This librar has as default the return types for the Routes * `string` (Raw print the content) * `Array` (JSON Encode The Return) * `stdClass|object|mixed` (JSON Encode The Return) But you can extend this functionality to process a return type in a customizible way with the API `RouteCollection::addParser(string $type, callable $function)` ```php get()); }); ``` ### Object Spawners The functions called by the Routing system might have a Data Type defined as a parameter. With the spawners, you can configure how this Objects will be created and passed prepared to the target function. With the default Behavior, in order, we grab the function parameters, match with the variable segments of the URL and instanciate a object from the defined type passing the URI parameter as the __construct main parameter ## Server configuration #### Requirements The following packages need to be installed for the project to run * Apache - apache2 phpX.X phpX.X-fpm libapache2-mod-phpX.X * Nginx - nginx phpX.X phpX.X-fpm The ports `80` and `443` must be open: `ufw allow 80 && ufw allow 443` #### Apache For apache, the basic required configuration ``` ServerAdmin webmaster@localhost DocumentRoot /var/www/html/public ServerName example.com Options Indexes FollowSymLinks MultiViews AllowOverride All Order allow,deny Allow from all ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined ``` For a server with HTTPs, the configuration with redirection ``` ServerName example.com Redirect / https://example.com ServerAdmin webmaster@localhost DocumentRoot /var/www/html/public ServerName urfat.com.br ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined SSLCertificateFile /etc/letsencrypt/live/example.com.br/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/example.com.br/privkey.pem Include /etc/letsencrypt/options-ssl-apache.conf ``` #### Nginx *For Nginx,this is the basic required configuration with PHP-FPM* ``` server { listen 82 default_server; listen [::]:82 default_server; server_name example.com; root /var/www/html/public; index index.php index.html index.htm index.nginx-debian.html; server_name localhost; location / { try_files $uri $uri/ /index.php$is_args$args; } location ~ \.php$ { include snippets/fastcgi-php.conf; #Check fpm-version fastcgi_pass unix:/run/php/php7.2-fpm.sock; } location ~ /\.ht { deny all; } } ``` For a server with HTTPs, the configuration with redirection ``` server { listen 80; listen [::]:80; listen 443 default_server ssl; server_name example.com; ssl_certificate /path/to/my/cert; ssl_certificate_key /path/to/my/key; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers "ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS:!AES256"; ssl_prefer_server_ciphers on; ssl_dhparam /path/to/my/dhp-4096.pem #sudo openssl dhparam -out /path/to/my/dhp-4096.pem 4096 if ($scheme = http) { return 301 https://$server_name$request_uri; } } ``` ## Inner workings The package consist in 3 main files, with `RouteCollection.php` providing the main API - `RouteCollection.php` => Aggregate all routes and provide a interface to interact with the routes dataset - `RouteGroup.php` => Aggregate a group of routes based on their namespaces - `Route.php` => Stores each route information The class `RouteCollection` is treated as a Singleton that return it's own global instance when loaded. The main interface would be something like: `RouteCollection::add($verb, $uri, $callback, $weight = 0)`, this method will return the instance of the `Route` object, so that the Route properties can be chained ## Other resources https://stackoverflow.com/questions/8054165/using-put-method-in-html-form