Merge pull request #6969 from MrPetovan/task/router
Add rule-based router
This commit is contained in:
commit
f69d73b5ff
|
@ -13,6 +13,7 @@ Version 2019.06 (UNRELEASED) (2019-06-?)
|
||||||
Added syslog and stream Logger [nupplaphil]
|
Added syslog and stream Logger [nupplaphil]
|
||||||
Added storage move cronjob [MrPetovan]
|
Added storage move cronjob [MrPetovan]
|
||||||
Added collapsible panel for connector permission fields [MrPetovan]
|
Added collapsible panel for connector permission fields [MrPetovan]
|
||||||
|
Added rule-based router [MrPetovan]
|
||||||
|
|
||||||
Closed Issues:
|
Closed Issues:
|
||||||
6303, 6478, 6319, 6921, 6903, 6943
|
6303, 6478, 6319, 6921, 6903, 6943
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
"michelf/php-markdown": "^1.7",
|
"michelf/php-markdown": "^1.7",
|
||||||
"mobiledetect/mobiledetectlib": "2.8.*",
|
"mobiledetect/mobiledetectlib": "2.8.*",
|
||||||
"monolog/monolog": "^1.24",
|
"monolog/monolog": "^1.24",
|
||||||
|
"nikic/fast-route": "^1.3",
|
||||||
"paragonie/random_compat": "^2.0",
|
"paragonie/random_compat": "^2.0",
|
||||||
"pear/text_languagedetect": "1.*",
|
"pear/text_languagedetect": "1.*",
|
||||||
"psr/container": "^1.0",
|
"psr/container": "^1.0",
|
||||||
|
|
104
composer.lock
generated
104
composer.lock
generated
|
@ -4,7 +4,7 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "8897c1f6912cc9b889534a8c59deead1",
|
"content-hash": "cf9846983bd7e4eb34f93ab6b493736b",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "asika/simple-console",
|
"name": "asika/simple-console",
|
||||||
|
@ -887,6 +887,52 @@
|
||||||
],
|
],
|
||||||
"time": "2018-11-05T09:00:11+00:00"
|
"time": "2018-11-05T09:00:11+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "nikic/fast-route",
|
||||||
|
"version": "v1.3.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/nikic/FastRoute.git",
|
||||||
|
"reference": "181d480e08d9476e61381e04a71b34dc0432e812"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/nikic/FastRoute/zipball/181d480e08d9476e61381e04a71b34dc0432e812",
|
||||||
|
"reference": "181d480e08d9476e61381e04a71b34dc0432e812",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.4.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^4.8.35|~5.7"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"FastRoute\\": "src/"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"src/functions.php"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"BSD-3-Clause"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Nikita Popov",
|
||||||
|
"email": "nikic@php.net"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Fast request router for PHP",
|
||||||
|
"keywords": [
|
||||||
|
"router",
|
||||||
|
"routing"
|
||||||
|
],
|
||||||
|
"time": "2018-02-13T20:26:39+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "npm-asset/cropperjs",
|
"name": "npm-asset/cropperjs",
|
||||||
"version": "1.2.2",
|
"version": "1.2.2",
|
||||||
|
@ -1083,22 +1129,6 @@
|
||||||
"require": {
|
"require": {
|
||||||
"npm-asset/ev-emitter": ">=1.0.0,<2.0.0"
|
"npm-asset/ev-emitter": ">=1.0.0,<2.0.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
|
||||||
"npm-asset/chalk": ">=1.1.1,<2.0.0",
|
|
||||||
"npm-asset/cheerio": ">=0.19.0,<0.20.0",
|
|
||||||
"npm-asset/gulp": ">=3.9.0,<4.0.0",
|
|
||||||
"npm-asset/gulp-jshint": ">=1.11.2,<2.0.0",
|
|
||||||
"npm-asset/gulp-json-lint": ">=0.1.0,<0.2.0",
|
|
||||||
"npm-asset/gulp-rename": ">=1.2.2,<2.0.0",
|
|
||||||
"npm-asset/gulp-replace": ">=0.5.4,<0.6.0",
|
|
||||||
"npm-asset/gulp-requirejs-optimize": "dev-github:metafizzy/gulp-requirejs-optimize",
|
|
||||||
"npm-asset/gulp-uglify": ">=1.4.2,<2.0.0",
|
|
||||||
"npm-asset/gulp-util": ">=3.0.7,<4.0.0",
|
|
||||||
"npm-asset/highlight.js": ">=8.9.1,<9.0.0",
|
|
||||||
"npm-asset/marked": ">=0.3.5,<0.4.0",
|
|
||||||
"npm-asset/minimist": ">=1.2.0,<2.0.0",
|
|
||||||
"npm-asset/transfob": ">=1.0.0,<2.0.0"
|
|
||||||
},
|
|
||||||
"type": "npm-asset-library",
|
"type": "npm-asset-library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"npm-asset-bugs": {
|
"npm-asset-bugs": {
|
||||||
|
@ -1144,14 +1174,6 @@
|
||||||
"reference": null,
|
"reference": null,
|
||||||
"shasum": "2736e332aaee73ccf0a14a5f0066391a0a13f4a3"
|
"shasum": "2736e332aaee73ccf0a14a5f0066391a0a13f4a3"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
|
||||||
"npm-asset/grunt": "~0.4.2",
|
|
||||||
"npm-asset/grunt-contrib-cssmin": "~0.9.0",
|
|
||||||
"npm-asset/grunt-contrib-jshint": "~0.6.3",
|
|
||||||
"npm-asset/grunt-contrib-less": "~0.11.0",
|
|
||||||
"npm-asset/grunt-contrib-uglify": "~0.4.0",
|
|
||||||
"npm-asset/grunt-contrib-watch": "~0.6.1"
|
|
||||||
},
|
|
||||||
"type": "npm-asset-library",
|
"type": "npm-asset-library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"npm-asset-bugs": {
|
"npm-asset-bugs": {
|
||||||
|
@ -1185,32 +1207,6 @@
|
||||||
"reference": null,
|
"reference": null,
|
||||||
"shasum": "2c89d6889b5eac522a7eea32c14521559c6cbf02"
|
"shasum": "2c89d6889b5eac522a7eea32c14521559c6cbf02"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
|
||||||
"npm-asset/commitplease": "2.0.0",
|
|
||||||
"npm-asset/core-js": "0.9.17",
|
|
||||||
"npm-asset/grunt": "0.4.5",
|
|
||||||
"npm-asset/grunt-babel": "5.0.1",
|
|
||||||
"npm-asset/grunt-cli": "0.1.13",
|
|
||||||
"npm-asset/grunt-compare-size": "0.4.0",
|
|
||||||
"npm-asset/grunt-contrib-jshint": "0.11.2",
|
|
||||||
"npm-asset/grunt-contrib-uglify": "0.9.2",
|
|
||||||
"npm-asset/grunt-contrib-watch": "0.6.1",
|
|
||||||
"npm-asset/grunt-git-authors": "2.0.1",
|
|
||||||
"npm-asset/grunt-jscs": "2.1.0",
|
|
||||||
"npm-asset/grunt-jsonlint": "1.0.4",
|
|
||||||
"npm-asset/grunt-npmcopy": "0.1.0",
|
|
||||||
"npm-asset/gzip-js": "0.3.2",
|
|
||||||
"npm-asset/jsdom": "5.6.1",
|
|
||||||
"npm-asset/load-grunt-tasks": "1.0.0",
|
|
||||||
"npm-asset/qunit-assert-step": "1.0.3",
|
|
||||||
"npm-asset/qunitjs": "1.17.1",
|
|
||||||
"npm-asset/requirejs": "2.1.17",
|
|
||||||
"npm-asset/sinon": "1.10.3",
|
|
||||||
"npm-asset/sizzle": "2.2.1",
|
|
||||||
"npm-asset/strip-json-comments": "1.0.3",
|
|
||||||
"npm-asset/testswarm": "1.1.0",
|
|
||||||
"npm-asset/win-spawn": "2.0.0"
|
|
||||||
},
|
|
||||||
"type": "npm-asset-library",
|
"type": "npm-asset-library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"npm-asset-bugs": {
|
"npm-asset-bugs": {
|
||||||
|
@ -1361,12 +1357,6 @@
|
||||||
"reference": null,
|
"reference": null,
|
||||||
"shasum": "06f0335f16e353a695e7206bf50503cb523a6ee5"
|
"shasum": "06f0335f16e353a695e7206bf50503cb523a6ee5"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
|
||||||
"npm-asset/grunt": "~0.4.1",
|
|
||||||
"npm-asset/grunt-contrib-connect": "~0.5.0",
|
|
||||||
"npm-asset/grunt-contrib-jshint": "~0.7.1",
|
|
||||||
"npm-asset/grunt-contrib-uglify": "~0.2.7"
|
|
||||||
},
|
|
||||||
"type": "npm-asset-library",
|
"type": "npm-asset-library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"npm-asset-bugs": {
|
"npm-asset-bugs": {
|
||||||
|
|
|
@ -433,7 +433,11 @@ For `select`, **field** is:
|
||||||
- [3] (String): Additional help text; Optional, default is none.
|
- [3] (String): Additional help text; Optional, default is none.
|
||||||
- [4] (Array): Associative array of options. Item key is option value, item value is option label; Mandatory.
|
- [4] (Array): Associative array of options. Item key is option value, item value is option label; Mandatory.
|
||||||
|
|
||||||
|
### route_collection
|
||||||
|
Called just before dispatching the router.
|
||||||
|
Hook data is a `\FastRoute\RouterCollector` object that should be used to add addon routes pointing to classes.
|
||||||
|
|
||||||
|
**Notice**: The class whose name is provided in the route handler must be reachable via auto-loader.
|
||||||
|
|
||||||
## Complete list of hook callbacks
|
## Complete list of hook callbacks
|
||||||
|
|
||||||
|
@ -610,6 +614,7 @@ Here is a complete list of all hook callbacks with file locations (as of 24-Sep-
|
||||||
Hook::callAll('load_config');
|
Hook::callAll('load_config');
|
||||||
Hook::callAll('head');
|
Hook::callAll('head');
|
||||||
Hook::callAll('footer');
|
Hook::callAll('footer');
|
||||||
|
Hook::callAll('route_collection');
|
||||||
|
|
||||||
### src/Model/Item.php
|
### src/Model/Item.php
|
||||||
|
|
||||||
|
|
57
src/App.php
57
src/App.php
|
@ -8,8 +8,10 @@ use Detection\MobileDetect;
|
||||||
use DOMDocument;
|
use DOMDocument;
|
||||||
use DOMXPath;
|
use DOMXPath;
|
||||||
use Exception;
|
use Exception;
|
||||||
|
use FastRoute\RouteCollector;
|
||||||
use Friendica\Core\Config\Cache\IConfigCache;
|
use Friendica\Core\Config\Cache\IConfigCache;
|
||||||
use Friendica\Core\Config\Configuration;
|
use Friendica\Core\Config\Configuration;
|
||||||
|
use Friendica\Core\Hook;
|
||||||
use Friendica\Core\Theme;
|
use Friendica\Core\Theme;
|
||||||
use Friendica\Database\DBA;
|
use Friendica\Database\DBA;
|
||||||
use Friendica\Model\Profile;
|
use Friendica\Model\Profile;
|
||||||
|
@ -35,7 +37,6 @@ use Psr\Log\LoggerInterface;
|
||||||
*/
|
*/
|
||||||
class App
|
class App
|
||||||
{
|
{
|
||||||
public $module_loaded = false;
|
|
||||||
public $module_class = null;
|
public $module_class = null;
|
||||||
public $query_string = '';
|
public $query_string = '';
|
||||||
public $page = [];
|
public $page = [];
|
||||||
|
@ -77,6 +78,11 @@ class App
|
||||||
*/
|
*/
|
||||||
private $mode;
|
private $mode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var App\Router
|
||||||
|
*/
|
||||||
|
private $router;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string The App URL path
|
* @var string The App URL path
|
||||||
*/
|
*/
|
||||||
|
@ -172,6 +178,11 @@ class App
|
||||||
return $this->mode;
|
return $this->mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getRouter()
|
||||||
|
{
|
||||||
|
return $this->router;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a stylesheet file path to be included in the <head> tag of every page.
|
* Register a stylesheet file path to be included in the <head> tag of every page.
|
||||||
* Inclusion is done in App->initHead().
|
* Inclusion is done in App->initHead().
|
||||||
|
@ -217,20 +228,22 @@ class App
|
||||||
*
|
*
|
||||||
* @param Configuration $config The Configuration
|
* @param Configuration $config The Configuration
|
||||||
* @param App\Mode $mode The mode of this Friendica app
|
* @param App\Mode $mode The mode of this Friendica app
|
||||||
|
* @param App\Router $router The router of this Friendica app
|
||||||
* @param LoggerInterface $logger The current app logger
|
* @param LoggerInterface $logger The current app logger
|
||||||
* @param Profiler $profiler The profiler of this application
|
* @param Profiler $profiler The profiler of this application
|
||||||
* @param bool $isBackend Whether it is used for backend or frontend (Default true=backend)
|
* @param bool $isBackend Whether it is used for backend or frontend (Default true=backend)
|
||||||
*
|
*
|
||||||
* @throws Exception if the Basepath is not usable
|
* @throws Exception if the Basepath is not usable
|
||||||
*/
|
*/
|
||||||
public function __construct(Configuration $config, App\Mode $mode, LoggerInterface $logger, Profiler $profiler, $isBackend = true)
|
public function __construct(Configuration $config, App\Mode $mode, App\Router $router, LoggerInterface $logger, Profiler $profiler, $isBackend = true)
|
||||||
{
|
{
|
||||||
BaseObject::setApp($this);
|
BaseObject::setApp($this);
|
||||||
|
|
||||||
$this->logger = $logger;
|
|
||||||
$this->config = $config;
|
$this->config = $config;
|
||||||
$this->profiler = $profiler;
|
|
||||||
$this->mode = $mode;
|
$this->mode = $mode;
|
||||||
|
$this->router = $router;
|
||||||
|
$this->profiler = $profiler;
|
||||||
|
$this->logger = $logger;
|
||||||
|
|
||||||
$this->checkBackend($isBackend);
|
$this->checkBackend($isBackend);
|
||||||
$this->checkFriendicaApp();
|
$this->checkFriendicaApp();
|
||||||
|
@ -1247,9 +1260,24 @@ class App
|
||||||
$this->module = "login";
|
$this->module = "login";
|
||||||
}
|
}
|
||||||
|
|
||||||
$privateapps = $this->config->get('config', 'private_addons', false);
|
/*
|
||||||
if (Core\Addon::isEnabled($this->module) && file_exists("addon/{$this->module}/{$this->module}.php")) {
|
* ROUTING
|
||||||
|
*
|
||||||
|
* From the request URL, routing consists of obtaining the name of a BaseModule-extending class of which the
|
||||||
|
* post() and/or content() static methods can be respectively called to produce a data change or an output.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// First we try explicit routes defined in App\Router
|
||||||
|
$this->router->collectRoutes();
|
||||||
|
|
||||||
|
Hook::callAll('route_collection', $this->router->getRouteCollector());
|
||||||
|
|
||||||
|
$this->module_class = $this->router->getModuleClass($this->cmd);
|
||||||
|
|
||||||
|
// Then we try addon-provided modules that we wrap in the LegacyModule class
|
||||||
|
if (!$this->module_class && Core\Addon::isEnabled($this->module) && file_exists("addon/{$this->module}/{$this->module}.php")) {
|
||||||
//Check if module is an app and if public access to apps is allowed or not
|
//Check if module is an app and if public access to apps is allowed or not
|
||||||
|
$privateapps = $this->config->get('config', 'private_addons', false);
|
||||||
if ((!local_user()) && Core\Hook::isAddonApp($this->module) && $privateapps) {
|
if ((!local_user()) && Core\Hook::isAddonApp($this->module) && $privateapps) {
|
||||||
info(Core\L10n::t("You must be logged in to use addons. "));
|
info(Core\L10n::t("You must be logged in to use addons. "));
|
||||||
} else {
|
} else {
|
||||||
|
@ -1257,24 +1285,21 @@ class App
|
||||||
if (function_exists($this->module . '_module')) {
|
if (function_exists($this->module . '_module')) {
|
||||||
LegacyModule::setModuleFile("addon/{$this->module}/{$this->module}.php");
|
LegacyModule::setModuleFile("addon/{$this->module}/{$this->module}.php");
|
||||||
$this->module_class = 'Friendica\\LegacyModule';
|
$this->module_class = 'Friendica\\LegacyModule';
|
||||||
$this->module_loaded = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Controller class routing
|
// Then we try name-matching a Friendica\Module class
|
||||||
if (! $this->module_loaded && class_exists('Friendica\\Module\\' . ucfirst($this->module))) {
|
if (!$this->module_class && class_exists('Friendica\\Module\\' . ucfirst($this->module))) {
|
||||||
$this->module_class = 'Friendica\\Module\\' . ucfirst($this->module);
|
$this->module_class = 'Friendica\\Module\\' . ucfirst($this->module);
|
||||||
$this->module_loaded = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If not, next look for a 'standard' program module in the 'mod' directory
|
/* Finally, we look for a 'standard' program module in the 'mod' directory
|
||||||
* We emulate a Module class through the LegacyModule class
|
* We emulate a Module class through the LegacyModule class
|
||||||
*/
|
*/
|
||||||
if (! $this->module_loaded && file_exists("mod/{$this->module}.php")) {
|
if (!$this->module_class && file_exists("mod/{$this->module}.php")) {
|
||||||
LegacyModule::setModuleFile("mod/{$this->module}.php");
|
LegacyModule::setModuleFile("mod/{$this->module}.php");
|
||||||
$this->module_class = 'Friendica\\LegacyModule';
|
$this->module_class = 'Friendica\\LegacyModule';
|
||||||
$this->module_loaded = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The URL provided does not resolve to a valid module.
|
/* The URL provided does not resolve to a valid module.
|
||||||
|
@ -1286,7 +1311,7 @@ class App
|
||||||
*
|
*
|
||||||
* Otherwise we are going to emit a 404 not found.
|
* Otherwise we are going to emit a 404 not found.
|
||||||
*/
|
*/
|
||||||
if (! $this->module_loaded) {
|
if (!$this->module_class) {
|
||||||
// Stupid browser tried to pre-fetch our Javascript img template. Don't log the event or return anything - just quietly exit.
|
// Stupid browser tried to pre-fetch our Javascript img template. Don't log the event or return anything - just quietly exit.
|
||||||
if (!empty($_SERVER['QUERY_STRING']) && preg_match('/{[0-9]}/', $_SERVER['QUERY_STRING']) !== 0) {
|
if (!empty($_SERVER['QUERY_STRING']) && preg_match('/{[0-9]}/', $_SERVER['QUERY_STRING']) !== 0) {
|
||||||
exit();
|
exit();
|
||||||
|
@ -1310,7 +1335,7 @@ class App
|
||||||
$content = '';
|
$content = '';
|
||||||
|
|
||||||
// Initialize module that can set the current theme in the init() method, either directly or via App->profile_uid
|
// Initialize module that can set the current theme in the init() method, either directly or via App->profile_uid
|
||||||
if ($this->module_loaded) {
|
if ($this->module_class) {
|
||||||
$this->page['page_title'] = $this->module;
|
$this->page['page_title'] = $this->module;
|
||||||
$placeholder = '';
|
$placeholder = '';
|
||||||
|
|
||||||
|
@ -1336,7 +1361,7 @@ class App
|
||||||
$func($this);
|
$func($this);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->module_loaded) {
|
if ($this->module_class) {
|
||||||
if (! $this->error && $_SERVER['REQUEST_METHOD'] === 'POST') {
|
if (! $this->error && $_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
Core\Hook::callAll($this->module . '_mod_post', $_POST);
|
Core\Hook::callAll($this->module . '_mod_post', $_POST);
|
||||||
call_user_func([$this->module_class, 'post']);
|
call_user_func([$this->module_class, 'post']);
|
||||||
|
|
83
src/App/Router.php
Normal file
83
src/App/Router.php
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Friendica\App;
|
||||||
|
|
||||||
|
|
||||||
|
use FastRoute\DataGenerator\GroupCountBased;
|
||||||
|
use FastRoute\Dispatcher;
|
||||||
|
use FastRoute\RouteCollector;
|
||||||
|
use FastRoute\RouteParser\Std;
|
||||||
|
use Friendica\Module;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper for FastRoute\Router
|
||||||
|
*
|
||||||
|
* This wrapper only makes use of a subset of the router features, mainly parses a route rule to return the relevant
|
||||||
|
* module class.
|
||||||
|
*
|
||||||
|
* Actual routes are defined in App->collectRoutes.
|
||||||
|
*
|
||||||
|
* @package Friendica\App
|
||||||
|
*/
|
||||||
|
class Router
|
||||||
|
{
|
||||||
|
/** @var RouteCollector */
|
||||||
|
protected $routeCollector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static declaration of Friendica routes.
|
||||||
|
*
|
||||||
|
* Supports:
|
||||||
|
* - Route groups
|
||||||
|
* - Variable parts
|
||||||
|
* Disregards:
|
||||||
|
* - HTTP method other than GET
|
||||||
|
* - Named parameters
|
||||||
|
*
|
||||||
|
* Handler must be the name of a class extending Friendica\BaseModule.
|
||||||
|
*
|
||||||
|
* @brief Static declaration of Friendica routes.
|
||||||
|
*/
|
||||||
|
public function collectRoutes()
|
||||||
|
{
|
||||||
|
$this->routeCollector->addRoute(['GET', 'POST'], '/itemsource[/{guid}]', Module\Itemsource::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __construct(RouteCollector $routeCollector = null)
|
||||||
|
{
|
||||||
|
if (!$routeCollector) {
|
||||||
|
$routeCollector = new RouteCollector(new Std(), new GroupCountBased());
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->routeCollector = $routeCollector;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRouteCollector()
|
||||||
|
{
|
||||||
|
return $this->routeCollector;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the relevant module class name for the given page URI or NULL if no route rule matched.
|
||||||
|
*
|
||||||
|
* @param string $cmd The path component of the request URL without the query string
|
||||||
|
* @return string|null A Friendica\BaseModule-extending class name if a route rule matched
|
||||||
|
*/
|
||||||
|
public function getModuleClass($cmd)
|
||||||
|
{
|
||||||
|
$cmd = '/' . ltrim($cmd, '/');
|
||||||
|
|
||||||
|
$dispatcher = new \FastRoute\Dispatcher\GroupCountBased($this->routeCollector->getData());
|
||||||
|
|
||||||
|
$moduleClass = null;
|
||||||
|
|
||||||
|
// @TODO: Enable method-specific modules
|
||||||
|
$httpMethod = 'GET';
|
||||||
|
$routeInfo = $dispatcher->dispatch($httpMethod, $cmd);
|
||||||
|
if ($routeInfo[0] === Dispatcher::FOUND) {
|
||||||
|
$moduleClass = $routeInfo[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $moduleClass;
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,6 +24,7 @@ class DependencyFactory
|
||||||
{
|
{
|
||||||
$basePath = BasePath::create($directory, $_SERVER);
|
$basePath = BasePath::create($directory, $_SERVER);
|
||||||
$mode = new App\Mode($basePath);
|
$mode = new App\Mode($basePath);
|
||||||
|
$router = new App\Router();
|
||||||
$configLoader = new Config\ConfigFileLoader($basePath, $mode);
|
$configLoader = new Config\ConfigFileLoader($basePath, $mode);
|
||||||
$configCache = Factory\ConfigFactory::createCache($configLoader);
|
$configCache = Factory\ConfigFactory::createCache($configLoader);
|
||||||
$profiler = Factory\ProfilerFactory::create($configCache);
|
$profiler = Factory\ProfilerFactory::create($configCache);
|
||||||
|
@ -34,6 +35,6 @@ class DependencyFactory
|
||||||
$logger = Factory\LoggerFactory::create($channel, $config, $profiler);
|
$logger = Factory\LoggerFactory::create($channel, $config, $profiler);
|
||||||
Factory\LoggerFactory::createDev($channel, $config, $profiler);
|
Factory\LoggerFactory::createDev($channel, $config, $profiler);
|
||||||
|
|
||||||
return new App($config, $mode, $logger, $profiler, $isBackend);
|
return new App($config, $mode, $router, $logger, $profiler, $isBackend);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,6 @@ class Itemsource extends \Friendica\BaseModule
|
||||||
|
|
||||||
$conversation = Model\Conversation::getByItemUri($item['uri']);
|
$conversation = Model\Conversation::getByItemUri($item['uri']);
|
||||||
|
|
||||||
$guid = $item['guid'];
|
|
||||||
$item_id = $item['id'];
|
$item_id = $item['id'];
|
||||||
$item_uri = $item['uri'];
|
$item_uri = $item['uri'];
|
||||||
$source = $conversation['source'];
|
$source = $conversation['source'];
|
||||||
|
|
|
@ -50,6 +50,7 @@ class ApiTest extends DatabaseTest
|
||||||
{
|
{
|
||||||
$basePath = BasePath::create(dirname(__DIR__) . '/../');
|
$basePath = BasePath::create(dirname(__DIR__) . '/../');
|
||||||
$mode = new App\Mode($basePath);
|
$mode = new App\Mode($basePath);
|
||||||
|
$router = new App\Router();
|
||||||
$configLoader = new ConfigFileLoader($basePath, $mode);
|
$configLoader = new ConfigFileLoader($basePath, $mode);
|
||||||
$configCache = Factory\ConfigFactory::createCache($configLoader);
|
$configCache = Factory\ConfigFactory::createCache($configLoader);
|
||||||
$profiler = Factory\ProfilerFactory::create($configCache);
|
$profiler = Factory\ProfilerFactory::create($configCache);
|
||||||
|
@ -57,7 +58,7 @@ class ApiTest extends DatabaseTest
|
||||||
$config = Factory\ConfigFactory::createConfig($configCache);
|
$config = Factory\ConfigFactory::createConfig($configCache);
|
||||||
Factory\ConfigFactory::createPConfig($configCache);
|
Factory\ConfigFactory::createPConfig($configCache);
|
||||||
$logger = Factory\LoggerFactory::create('test', $config, $profiler);
|
$logger = Factory\LoggerFactory::create('test', $config, $profiler);
|
||||||
$this->app = new App($config, $mode, $logger, $profiler, false);
|
$this->app = new App($config, $mode, $router, $logger, $profiler, false);
|
||||||
|
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
|
|
||||||
|
|
42
tests/src/App/RouterTest.php
Normal file
42
tests/src/App/RouterTest.php
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Friendica\Test\src\App;
|
||||||
|
|
||||||
|
use Friendica\App\Router;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class RouterTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testGetModuleClass()
|
||||||
|
{
|
||||||
|
$router = new Router();
|
||||||
|
|
||||||
|
$routeCollector = $router->getRouteCollector();
|
||||||
|
$routeCollector->addRoute(['GET'], '/', 'IndexModuleClassName');
|
||||||
|
$routeCollector->addRoute(['GET'], '/test', 'TestModuleClassName');
|
||||||
|
$routeCollector->addRoute(['GET'], '/test/sub', 'TestSubModuleClassName');
|
||||||
|
$routeCollector->addRoute(['GET'], '/optional[/option]', 'OptionalModuleClassName');
|
||||||
|
$routeCollector->addRoute(['GET'], '/variable/{var}', 'VariableModuleClassName');
|
||||||
|
$routeCollector->addRoute(['GET'], '/optionalvariable[/{option}]', 'OptionalVariableModuleClassName');
|
||||||
|
$routeCollector->addRoute(['POST', 'PUT', 'PATCH', 'DELETE', 'HEAD'], '/unsupported', 'UnsupportedMethodModuleClassName');
|
||||||
|
|
||||||
|
$this->assertEquals('IndexModuleClassName', $router->getModuleClass('/'));
|
||||||
|
|
||||||
|
$this->assertEquals('TestModuleClassName', $router->getModuleClass('/test'));
|
||||||
|
$this->assertNull($router->getModuleClass('/tes'));
|
||||||
|
|
||||||
|
$this->assertEquals('TestSubModuleClassName', $router->getModuleClass('/test/sub'));
|
||||||
|
|
||||||
|
$this->assertEquals('OptionalModuleClassName', $router->getModuleClass('/optional'));
|
||||||
|
$this->assertEquals('OptionalModuleClassName', $router->getModuleClass('/optional/option'));
|
||||||
|
$this->assertNull($router->getModuleClass('/optional/opt'));
|
||||||
|
|
||||||
|
$this->assertEquals('VariableModuleClassName', $router->getModuleClass('/variable/123abc'));
|
||||||
|
$this->assertNull($router->getModuleClass('/variable'));
|
||||||
|
|
||||||
|
$this->assertEquals('OptionalVariableModuleClassName', $router->getModuleClass('/optionalvariable'));
|
||||||
|
$this->assertEquals('OptionalVariableModuleClassName', $router->getModuleClass('/optionalvariable/123abc'));
|
||||||
|
|
||||||
|
$this->assertNull($router->getModuleClass('/unsupported'));
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,6 +15,7 @@ class DBATest extends DatabaseTest
|
||||||
{
|
{
|
||||||
$basePath = BasePath::create(dirname(__DIR__) . '/../../');
|
$basePath = BasePath::create(dirname(__DIR__) . '/../../');
|
||||||
$mode = new App\Mode($basePath);
|
$mode = new App\Mode($basePath);
|
||||||
|
$router = new App\Router();
|
||||||
$configLoader = new ConfigFileLoader($basePath, $mode);
|
$configLoader = new ConfigFileLoader($basePath, $mode);
|
||||||
$configCache = Factory\ConfigFactory::createCache($configLoader);
|
$configCache = Factory\ConfigFactory::createCache($configLoader);
|
||||||
$profiler = Factory\ProfilerFactory::create($configCache);
|
$profiler = Factory\ProfilerFactory::create($configCache);
|
||||||
|
@ -22,7 +23,7 @@ class DBATest extends DatabaseTest
|
||||||
$config = Factory\ConfigFactory::createConfig($configCache);
|
$config = Factory\ConfigFactory::createConfig($configCache);
|
||||||
Factory\ConfigFactory::createPConfig($configCache);
|
Factory\ConfigFactory::createPConfig($configCache);
|
||||||
$logger = Factory\LoggerFactory::create('test', $config, $profiler);
|
$logger = Factory\LoggerFactory::create('test', $config, $profiler);
|
||||||
$this->app = new App($config, $mode, $logger, $profiler, false);
|
$this->app = new App($config, $mode, $router, $logger, $profiler, false);
|
||||||
|
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ class DBStructureTest extends DatabaseTest
|
||||||
{
|
{
|
||||||
$basePath = BasePath::create(dirname(__DIR__) . '/../../');
|
$basePath = BasePath::create(dirname(__DIR__) . '/../../');
|
||||||
$mode = new App\Mode($basePath);
|
$mode = new App\Mode($basePath);
|
||||||
|
$router = new App\Router();
|
||||||
$configLoader = new ConfigFileLoader($basePath, $mode);
|
$configLoader = new ConfigFileLoader($basePath, $mode);
|
||||||
$configCache = Factory\ConfigFactory::createCache($configLoader);
|
$configCache = Factory\ConfigFactory::createCache($configLoader);
|
||||||
$profiler = Factory\ProfilerFactory::create($configCache);
|
$profiler = Factory\ProfilerFactory::create($configCache);
|
||||||
|
@ -22,7 +23,7 @@ class DBStructureTest extends DatabaseTest
|
||||||
$config = Factory\ConfigFactory::createConfig($configCache);
|
$config = Factory\ConfigFactory::createConfig($configCache);
|
||||||
Factory\ConfigFactory::createPConfig($configCache);
|
Factory\ConfigFactory::createPConfig($configCache);
|
||||||
$logger = Factory\LoggerFactory::create('test', $config, $profiler);
|
$logger = Factory\LoggerFactory::create('test', $config, $profiler);
|
||||||
$this->app = new App($config, $mode, $logger, $profiler, false);
|
$this->app = new App($config, $mode, $router, $logger, $profiler, false);
|
||||||
|
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue