diff --git a/_build/build.config.php b/_build/build.config.php index 48a93e3..9f05c80 100644 --- a/_build/build.config.php +++ b/_build/build.config.php @@ -6,7 +6,7 @@ define('PKG_NAME', 'FastRouter'); define('PKG_NAME_LOWER', strtolower(PKG_NAME)); -define('PKG_VERSION', '1.0.2'); +define('PKG_VERSION', '1.0.4'); define('PKG_RELEASE', 'pl'); define('PKG_AUTO_INSTALL', true); define('PKG_NAMESPACE_PATH', '{core_path}components/' . PKG_NAME_LOWER . '/'); @@ -14,10 +14,10 @@ /* define paths */ if (isset($_SERVER['MODX_BASE_PATH'])) { define('MODX_BASE_PATH', $_SERVER['MODX_BASE_PATH']); -} elseif (file_exists(realpath(dirname(dirname(__FILE__))) . DS . 'core')) { - define('MODX_BASE_PATH', realpath(dirname(dirname(__FILE__))) . DS); +} elseif (file_exists(realpath(dirname(__DIR__)) . DS . 'core')) { + define('MODX_BASE_PATH', realpath(dirname(__DIR__)) . DS); } else { - define('MODX_BASE_PATH', dirname(dirname(dirname(dirname(__FILE__)))) . '/'); + define('MODX_BASE_PATH', dirname(dirname(dirname(__DIR__))) . '/'); } define('MODX_CORE_PATH', MODX_BASE_PATH . 'core/'); @@ -42,6 +42,6 @@ define('BUILD_SNIPPET_STATIC', false); define('BUILD_PLUGIN_STATIC', false); -$BUILD_RESOLVERS = array( +$BUILD_RESOLVERS = [ 'chunks', -); +]; diff --git a/_build/build.transport.php b/_build/build.transport.php index 22c3aef..e35655a 100644 --- a/_build/build.transport.php +++ b/_build/build.transport.php @@ -4,15 +4,18 @@ $mtime = explode(' ', $mtime); $mtime = $mtime[1] + $mtime[0]; $tstart = $mtime; + set_time_limit(0); -header('Content-Type:text/html;charset=utf-8'); +header('Content-Type: text/html;charset=utf-8'); require_once 'build.config.php'; -/* define sources */ -$root = dirname(dirname(__FILE__)) . '/'; -$sources = array( +/** + * Define sources + */ +$root = dirname(__DIR__) . '/'; +$sources = [ 'root' => $root, 'build' => $root . '_build/', 'data' => $root . '_build/data/', @@ -23,7 +26,7 @@ 'lexicon' => $root . 'core/components/' . PKG_NAME_LOWER . '/lexicon/', 'docs' => $root . 'core/components/' . PKG_NAME_LOWER . '/docs/', 'source_core' => $root . 'core/components/' . PKG_NAME_LOWER, -); +]; unset($root); require_once MODX_CORE_PATH . 'model/modx/modx.class.php'; @@ -35,6 +38,7 @@ $modx->setLogTarget('ECHO'); $modx->getService('error', 'error.modError'); $modx->loadClass('transport.modPackageBuilder', '', false, true); + if (!XPDO_CLI_MODE) { echo '
';
 }
@@ -45,66 +49,86 @@
 
 $modx->log(modX::LOG_LEVEL_INFO, 'Created Transport Package and Namespace.');
 
-/* load system settings */
+/**
+ * Load system settings
+ */
 if (defined('BUILD_SETTING_UPDATE')) {
     $settings = include $sources['data'] . 'transport.settings.php';
+
     if (!is_array($settings)) {
         $modx->log(modX::LOG_LEVEL_ERROR, 'Could not package in settings.');
     } else {
-        $attributes = array(
+        $attributes = [
             xPDOTransport::UNIQUE_KEY => 'key',
             xPDOTransport::PRESERVE_KEYS => true,
             xPDOTransport::UPDATE_OBJECT => BUILD_SETTING_UPDATE,
-        );
+        ];
+
         foreach ($settings as $setting) {
             $vehicle = $builder->createVehicle($setting, $attributes);
             $builder->putVehicle($vehicle);
         }
+
         $modx->log(modX::LOG_LEVEL_INFO, 'Packaged in ' . count($settings) . ' System Settings.');
     }
+
     unset($settings, $setting, $attributes);
 }
 
-/* load plugins events */
+/**
+ * Load plugins events
+ */
 if (defined('BUILD_EVENT_UPDATE')) {
     $events = include $sources['data'] . 'transport.events.php';
+
     if (!is_array($events)) {
         $modx->log(modX::LOG_LEVEL_ERROR, 'Could not package in events.');
     } else {
-        $attributes = array(
+        $attributes = [
             xPDOTransport::PRESERVE_KEYS => true,
             xPDOTransport::UPDATE_OBJECT => BUILD_EVENT_UPDATE,
-        );
+        ];
+
         foreach ($events as $event) {
             $vehicle = $builder->createVehicle($event, $attributes);
             $builder->putVehicle($vehicle);
         }
+
         $modx->log(xPDO::LOG_LEVEL_INFO, 'Packaged in ' . count($events) . ' Plugins events.');
     }
+
     unset ($events, $event, $attributes);
 }
 
-/* create category */
+/**
+ * Create category
+ */
 $modx->log(xPDO::LOG_LEVEL_INFO, 'Created category.');
 /* @var modCategory $category */
 $category = $modx->newObject('modCategory');
 $category->set('category', PKG_NAME);
-/* create category vehicle */
-$attr = array(
+
+/**
+ * Create category vehicle
+ */
+$attr = [
     xPDOTransport::UNIQUE_KEY => 'category',
     xPDOTransport::PRESERVE_KEYS => false,
     xPDOTransport::UPDATE_OBJECT => true,
     xPDOTransport::RELATED_OBJECTS => true,
-);
+];
 
-/* add snippets */
+/**
+ * Add snippets
+ */
 if (defined('BUILD_SNIPPET_UPDATE')) {
-    $attr[xPDOTransport::RELATED_OBJECT_ATTRIBUTES]['Snippets'] = array(
+    $attr[xPDOTransport::RELATED_OBJECT_ATTRIBUTES]['Snippets'] = [
         xPDOTransport::PRESERVE_KEYS => false,
         xPDOTransport::UPDATE_OBJECT => BUILD_SNIPPET_UPDATE,
         xPDOTransport::UNIQUE_KEY => 'name',
-    );
+    ];
     $snippets = include $sources['data'] . 'transport.snippets.php';
+
     if (!is_array($snippets)) {
         $modx->log(modX::LOG_LEVEL_ERROR, 'Could not package in snippets.');
     } else {
@@ -113,14 +137,17 @@
     }
 }
 
-/* add chunks */
+/**
+ * Add chunks
+ */
 if (defined('BUILD_CHUNK_UPDATE')) {
-    $attr[xPDOTransport::RELATED_OBJECT_ATTRIBUTES]['Chunks'] = array(
+    $attr[xPDOTransport::RELATED_OBJECT_ATTRIBUTES]['Chunks'] = [
         xPDOTransport::PRESERVE_KEYS => false,
         xPDOTransport::UPDATE_OBJECT => BUILD_CHUNK_UPDATE,
         xPDOTransport::UNIQUE_KEY => 'name',
-    );
+    ];
     $chunks = include $sources['data'] . 'transport.chunks.php';
+
     if (!is_array($chunks)) {
         $modx->log(modX::LOG_LEVEL_ERROR, 'Could not package in chunks.');
     } else {
@@ -129,19 +156,22 @@
     }
 }
 
-/* add plugins */
+/**
+ * Add plugins
+ */
 if (defined('BUILD_PLUGIN_UPDATE')) {
-    $attr[xPDOTransport::RELATED_OBJECT_ATTRIBUTES]['Plugins'] = array(
+    $attr[xPDOTransport::RELATED_OBJECT_ATTRIBUTES]['Plugins'] = [
         xPDOTransport::PRESERVE_KEYS => false,
         xPDOTransport::UPDATE_OBJECT => BUILD_PLUGIN_UPDATE,
         xPDOTransport::UNIQUE_KEY => 'name',
-    );
-    $attr[xPDOTransport::RELATED_OBJECT_ATTRIBUTES]['PluginEvents'] = array(
+    ];
+    $attr[xPDOTransport::RELATED_OBJECT_ATTRIBUTES]['PluginEvents'] = [
         xPDOTransport::PRESERVE_KEYS => true,
         xPDOTransport::UPDATE_OBJECT => BUILD_PLUGIN_UPDATE,
-        xPDOTransport::UNIQUE_KEY => array('pluginid', 'event'),
-    );
+        xPDOTransport::UNIQUE_KEY => ['pluginid', 'event'],
+    ];
     $plugins = include $sources['data'] . 'transport.plugins.php';
+
     if (!is_array($plugins)) {
         $modx->log(modX::LOG_LEVEL_ERROR, 'Could not package in plugins.');
     } else {
@@ -152,14 +182,16 @@
 
 $vehicle = $builder->createVehicle($category, $attr);
 
-/* now pack in resolvers */
-$vehicle->resolve('file', array(
+/**
+ * Now pack in resolvers
+ */
+$vehicle->resolve('file', [
     'source' => $sources['source_core'],
     'target' => "return MODX_CORE_PATH . 'components/';",
-));
+]);
 
 foreach ($BUILD_RESOLVERS as $resolver) {
-    if ($vehicle->resolve('php', array('source' => $sources['resolvers'] . 'resolve.' . $resolver . '.php'))) {
+    if ($vehicle->resolve('php', ['source' => $sources['resolvers'] . 'resolve.' . $resolver . '.php'])) {
         $modx->log(modX::LOG_LEVEL_INFO, 'Added resolver "' . $resolver . '" to category.');
     } else {
         $modx->log(modX::LOG_LEVEL_INFO, 'Could not add resolver "' . $resolver . '" to category.');
@@ -167,41 +199,46 @@
 }
 
 flush();
+
 $builder->putVehicle($vehicle);
 
-/* now pack in the license file, readme and setup options */
-$builder->setPackageAttributes(array(
+/**
+ * Now pack in the license file, readme and setup options
+ */
+$builder->setPackageAttributes([
     'changelog' => file_get_contents($sources['docs'] . 'changelog.txt'),
     'license' => file_get_contents($sources['docs'] . 'license.txt'),
     'readme' => file_get_contents($sources['docs'] . 'readme.txt'),
     'chunks' => $BUILD_CHUNKS,
-    'setup-options' => array(
+    'setup-options' => [
         'source' => $sources['build'] . 'setup.options.php',
-    ),
-));
+    ],
+]);
 $modx->log(modX::LOG_LEVEL_INFO, 'Added package attributes and setup options.');
 
-/* zip up package */
+/**
+ * Zip up package
+ */
 $modx->log(modX::LOG_LEVEL_INFO, 'Packing up transport package zip...');
 $builder->pack();
 
 $mtime = microtime();
-$mtime = explode(" ", $mtime);
+$mtime = explode(' ', $mtime);
 $mtime = $mtime[1] + $mtime[0];
 $tend = $mtime;
 $totalTime = ($tend - $tstart);
-$totalTime = sprintf("%2.4f s", $totalTime);
+$totalTime = sprintf('%2.4f s', $totalTime);
 
 $signature = $builder->getSignature();
 if (defined('PKG_AUTO_INSTALL') && PKG_AUTO_INSTALL) {
     $sig = explode('-', $signature);
     $versionSignature = explode('.', $sig[1]);
 
-    /* @var modTransportPackage $package */
-    if (!$package = $modx->getObject('transport.modTransportPackage', array('signature' => $signature))) {
+    /** @var modTransportPackage $package */
+    if (!$package = $modx->getObject('transport.modTransportPackage', ['signature' => $signature])) {
         $package = $modx->newObject('transport.modTransportPackage');
         $package->set('signature', $signature);
-        $package->fromArray(array(
+        $package->fromArray([
             'created' => date('Y-m-d h:i:s'),
             'updated' => null,
             'state' => 1,
@@ -212,9 +249,11 @@
             'version_major' => $versionSignature[0],
             'version_minor' => !empty($versionSignature[1]) ? $versionSignature[1] : 0,
             'version_patch' => !empty($versionSignature[2]) ? $versionSignature[2] : 0,
-        ));
+        ]);
+
         if (!empty($sig[2])) {
-            $r = preg_split('/([0-9]+)/', $sig[2], -1, PREG_SPLIT_DELIM_CAPTURE);
+            $r = preg_split('/(\d+)/', $sig[2], -1, PREG_SPLIT_DELIM_CAPTURE);
+
             if (is_array($r) && !empty($r)) {
                 $package->set('release', $r[0]);
                 $package->set('release_index', (isset($r[1]) ? $r[1] : '0'));
@@ -222,6 +261,7 @@
                 $package->set('release', $sig[2]);
             }
         }
+
         $package->save();
     }
 
@@ -229,11 +269,13 @@
         $modx->runProcessor('system/clearcache');
     }
 }
+
 if (!empty($_GET['download'])) {
     echo '';
 }
 
-$modx->log(modX::LOG_LEVEL_INFO, "\n
Execution time: {$totalTime}\n"); +$modx->log(modX::LOG_LEVEL_INFO, "Execution time: {$totalTime}"); + if (!XPDO_CLI_MODE) { echo '
'; } diff --git a/_build/data/transport.chunks.php b/_build/data/transport.chunks.php index ee9b1c3..9f5b6a4 100644 --- a/_build/data/transport.chunks.php +++ b/_build/data/transport.chunks.php @@ -1,22 +1,22 @@ array( +$tmp = [ + 'fastrouter' => [ 'file' => 'fastrouter', 'source' => false, 'description' => '', - ), -); + ], +]; // Save chunks for setup options -$BUILD_CHUNKS = array(); +$BUILD_CHUNKS = []; foreach ($tmp as $k => $v) { /* @avr modChunk $chunk */ $chunk = $modx->newObject('modChunk'); - $chunk->fromArray(array( + $chunk->fromArray([ 'id' => 0, 'name' => $k, 'description' => $v['description'], @@ -24,7 +24,7 @@ 'static' => BUILD_CHUNK_STATIC, 'source' => $v['source'], 'static_file' => 'core/components/' . PKG_NAME_LOWER . '/elements/chunks/chunk.' . $v['file'] . '.tpl', - ), '', true, true); + ], '', true, true); $chunks[] = $chunk; @@ -32,4 +32,5 @@ } unset($tmp); + return $chunks; diff --git a/_build/data/transport.plugins.php b/_build/data/transport.plugins.php index f07551b..8ad083a 100644 --- a/_build/data/transport.plugins.php +++ b/_build/data/transport.plugins.php @@ -1,43 +1,46 @@ array( +$tmp = [ + 'fastrouter' => [ 'file' => 'fastrouter', 'description' => '', - 'events' => array( - 'OnPageNotFound' => array(), - 'OnChunkSave' => array() - ) - ) -); + 'events' => [ + 'OnPageNotFound' => [], + 'OnChunkSave' => [], + ], + ], +]; foreach ($tmp as $k => $v) { /* @avr modplugin $plugin */ $plugin = $modx->newObject('modPlugin'); - $plugin->fromArray(array( + $plugin->fromArray([ 'name' => $k, 'category' => 0, 'description' => $v['description'], 'plugincode' => getSnippetContent($sources['source_core'] . '/elements/plugins/plugin.' . $v['file'] . '.php'), 'static' => BUILD_PLUGIN_STATIC, 'source' => 1, - 'static_file' => 'core/components/' . PKG_NAME_LOWER . '/elements/plugins/plugin.' . $v['file'] . '.php' - ), '', true, true); + 'static_file' => 'core/components/' . PKG_NAME_LOWER . '/elements/plugins/plugin.' . $v['file'] . '.php', + ], '', true, true); - $events = array(); + $events = []; if (!empty($v['events'])) { foreach ($v['events'] as $k2 => $v2) { /* @var modPluginEvent $event */ $event = $modx->newObject('modPluginEvent'); - $event->fromArray(array_merge( - array( + $event->fromArray( + array_merge([ 'event' => $k2, 'priority' => 0, 'propertyset' => 0, - ), $v2 - ), '', true, true); + ], $v2), + '', + true, + true + ); $events[] = $event; } unset($v['events']); @@ -51,4 +54,5 @@ } unset($tmp, $properties); + return $plugins; diff --git a/_build/data/transport.settings.php b/_build/data/transport.settings.php index 758e858..fecaac5 100644 --- a/_build/data/transport.settings.php +++ b/_build/data/transport.settings.php @@ -1,24 +1,27 @@ array( +$tmp = [ + 'paramsKey' => [ 'xtype' => 'textarea', 'value' => 'fastrouter', 'area' => 'general', - ), -); + ], +]; foreach ($tmp as $k => $v) { /* @var modSystemSetting $setting */ $setting = $modx->newObject('modSystemSetting'); - $setting->fromArray(array_merge( - array( + $setting->fromArray( + array_merge([ 'key' => PKG_NAME_LOWER . '.' . $k, 'namespace' => PKG_NAME_LOWER, - ), $v - ), '', true, true); + ], $v), + '', + true, + true + ); $settings[] = $setting; } diff --git a/_build/data/transport.snippets.php b/_build/data/transport.snippets.php index 5d35bd5..3c52492 100644 --- a/_build/data/transport.snippets.php +++ b/_build/data/transport.snippets.php @@ -1,30 +1,31 @@ array( +$tmp = [ + 'fastrouter' => [ 'file' => 'fastrouter', 'source' => true, 'description' => '', - ), -); + ], +]; foreach ($tmp as $k => $v) { /* @avr modSnippet $snippet */ $snippet = $modx->newObject('modSnippet'); - $snippet->fromArray(array( + $snippet->fromArray([ 'id' => 0, 'name' => $k, 'description' => $v['description'], 'snippet' => getSnippetContent($sources['source_core'] . '/elements/snippets/snippet.' . $v['file'] . '.php'), 'static' => BUILD_SNIPPET_STATIC, - 'source' => (bool)$v['source'], + 'source' => (bool) $v['source'], 'static_file' => 'core/components/' . PKG_NAME_LOWER . '/elements/snippets/snippet.' . $v['file'] . '.php', - ), '', true, true); + ], '', true, true); $snippets[] = $snippet; } unset($tmp); + return $snippets; diff --git a/_build/includes/functions.php b/_build/includes/functions.php index 7d7c3fc..ac967ba 100644 --- a/_build/includes/functions.php +++ b/_build/includes/functions.php @@ -1,33 +1,34 @@ ')); } - /** * Recursive directory remove * - * @param $dir + * @param string $dir */ -function rrmdir($dir) { +function rrmdir($dir) +{ if (is_dir($dir)) { - $objects = scandir($dir); + $objects = scandir($dir, SCANDIR_SORT_NONE); foreach ($objects as $object) { - if ($object != "." && $object != "..") { - if (filetype($dir . "/" . $object) == "dir") { - rrmdir($dir . "/" . $object); + if ($object !== '.' && $object !== '..') { + if (filetype($dir . '/' . $object) === 'dir') { + rrmdir($dir . '/' . $object); } else { - unlink($dir . "/" . $object); + unlink($dir . '/' . $object); } } } diff --git a/_build/resolvers/resolve.chunks.php b/_build/resolvers/resolve.chunks.php index 51ecf64..bc30165 100644 --- a/_build/resolvers/resolve.chunks.php +++ b/_build/resolvers/resolve.chunks.php @@ -2,7 +2,7 @@ if ($object->xpdo) { /** @var modX $modx */ - $modx =& $object->xpdo; + $modx = $object->xpdo; switch ($options[xPDOTransport::PACKAGE_ACTION]) { case xPDOTransport::ACTION_INSTALL: @@ -11,17 +11,20 @@ case xPDOTransport::ACTION_UPGRADE: if (!empty($options['chunks']) && !empty($options['update_chunks'])) { foreach ($options['update_chunks'] as $v) { - if (!empty($options['chunks'][$v]) && $chunk = $modx->getObject('modChunk', array('name' => $v))) { + if (!empty($options['chunks'][$v]) && $chunk = $modx->getObject('modChunk', ['name' => $v])) { $chunk->set('snippet', $options['chunks'][$v]); $chunk->save(); - $modx->log(modX::LOG_LEVEL_INFO, 'Updated chunk "' . $v . '"'); + + $modx->log(modX::LOG_LEVEL_INFO, "Updated chunk \"{$v}\""); } } } + break; case xPDOTransport::ACTION_UNINSTALL: break; } } + return true; diff --git a/_build/resolvers/resolve.setup.php b/_build/resolvers/resolve.setup.php index 67b620c..4d879a2 100644 --- a/_build/resolvers/resolve.setup.php +++ b/_build/resolvers/resolve.setup.php @@ -8,7 +8,7 @@ if ($object->xpdo) { /** @var modX $modx */ - $modx =& $object->xpdo; + $modx = $object->xpdo; $success = false; switch ($options[xPDOTransport::PACKAGE_ACTION]) { diff --git a/_build/setup.options.php b/_build/setup.options.php index 7a6e901..ff2a23e 100644 --- a/_build/setup.options.php +++ b/_build/setup.options.php @@ -37,6 +37,7 @@ '; break; + default: $output .= 'Select chunks, which need to overwrite:
diff --git a/core/components/fastrouter/docs/license.txt b/core/components/fastrouter/docs/license.txt index 3656f20..03567f8 100644 --- a/core/components/fastrouter/docs/license.txt +++ b/core/components/fastrouter/docs/license.txt @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2014 Ivan Brezhnev +Copyright (c) 2014-2018 Ivan Brezhnev Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -14,7 +14,7 @@ copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE diff --git a/core/components/fastrouter/elements/plugins/plugin.fastrouter.php b/core/components/fastrouter/elements/plugins/plugin.fastrouter.php index 55edd57..8ac465f 100644 --- a/core/components/fastrouter/elements/plugins/plugin.fastrouter.php +++ b/core/components/fastrouter/elements/plugins/plugin.fastrouter.php @@ -4,7 +4,7 @@ $router = new FastRouter($modx); -if ($router->needDispath()) { +if ($router->needDispatch()) { $router->dispatch(); } elseif ($router->isRoutesChunkUpdated($chunk->name)) { $router->clearCache(); diff --git a/core/components/fastrouter/elements/snippets/snippet.fastrouter.php b/core/components/fastrouter/elements/snippets/snippet.fastrouter.php index 9d4ec93..6bb7b46 100644 --- a/core/components/fastrouter/elements/snippets/snippet.fastrouter.php +++ b/core/components/fastrouter/elements/snippets/snippet.fastrouter.php @@ -1,6 +1,6 @@ getOption('fastrouter.paramsKey', null, 'fastrouter'); -$params = $modx->getOption($key, $scriptProperties, isset($_REQUEST[$key]) ? $_REQUEST[$key] : array()); +$params = $modx->getOption($key, $scriptProperties, isset($_REQUEST[$key]) ? $_REQUEST[$key] : []); return '
' . print_r($params, true) . '
'; diff --git a/core/components/fastrouter/fastrouter.class.php b/core/components/fastrouter/fastrouter.class.php index 156ea68..a333d6b 100644 --- a/core/components/fastrouter/fastrouter.class.php +++ b/core/components/fastrouter/fastrouter.class.php @@ -5,7 +5,12 @@ /** * Class FastRouter */ -class FastRouter { +class FastRouter +{ + const FAST_ROUTER = 'fastrouter'; + const EVENT = 'OnPageNotFound'; + const EVENT_ON_CHUNK_SAVE = 'OnChunkSave'; + /** * Path to routes cache file * @@ -26,14 +31,16 @@ class FastRouter { protected $paramsKey; /** - * FastRouter constructor. + * FastRouter constructor * * @param modX $modx */ - function __construct(modX $modx) { + public function __construct(modX $modx) + { $this->modx = $modx; - $this->cacheFile = $modx->getOption(xPDO::OPT_CACHE_PATH) . 'fastrouter.cache.php'; - $this->paramsKey = $modx->getOption('fastrouter.paramsKey', null, 'fastrouter'); + $this->cacheFile = $modx->getOption(xPDO::OPT_CACHE_PATH) . static::FAST_ROUTER . '.cache.php'; + $this->paramsKey = $modx->getOption(static::FAST_ROUTER . '.paramsKey', null, static::FAST_ROUTER); + $this->registerDispatcher(); } @@ -42,7 +49,8 @@ function __construct(modX $modx) { * * @return string */ - protected function getMethod() { + protected function getMethod() + { return strtoupper($_SERVER['REQUEST_METHOD']); } @@ -51,10 +59,11 @@ protected function getMethod() { * * @return string */ - protected function getUri() { + protected function getUri() + { $alias = $this->modx->getOption('request_alias', null, 'q'); - $uri = isset($_REQUEST[$alias]) ? (string) $_REQUEST[$alias] : ''; + $uri = isset($_REQUEST[$alias]) && is_scalar($_REQUEST[$alias]) ? (string) $_REQUEST[$alias] : ''; return '/' . ltrim($uri, '/'); } @@ -64,7 +73,8 @@ protected function getUri() { * * @return FastRoute\Dispatcher|FastRoute\Dispatcher\GroupCountBased */ - protected function getDispatcher() { + protected function getDispatcher() + { return $this->dispatcher; } @@ -73,11 +83,12 @@ protected function getDispatcher() { * * @param FastRoute\RouteCollector $router */ - protected function getRoutes(FastRoute\RouteCollector $router) { + protected function getRoutes(FastRoute\RouteCollector $router) + { $routes = json_decode($this->getRoutesChunk(), true); if (!$routes) { - throw new InvalidArgumentException('Invalid routes'); + throw new InvalidArgumentException('Routes is invalid.'); } foreach ($routes as $r) { @@ -92,10 +103,9 @@ protected function getRoutes(FastRoute\RouteCollector $router) { * * @return string */ - protected function getRoutesChunk() { - $chunk = $this->modx->getChunk($this->chunkName()); - - return $chunk; + protected function getRoutesChunk() + { + return $this->modx->getChunk($this->chunkName()); } /** @@ -103,10 +113,9 @@ protected function getRoutesChunk() { * * @return string */ - public function chunkName() { - $name = $this->modx->getOption('fastrouter.chunkName', null, 'fastrouter'); - - return $name; + public function chunkName() + { + return $this->modx->getOption(static::FAST_ROUTER . '.chunkName', null, static::FAST_ROUTER); } /** @@ -114,7 +123,8 @@ public function chunkName() { * * @return null */ - public function dispatch() { + public function dispatch() + { $dispatcher = $this->getDispatcher(); $params = $dispatcher->dispatch($this->getMethod(), $this->getUri()); @@ -123,11 +133,9 @@ public function dispatch() { case FastRoute\Dispatcher::NOT_FOUND: case FastRoute\Dispatcher::METHOD_NOT_ALLOWED: return $this->error(); - break; case FastRoute\Dispatcher::FOUND: return $this->handle($params[1], $params[2]); - break; } return null; @@ -136,25 +144,27 @@ public function dispatch() { /** * Handle route * - * @param mixed $routeHandler + * @param integer|string $routeHandler * @param array $data * * @return null */ - protected function handle($routeHandler, array $data) { + protected function handle($routeHandler, array $data) + { + // Send forward to resource if (is_numeric($routeHandler)) { - // Send forward to resource - $_REQUEST += array($this->paramsKey => $data); + $_REQUEST += [$this->paramsKey => $data]; $this->modx->sendForward($routeHandler); - } else { - // Call snippet - echo $this->modx->runSnippet($routeHandler, array( - $this->paramsKey => $data, - )); - die; + + return null; } - return null; + // TODO: Refactor. Remove exit. What is the best way to do this? + // Call snippet + echo $this->modx->runSnippet($routeHandler, [ + $this->paramsKey => $data, + ]); + exit(); } /** @@ -162,14 +172,19 @@ protected function handle($routeHandler, array $data) { * * @return null */ - protected function error() { - $options = array( + protected function error() + { + $options = [ 'response_code' => $this->modx->getOption('error_page_header', null, 'HTTP/1.1 404 Not Found'), 'error_type' => '404', 'error_header' => $this->modx->getOption('error_page_header', null, 'HTTP/1.1 404 Not Found'), 'error_pagetitle' => $this->modx->getOption('error_page_pagetitle', null, 'Error 404: Page not found'), - 'error_message' => $this->modx->getOption('error_page_message', null, '

Page not found

The page you requested was not found.

'), - ); + 'error_message' => $this->modx->getOption( + 'error_page_message', + null, + '

Page not found

The page you requested was not found.

' + ), + ]; $this->modx->sendForward($this->modx->getOption('error_page', $options, '404'), $options); @@ -179,7 +194,8 @@ protected function error() { /** * Remove routes cache */ - public function clearCache() { + public function clearCache() + { if (file_exists($this->cacheFile)) { unlink($this->cacheFile); } @@ -188,27 +204,35 @@ public function clearCache() { /** * Register router dispatcher */ - protected function registerDispatcher() { + protected function registerDispatcher() + { $this->dispatcher = FastRoute\cachedDispatcher(function (FastRoute\RouteCollector $router) { $this->getRoutes($router); - }, array( + }, [ 'cacheFile' => $this->cacheFile, - )); + ]); } /** * @return bool */ - public function needDispath() { - return $this->modx->event->name === 'OnPageNotFound' && !isset($this->modx->event->params['stop']); + public function needDispatch() + { + $event = $this->modx->event; + + return static::EVENT === $event->name && !isset($event->params['stop']); } /** * Check if chunk with routes updated * + * @param string $chunkName * @return bool */ - public function isRoutesChunkUpdated($chunkName) { - return $this->modx->event->name == 'OnChunkSave' && $chunkName == $this->chunkName(); + public function isRoutesChunkUpdated($chunkName) + { + $event = $this->modx->event; + + return static::EVENT_ON_CHUNK_SAVE === $event->name && $chunkName === $this->chunkName(); } } diff --git a/core/components/fastrouter/routes.php b/core/components/fastrouter/routes.php index b9ee14e..9818e2c 100644 --- a/core/components/fastrouter/routes.php +++ b/core/components/fastrouter/routes.php @@ -4,4 +4,5 @@ $r->addRoute('GET', '/fastrouter/{name}/{id:[0-9]+}', '1'); $r->addRoute('GET', '/fastrouter/{id:[0-9]+}', '1'); $r->addRoute('GET', '/hello/{name}', '1'); -$r->addRoute('GET', '/some_snipper', 'snippet_name'); +$r->addRoute('GET', '/some_snippet/{id}', 'fastrouter'); +$r->addRoute('GET', '/contact', '1'); diff --git a/core/components/fastrouter/vendor/nikic/fast-route/.travis.yml b/core/components/fastrouter/vendor/nikic/fast-route/.travis.yml deleted file mode 100644 index 4f0a7bc..0000000 --- a/core/components/fastrouter/vendor/nikic/fast-route/.travis.yml +++ /dev/null @@ -1,8 +0,0 @@ -language: php - -php: - - 5.4 - - 5.5 - - 5.6 - - hhvm - diff --git a/core/components/fastrouter/vendor/nikic/fast-route/README.md b/core/components/fastrouter/vendor/nikic/fast-route/README.md index 257342e..de1925e 100644 --- a/core/components/fastrouter/vendor/nikic/fast-route/README.md +++ b/core/components/fastrouter/vendor/nikic/fast-route/README.md @@ -4,6 +4,17 @@ FastRoute - Fast request router for PHP This library provides a fast implementation of a regular expression based router. [Blog post explaining how the implementation works and why it is fast.][blog_post] +Install +------- + +To install with composer: + +```sh +composer require nikic/fast-route +``` + +Requires PHP 5.4 or newer. + Usage ----- @@ -12,14 +23,26 @@ Here's a basic usage example: ```php addRoute('GET', '/user/{name}/{id:[0-9]+}', 'handler0'); - $r->addRoute('GET', '/user/{id:[0-9]+}', 'handler1'); - $r->addRoute('GET', '/user/{name}', 'handler2'); + $r->addRoute('GET', '/users', 'get_all_users_handler'); + // {id} must be a number (\d+) + $r->addRoute('GET', '/user/{id:\d+}', 'get_user_handler'); + // The /{title} suffix is optional + $r->addRoute('GET', '/articles/{id:\d+}[/{title}]', 'get_article_handler'); }); +// Fetch method and URI from somewhere +$httpMethod = $_SERVER['REQUEST_METHOD']; +$uri = $_SERVER['REQUEST_URI']; + +// Strip query string (?foo=bar) and decode URI +if (false !== $pos = strpos($uri, '?')) { + $uri = substr($uri, 0, $pos); +} +$uri = rawurldecode($uri); + $routeInfo = $dispatcher->dispatch($httpMethod, $uri); switch ($routeInfo[0]) { case FastRoute\Dispatcher::NOT_FOUND: @@ -39,18 +62,107 @@ switch ($routeInfo[0]) { ### Defining routes -The routes are defined by calling the `FastRoute\simpleDispatcher` function, which accepts +The routes are defined by calling the `FastRoute\simpleDispatcher()` function, which accepts a callable taking a `FastRoute\RouteCollector` instance. The routes are added by calling -`addRoute()` on the collector instance. +`addRoute()` on the collector instance: + +```php +$r->addRoute($method, $routePattern, $handler); +``` + +The `$method` is an uppercase HTTP method string for which a certain route should match. It +is possible to specify multiple valid methods using an array: + +```php +// These two calls +$r->addRoute('GET', '/test', 'handler'); +$r->addRoute('POST', '/test', 'handler'); +// Are equivalent to this one call +$r->addRoute(['GET', 'POST'], '/test', 'handler'); +``` + +By default the `$routePattern` uses a syntax where `{foo}` specifies a placeholder with name `foo` +and matching the regex `[^/]+`. To adjust the pattern the placeholder matches, you can specify +a custom pattern by writing `{bar:[0-9]+}`. Some examples: + +```php +// Matches /user/42, but not /user/xyz +$r->addRoute('GET', '/user/{id:\d+}', 'handler'); + +// Matches /user/foobar, but not /user/foo/bar +$r->addRoute('GET', '/user/{name}', 'handler'); + +// Matches /user/foo/bar as well +$r->addRoute('GET', '/user/{name:.+}', 'handler'); +``` + +Custom patterns for route placeholders cannot use capturing groups. For example `{lang:(en|de)}` +is not a valid placeholder, because `()` is a capturing group. Instead you can use either +`{lang:en|de}` or `{lang:(?:en|de)}`. + +Furthermore parts of the route enclosed in `[...]` are considered optional, so that `/foo[bar]` +will match both `/foo` and `/foobar`. Optional parts are only supported in a trailing position, +not in the middle of a route. + +```php +// This route +$r->addRoute('GET', '/user/{id:\d+}[/{name}]', 'handler'); +// Is equivalent to these two routes +$r->addRoute('GET', '/user/{id:\d+}', 'handler'); +$r->addRoute('GET', '/user/{id:\d+}/{name}', 'handler'); + +// Multiple nested optional parts are possible as well +$r->addRoute('GET', '/user[/{id:\d+}[/{name}]]', 'handler'); + +// This route is NOT valid, because optional parts can only occur at the end +$r->addRoute('GET', '/user[/{id:\d+}]/{name}', 'handler'); +``` + +The `$handler` parameter does not necessarily have to be a callback, it could also be a controller +class name or any other kind of data you wish to associate with the route. FastRoute only tells you +which handler corresponds to your URI, how you interpret it is up to you. + +#### Shortcut methods for common request methods + +For the `GET`, `POST`, `PUT`, `PATCH`, `DELETE` and `HEAD` request methods shortcut methods are available. For example: + +```php +$r->get('/get-route', 'get_handler'); +$r->post('/post-route', 'post_handler'); +``` + +Is equivalent to: + +```php +$r->addRoute('GET', '/get-route', 'get_handler'); +$r->addRoute('POST', '/post-route', 'post_handler'); +``` + +#### Route Groups + +Additionally, you can specify routes inside of a group. All routes defined inside a group will have a common prefix. + +For example, defining your routes as: + +```php +$r->addGroup('/admin', function (RouteCollector $r) { + $r->addRoute('GET', '/do-something', 'handler'); + $r->addRoute('GET', '/do-another-thing', 'handler'); + $r->addRoute('GET', '/do-something-else', 'handler'); +}); +``` + +Will have the same result as: + + ```php +$r->addRoute('GET', '/admin/do-something', 'handler'); +$r->addRoute('GET', '/admin/do-another-thing', 'handler'); +$r->addRoute('GET', '/admin/do-something-else', 'handler'); + ``` -This method accepts the HTTP method the route must match, the route pattern and an associated -handler. The handler does not necessarily have to be a callback (it could also be a controller -class name or any other kind of data you wish to associate with the route). +Nested groups are also supported, in which case the prefixes of all the nested groups are combined. -By default a route pattern syntax is used where `{foo}` specified a placeholder with name `foo` -and matching the string `[^/]+`. To adjust the pattern the placeholder matches, you can specify -a custom pattern by writing `{bar:[0-9]+}`. However, it is also possible to adjust the pattern -syntax by passing using a different route parser. +### Caching The reason `simpleDispatcher` accepts a callback for defining the routes is to allow seamless caching. By using `cachedDispatcher` instead of `simpleDispatcher` you can cache the generated @@ -78,7 +190,7 @@ A URI is dispatched by calling the `dispatch()` method of the created dispatcher accepts the HTTP method and a URI. Getting those two bits of information (and normalizing them appropriately) is your job - this library is not bound to the PHP web SAPIs. -The `dispatch()` method returns an array those first element contains a status code. It is one +The `dispatch()` method returns an array whose first element contains a status code. It is one of `Dispatcher::NOT_FOUND`, `Dispatcher::METHOD_NOT_ALLOWED` and `Dispatcher::FOUND`. For the method not allowed status the second array element contains a list of HTTP methods allowed for the supplied URI. For example: @@ -122,15 +234,21 @@ interface Dispatcher { } ``` -The route parser takes a route pattern string and converts it into an array of it's parts. The -array has a certain structure, best understood using an example: +The route parser takes a route pattern string and converts it into an array of route infos, where +each route info is again an array of it's parts. The structure is best understood using an example: - /* The route /user/{name}/{id:[0-9]+} converts to the following array: */ + /* The route /user/{id:\d+}[/{name}] converts to the following array: */ [ - '/user/', - ['name', '[^/]+'], - '/', - ['id', '[0-9]+'], + [ + '/user/', + ['id', '\d+'], + ], + [ + '/user/', + ['id', '\d+'], + '/', + ['name', '[^/]+'], + ], ] This array can then be passed to the `addRoute()` method of a data generator. After all routes have @@ -175,7 +293,7 @@ To avoid forcing users to manually register HEAD routes for each resource we fal available GET route for a given resource. The PHP web SAPI transparently removes the entity body from HEAD responses so this behavior has no effect on the vast majority of users. -However, implementors using FastRoute outside the web SAPI environment (e.g. a custom server) MUST +However, implementers using FastRoute outside the web SAPI environment (e.g. a custom server) MUST NOT send entity bodies generated in response to HEAD requests. If you are a non-SAPI user this is *your responsibility*; FastRoute has no purview to prevent you from breaking HTTP in such cases. diff --git a/core/components/fastrouter/vendor/nikic/fast-route/composer.json b/core/components/fastrouter/vendor/nikic/fast-route/composer.json index 62aad22..fb446a2 100644 --- a/core/components/fastrouter/vendor/nikic/fast-route/composer.json +++ b/core/components/fastrouter/vendor/nikic/fast-route/composer.json @@ -9,13 +9,16 @@ "email": "nikic@php.net" } ], - "require": { - "php": ">=5.4.0" - }, "autoload": { "psr-4": { "FastRoute\\": "src/" }, "files": ["src/functions.php"] + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35|~5.7" } } diff --git a/core/components/fastrouter/vendor/nikic/fast-route/phpunit.xml b/core/components/fastrouter/vendor/nikic/fast-route/phpunit.xml deleted file mode 100644 index 3c807b6..0000000 --- a/core/components/fastrouter/vendor/nikic/fast-route/phpunit.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - ./test/ - - - - - - ./src/ - - - diff --git a/core/components/fastrouter/vendor/nikic/fast-route/src/BadRouteException.php b/core/components/fastrouter/vendor/nikic/fast-route/src/BadRouteException.php index 7e38479..62262ec 100644 --- a/core/components/fastrouter/vendor/nikic/fast-route/src/BadRouteException.php +++ b/core/components/fastrouter/vendor/nikic/fast-route/src/BadRouteException.php @@ -2,5 +2,6 @@ namespace FastRoute; -class BadRouteException extends \LogicException { +class BadRouteException extends \LogicException +{ } diff --git a/core/components/fastrouter/vendor/nikic/fast-route/src/DataGenerator.php b/core/components/fastrouter/vendor/nikic/fast-route/src/DataGenerator.php index 16053db..af577cd 100644 --- a/core/components/fastrouter/vendor/nikic/fast-route/src/DataGenerator.php +++ b/core/components/fastrouter/vendor/nikic/fast-route/src/DataGenerator.php @@ -2,7 +2,8 @@ namespace FastRoute; -interface DataGenerator { +interface DataGenerator +{ /** * Adds a route to the data generator. The route data uses the * same format that is returned by RouterParser::parser(). diff --git a/core/components/fastrouter/vendor/nikic/fast-route/src/DataGenerator/CharCountBased.php b/core/components/fastrouter/vendor/nikic/fast-route/src/DataGenerator/CharCountBased.php index 5c38b89..3cfeed6 100644 --- a/core/components/fastrouter/vendor/nikic/fast-route/src/DataGenerator/CharCountBased.php +++ b/core/components/fastrouter/vendor/nikic/fast-route/src/DataGenerator/CharCountBased.php @@ -2,12 +2,15 @@ namespace FastRoute\DataGenerator; -class CharCountBased extends RegexBasedAbstract { - protected function getApproxChunkSize() { +class CharCountBased extends RegexBasedAbstract +{ + protected function getApproxChunkSize() + { return 30; } - protected function processChunk($regexToRoutesMap) { + protected function processChunk($regexToRoutesMap) + { $routeMap = []; $regexes = []; diff --git a/core/components/fastrouter/vendor/nikic/fast-route/src/DataGenerator/GroupCountBased.php b/core/components/fastrouter/vendor/nikic/fast-route/src/DataGenerator/GroupCountBased.php index d51807f..54d9a05 100644 --- a/core/components/fastrouter/vendor/nikic/fast-route/src/DataGenerator/GroupCountBased.php +++ b/core/components/fastrouter/vendor/nikic/fast-route/src/DataGenerator/GroupCountBased.php @@ -2,12 +2,15 @@ namespace FastRoute\DataGenerator; -class GroupCountBased extends RegexBasedAbstract { - protected function getApproxChunkSize() { +class GroupCountBased extends RegexBasedAbstract +{ + protected function getApproxChunkSize() + { return 10; } - protected function processChunk($regexToRoutesMap) { + protected function processChunk($regexToRoutesMap) + { $routeMap = []; $regexes = []; $numGroups = 0; @@ -25,4 +28,3 @@ protected function processChunk($regexToRoutesMap) { return ['regex' => $regex, 'routeMap' => $routeMap]; } } - diff --git a/core/components/fastrouter/vendor/nikic/fast-route/src/DataGenerator/GroupPosBased.php b/core/components/fastrouter/vendor/nikic/fast-route/src/DataGenerator/GroupPosBased.php index 4152f7a..af49675 100644 --- a/core/components/fastrouter/vendor/nikic/fast-route/src/DataGenerator/GroupPosBased.php +++ b/core/components/fastrouter/vendor/nikic/fast-route/src/DataGenerator/GroupPosBased.php @@ -2,12 +2,15 @@ namespace FastRoute\DataGenerator; -class GroupPosBased extends RegexBasedAbstract { - protected function getApproxChunkSize() { +class GroupPosBased extends RegexBasedAbstract +{ + protected function getApproxChunkSize() + { return 10; } - protected function processChunk($regexToRoutesMap) { + protected function processChunk($regexToRoutesMap) + { $routeMap = []; $regexes = []; $offset = 1; @@ -19,7 +22,7 @@ protected function processChunk($regexToRoutesMap) { } $regex = '~^(?:' . implode('|', $regexes) . ')$~'; + return ['regex' => $regex, 'routeMap' => $routeMap]; } } - diff --git a/core/components/fastrouter/vendor/nikic/fast-route/src/DataGenerator/MarkBased.php b/core/components/fastrouter/vendor/nikic/fast-route/src/DataGenerator/MarkBased.php index 61359f5..0aebed9 100644 --- a/core/components/fastrouter/vendor/nikic/fast-route/src/DataGenerator/MarkBased.php +++ b/core/components/fastrouter/vendor/nikic/fast-route/src/DataGenerator/MarkBased.php @@ -2,12 +2,15 @@ namespace FastRoute\DataGenerator; -class MarkBased extends RegexBasedAbstract { - protected function getApproxChunkSize() { +class MarkBased extends RegexBasedAbstract +{ + protected function getApproxChunkSize() + { return 30; } - protected function processChunk($regexToRoutesMap) { + protected function processChunk($regexToRoutesMap) + { $routeMap = []; $regexes = []; $markName = 'a'; @@ -22,4 +25,3 @@ protected function processChunk($regexToRoutesMap) { return ['regex' => $regex, 'routeMap' => $routeMap]; } } - diff --git a/core/components/fastrouter/vendor/nikic/fast-route/src/DataGenerator/RegexBasedAbstract.php b/core/components/fastrouter/vendor/nikic/fast-route/src/DataGenerator/RegexBasedAbstract.php index 6c1e0c5..6457290 100644 --- a/core/components/fastrouter/vendor/nikic/fast-route/src/DataGenerator/RegexBasedAbstract.php +++ b/core/components/fastrouter/vendor/nikic/fast-route/src/DataGenerator/RegexBasedAbstract.php @@ -2,18 +2,30 @@ namespace FastRoute\DataGenerator; -use FastRoute\DataGenerator; use FastRoute\BadRouteException; +use FastRoute\DataGenerator; use FastRoute\Route; -abstract class RegexBasedAbstract implements DataGenerator { +abstract class RegexBasedAbstract implements DataGenerator +{ + /** @var mixed[][] */ protected $staticRoutes = []; + + /** @var Route[][] */ protected $methodToRegexToRoutesMap = []; - protected abstract function getApproxChunkSize(); - protected abstract function processChunk($regexToRoutesMap); + /** + * @return int + */ + abstract protected function getApproxChunkSize(); + + /** + * @return mixed[] + */ + abstract protected function processChunk($regexToRoutesMap); - public function addRoute($httpMethod, $routeData, $handler) { + public function addRoute($httpMethod, $routeData, $handler) + { if ($this->isStaticRoute($routeData)) { $this->addStaticRoute($httpMethod, $routeData, $handler); } else { @@ -21,7 +33,11 @@ public function addRoute($httpMethod, $routeData, $handler) { } } - public function getData() { + /** + * @return mixed[] + */ + public function getData() + { if (empty($this->methodToRegexToRoutesMap)) { return [$this->staticRoutes, []]; } @@ -29,29 +45,44 @@ public function getData() { return [$this->staticRoutes, $this->generateVariableRouteData()]; } - private function generateVariableRouteData() { + /** + * @return mixed[] + */ + private function generateVariableRouteData() + { $data = []; foreach ($this->methodToRegexToRoutesMap as $method => $regexToRoutesMap) { $chunkSize = $this->computeChunkSize(count($regexToRoutesMap)); $chunks = array_chunk($regexToRoutesMap, $chunkSize, true); - $data[$method] = array_map([$this, 'processChunk'], $chunks); + $data[$method] = array_map([$this, 'processChunk'], $chunks); } return $data; } - private function computeChunkSize($count) { + /** + * @param int + * @return int + */ + private function computeChunkSize($count) + { $numParts = max(1, round($count / $this->getApproxChunkSize())); - return ceil($count / $numParts); + return (int) ceil($count / $numParts); } - private function isStaticRoute($routeData) { - return count($routeData) == 1 && is_string($routeData[0]); + /** + * @param mixed[] + * @return bool + */ + private function isStaticRoute($routeData) + { + return count($routeData) === 1 && is_string($routeData[0]); } - private function addStaticRoute($httpMethod, $routeData, $handler) { + private function addStaticRoute($httpMethod, $routeData, $handler) + { $routeStr = $routeData[0]; - if (isset($this->staticRoutes[$routeStr][$httpMethod])) { + if (isset($this->staticRoutes[$httpMethod][$routeStr])) { throw new BadRouteException(sprintf( 'Cannot register two routes matching "%s" for method "%s"', $routeStr, $httpMethod @@ -69,10 +100,11 @@ private function addStaticRoute($httpMethod, $routeData, $handler) { } } - $this->staticRoutes[$routeStr][$httpMethod] = $handler; + $this->staticRoutes[$httpMethod][$routeStr] = $handler; } - private function addVariableRoute($httpMethod, $routeData, $handler) { + private function addVariableRoute($httpMethod, $routeData, $handler) + { list($regex, $variables) = $this->buildRegexForRoute($routeData); if (isset($this->methodToRegexToRoutesMap[$httpMethod][$regex])) { @@ -87,7 +119,12 @@ private function addVariableRoute($httpMethod, $routeData, $handler) { ); } - private function buildRegexForRoute($routeData) { + /** + * @param mixed[] + * @return mixed[] + */ + private function buildRegexForRoute($routeData) + { $regex = ''; $variables = []; foreach ($routeData as $part) { @@ -104,10 +141,46 @@ private function buildRegexForRoute($routeData) { )); } + if ($this->regexHasCapturingGroups($regexPart)) { + throw new BadRouteException(sprintf( + 'Regex "%s" for parameter "%s" contains a capturing group', + $regexPart, $varName + )); + } + $variables[$varName] = $varName; $regex .= '(' . $regexPart . ')'; } return [$regex, $variables]; } + + /** + * @param string + * @return bool + */ + private function regexHasCapturingGroups($regex) + { + if (false === strpos($regex, '(')) { + // Needs to have at least a ( to contain a capturing group + return false; + } + + // Semi-accurate detection for capturing groups + return (bool) preg_match( + '~ + (?: + \(\?\( + | \[ [^\]\\\\]* (?: \\\\ . [^\]\\\\]* )* \] + | \\\\ . + ) (*SKIP)(*FAIL) | + \( + (?! + \? (?! <(?![!=]) | P< | \' ) + | \* + ) + ~x', + $regex + ); + } } diff --git a/core/components/fastrouter/vendor/nikic/fast-route/src/Dispatcher.php b/core/components/fastrouter/vendor/nikic/fast-route/src/Dispatcher.php index ea98009..4ae72a3 100644 --- a/core/components/fastrouter/vendor/nikic/fast-route/src/Dispatcher.php +++ b/core/components/fastrouter/vendor/nikic/fast-route/src/Dispatcher.php @@ -2,7 +2,8 @@ namespace FastRoute; -interface Dispatcher { +interface Dispatcher +{ const NOT_FOUND = 0; const FOUND = 1; const METHOD_NOT_ALLOWED = 2; diff --git a/core/components/fastrouter/vendor/nikic/fast-route/src/Dispatcher/CharCountBased.php b/core/components/fastrouter/vendor/nikic/fast-route/src/Dispatcher/CharCountBased.php index 22ba240..ef1eec1 100644 --- a/core/components/fastrouter/vendor/nikic/fast-route/src/Dispatcher/CharCountBased.php +++ b/core/components/fastrouter/vendor/nikic/fast-route/src/Dispatcher/CharCountBased.php @@ -2,12 +2,15 @@ namespace FastRoute\Dispatcher; -class CharCountBased extends RegexBasedAbstract { - public function __construct($data) { +class CharCountBased extends RegexBasedAbstract +{ + public function __construct($data) + { list($this->staticRouteMap, $this->variableRouteData) = $data; } - protected function dispatchVariableRoute($routeData, $uri) { + protected function dispatchVariableRoute($routeData, $uri) + { foreach ($routeData as $data) { if (!preg_match($data['regex'], $uri . $data['suffix'], $matches)) { continue; diff --git a/core/components/fastrouter/vendor/nikic/fast-route/src/Dispatcher/GroupCountBased.php b/core/components/fastrouter/vendor/nikic/fast-route/src/Dispatcher/GroupCountBased.php index 0abd322..493e7a9 100644 --- a/core/components/fastrouter/vendor/nikic/fast-route/src/Dispatcher/GroupCountBased.php +++ b/core/components/fastrouter/vendor/nikic/fast-route/src/Dispatcher/GroupCountBased.php @@ -2,12 +2,15 @@ namespace FastRoute\Dispatcher; -class GroupCountBased extends RegexBasedAbstract { - public function __construct($data) { +class GroupCountBased extends RegexBasedAbstract +{ + public function __construct($data) + { list($this->staticRouteMap, $this->variableRouteData) = $data; } - protected function dispatchVariableRoute($routeData, $uri) { + protected function dispatchVariableRoute($routeData, $uri) + { foreach ($routeData as $data) { if (!preg_match($data['regex'], $uri, $matches)) { continue; diff --git a/core/components/fastrouter/vendor/nikic/fast-route/src/Dispatcher/GroupPosBased.php b/core/components/fastrouter/vendor/nikic/fast-route/src/Dispatcher/GroupPosBased.php index 32227d4..498220e 100644 --- a/core/components/fastrouter/vendor/nikic/fast-route/src/Dispatcher/GroupPosBased.php +++ b/core/components/fastrouter/vendor/nikic/fast-route/src/Dispatcher/GroupPosBased.php @@ -2,12 +2,15 @@ namespace FastRoute\Dispatcher; -class GroupPosBased extends RegexBasedAbstract { - public function __construct($data) { +class GroupPosBased extends RegexBasedAbstract +{ + public function __construct($data) + { list($this->staticRouteMap, $this->variableRouteData) = $data; } - protected function dispatchVariableRoute($routeData, $uri) { + protected function dispatchVariableRoute($routeData, $uri) + { foreach ($routeData as $data) { if (!preg_match($data['regex'], $uri, $matches)) { continue; diff --git a/core/components/fastrouter/vendor/nikic/fast-route/src/Dispatcher/MarkBased.php b/core/components/fastrouter/vendor/nikic/fast-route/src/Dispatcher/MarkBased.php index fefa711..22eb09b 100644 --- a/core/components/fastrouter/vendor/nikic/fast-route/src/Dispatcher/MarkBased.php +++ b/core/components/fastrouter/vendor/nikic/fast-route/src/Dispatcher/MarkBased.php @@ -2,12 +2,15 @@ namespace FastRoute\Dispatcher; -class MarkBased extends RegexBasedAbstract { - public function __construct($data) { +class MarkBased extends RegexBasedAbstract +{ + public function __construct($data) + { list($this->staticRouteMap, $this->variableRouteData) = $data; } - protected function dispatchVariableRoute($routeData, $uri) { + protected function dispatchVariableRoute($routeData, $uri) + { foreach ($routeData as $data) { if (!preg_match($data['regex'], $uri, $matches)) { continue; diff --git a/core/components/fastrouter/vendor/nikic/fast-route/src/Dispatcher/RegexBasedAbstract.php b/core/components/fastrouter/vendor/nikic/fast-route/src/Dispatcher/RegexBasedAbstract.php index 5e86907..206e879 100644 --- a/core/components/fastrouter/vendor/nikic/fast-route/src/Dispatcher/RegexBasedAbstract.php +++ b/core/components/fastrouter/vendor/nikic/fast-route/src/Dispatcher/RegexBasedAbstract.php @@ -4,15 +4,24 @@ use FastRoute\Dispatcher; -abstract class RegexBasedAbstract implements Dispatcher { - protected $staticRouteMap; - protected $variableRouteData; +abstract class RegexBasedAbstract implements Dispatcher +{ + /** @var mixed[][] */ + protected $staticRouteMap = []; - protected abstract function dispatchVariableRoute($routeData, $uri); + /** @var mixed[] */ + protected $variableRouteData = []; - public function dispatch($httpMethod, $uri) { - if (isset($this->staticRouteMap[$uri])) { - return $this->dispatchStaticRoute($httpMethod, $uri); + /** + * @return mixed[] + */ + abstract protected function dispatchVariableRoute($routeData, $uri); + + public function dispatch($httpMethod, $uri) + { + if (isset($this->staticRouteMap[$httpMethod][$uri])) { + $handler = $this->staticRouteMap[$httpMethod][$uri]; + return [self::FOUND, $handler, []]; } $varRouteData = $this->variableRouteData; @@ -21,16 +30,43 @@ public function dispatch($httpMethod, $uri) { if ($result[0] === self::FOUND) { return $result; } - } else if ($httpMethod === 'HEAD' && isset($varRouteData['GET'])) { - $result = $this->dispatchVariableRoute($varRouteData['GET'], $uri); + } + + // For HEAD requests, attempt fallback to GET + if ($httpMethod === 'HEAD') { + if (isset($this->staticRouteMap['GET'][$uri])) { + $handler = $this->staticRouteMap['GET'][$uri]; + return [self::FOUND, $handler, []]; + } + if (isset($varRouteData['GET'])) { + $result = $this->dispatchVariableRoute($varRouteData['GET'], $uri); + if ($result[0] === self::FOUND) { + return $result; + } + } + } + + // If nothing else matches, try fallback routes + if (isset($this->staticRouteMap['*'][$uri])) { + $handler = $this->staticRouteMap['*'][$uri]; + return [self::FOUND, $handler, []]; + } + if (isset($varRouteData['*'])) { + $result = $this->dispatchVariableRoute($varRouteData['*'], $uri); if ($result[0] === self::FOUND) { return $result; } } - // Find allowed methods for this URI by matching against all other - // HTTP methods as well + // Find allowed methods for this URI by matching against all other HTTP methods as well $allowedMethods = []; + + foreach ($this->staticRouteMap as $method => $uriMap) { + if ($method !== $httpMethod && isset($uriMap[$uri])) { + $allowedMethods[] = $method; + } + } + foreach ($varRouteData as $method => $routeData) { if ($method === $httpMethod) { continue; @@ -45,20 +81,8 @@ public function dispatch($httpMethod, $uri) { // If there are no allowed methods the route simply does not exist if ($allowedMethods) { return [self::METHOD_NOT_ALLOWED, $allowedMethods]; - } else { - return [self::NOT_FOUND]; } - } - protected function dispatchStaticRoute($httpMethod, $uri) { - $routes = $this->staticRouteMap[$uri]; - - if (isset($routes[$httpMethod])) { - return [self::FOUND, $routes[$httpMethod], []]; - } elseif ($httpMethod === 'HEAD' && isset($routes['GET'])) { - return [self::FOUND, $routes['GET'], []]; - } else { - return [self::METHOD_NOT_ALLOWED, array_keys($routes)]; - } + return [self::NOT_FOUND]; } } diff --git a/core/components/fastrouter/vendor/nikic/fast-route/src/Route.php b/core/components/fastrouter/vendor/nikic/fast-route/src/Route.php index d71ded1..e1bf7dd 100644 --- a/core/components/fastrouter/vendor/nikic/fast-route/src/Route.php +++ b/core/components/fastrouter/vendor/nikic/fast-route/src/Route.php @@ -2,10 +2,18 @@ namespace FastRoute; -class Route { +class Route +{ + /** @var string */ public $httpMethod; + + /** @var string */ public $regex; + + /** @var array */ public $variables; + + /** @var mixed */ public $handler; /** @@ -16,7 +24,8 @@ class Route { * @param string $regex * @param array $variables */ - public function __construct($httpMethod, $handler, $regex, $variables) { + public function __construct($httpMethod, $handler, $regex, $variables) + { $this->httpMethod = $httpMethod; $this->handler = $handler; $this->regex = $regex; @@ -30,9 +39,9 @@ public function __construct($httpMethod, $handler, $regex, $variables) { * * @return bool */ - public function matches($str) { + public function matches($str) + { $regex = '~^' . $this->regex . '$~'; return (bool) preg_match($regex, $str); } } - diff --git a/core/components/fastrouter/vendor/nikic/fast-route/src/RouteCollector.php b/core/components/fastrouter/vendor/nikic/fast-route/src/RouteCollector.php index 056a0aa..6e5aa6a 100644 --- a/core/components/fastrouter/vendor/nikic/fast-route/src/RouteCollector.php +++ b/core/components/fastrouter/vendor/nikic/fast-route/src/RouteCollector.php @@ -2,9 +2,16 @@ namespace FastRoute; -class RouteCollector { - private $routeParser; - private $dataGenerator; +class RouteCollector +{ + /** @var RouteParser */ + protected $routeParser; + + /** @var DataGenerator */ + protected $dataGenerator; + + /** @var string */ + protected $currentGroupPrefix; /** * Constructs a route collector. @@ -12,9 +19,11 @@ class RouteCollector { * @param RouteParser $routeParser * @param DataGenerator $dataGenerator */ - public function __construct(RouteParser $routeParser, DataGenerator $dataGenerator) { + public function __construct(RouteParser $routeParser, DataGenerator $dataGenerator) + { $this->routeParser = $routeParser; $this->dataGenerator = $dataGenerator; + $this->currentGroupPrefix = ''; } /** @@ -22,13 +31,126 @@ public function __construct(RouteParser $routeParser, DataGenerator $dataGenerat * * The syntax used in the $route string depends on the used route parser. * - * @param string $httpMethod + * @param string|string[] $httpMethod + * @param string $route + * @param mixed $handler + */ + public function addRoute($httpMethod, $route, $handler) + { + $route = $this->currentGroupPrefix . $route; + $routeDatas = $this->routeParser->parse($route); + foreach ((array) $httpMethod as $method) { + foreach ($routeDatas as $routeData) { + $this->dataGenerator->addRoute($method, $routeData, $handler); + } + } + } + + /** + * Create a route group with a common prefix. + * + * All routes created in the passed callback will have the given group prefix prepended. + * + * @param string $prefix + * @param callable $callback + */ + public function addGroup($prefix, callable $callback) + { + $previousGroupPrefix = $this->currentGroupPrefix; + $this->currentGroupPrefix = $previousGroupPrefix . $prefix; + $callback($this); + $this->currentGroupPrefix = $previousGroupPrefix; + } + + /** + * Adds a GET route to the collection + * + * This is simply an alias of $this->addRoute('GET', $route, $handler) + * + * @param string $route + * @param mixed $handler + */ + public function get($route, $handler) + { + $this->addRoute('GET', $route, $handler); + } + + /** + * Adds a POST route to the collection + * + * This is simply an alias of $this->addRoute('POST', $route, $handler) + * + * @param string $route + * @param mixed $handler + */ + public function post($route, $handler) + { + $this->addRoute('POST', $route, $handler); + } + + /** + * Adds a PUT route to the collection + * + * This is simply an alias of $this->addRoute('PUT', $route, $handler) + * + * @param string $route + * @param mixed $handler + */ + public function put($route, $handler) + { + $this->addRoute('PUT', $route, $handler); + } + + /** + * Adds a DELETE route to the collection + * + * This is simply an alias of $this->addRoute('DELETE', $route, $handler) + * + * @param string $route + * @param mixed $handler + */ + public function delete($route, $handler) + { + $this->addRoute('DELETE', $route, $handler); + } + + /** + * Adds a PATCH route to the collection + * + * This is simply an alias of $this->addRoute('PATCH', $route, $handler) + * + * @param string $route + * @param mixed $handler + */ + public function patch($route, $handler) + { + $this->addRoute('PATCH', $route, $handler); + } + + /** + * Adds a HEAD route to the collection + * + * This is simply an alias of $this->addRoute('HEAD', $route, $handler) + * + * @param string $route + * @param mixed $handler + */ + public function head($route, $handler) + { + $this->addRoute('HEAD', $route, $handler); + } + + /** + * Adds an OPTIONS route to the collection + * + * This is simply an alias of $this->addRoute('OPTIONS', $route, $handler) + * * @param string $route * @param mixed $handler */ - public function addRoute($httpMethod, $route, $handler) { - $routeData = $this->routeParser->parse($route); - $this->dataGenerator->addRoute($httpMethod, $routeData, $handler); + public function options($route, $handler) + { + $this->addRoute('OPTIONS', $route, $handler); } /** @@ -36,7 +158,8 @@ public function addRoute($httpMethod, $route, $handler) { * * @return array */ - public function getData() { + public function getData() + { return $this->dataGenerator->getData(); } } diff --git a/core/components/fastrouter/vendor/nikic/fast-route/src/RouteParser.php b/core/components/fastrouter/vendor/nikic/fast-route/src/RouteParser.php index a451253..6a7685c 100644 --- a/core/components/fastrouter/vendor/nikic/fast-route/src/RouteParser.php +++ b/core/components/fastrouter/vendor/nikic/fast-route/src/RouteParser.php @@ -2,20 +2,36 @@ namespace FastRoute; -interface RouteParser { +interface RouteParser +{ /** - * Returns an array of the following form: + * Parses a route string into multiple route data arrays. + * + * The expected output is defined using an example: + * + * For the route string "/fixedRoutePart/{varName}[/moreFixed/{varName2:\d+}]", if {varName} is interpreted as + * a placeholder and [...] is interpreted as an optional route part, the expected result is: * * [ - * "/fixedRoutePart/", - * ["varName", "[^/]+"], - * "/moreFixed/", - * ["varName2", [0-9]+"], + * // first route: without optional part + * [ + * "/fixedRoutePart/", + * ["varName", "[^/]+"], + * ], + * // second route: with optional part + * [ + * "/fixedRoutePart/", + * ["varName", "[^/]+"], + * "/moreFixed/", + * ["varName2", [0-9]+"], + * ], * ] * - * @param string $route Route to parse + * Here one route string was converted into two route data arrays. + * + * @param string $route Route string to parse * - * @return array Parsed route data + * @return mixed[][] Array of route data arrays */ public function parse($route); } diff --git a/core/components/fastrouter/vendor/nikic/fast-route/src/RouteParser/Std.php b/core/components/fastrouter/vendor/nikic/fast-route/src/RouteParser/Std.php index de7590e..4fbdee1 100644 --- a/core/components/fastrouter/vendor/nikic/fast-route/src/RouteParser/Std.php +++ b/core/components/fastrouter/vendor/nikic/fast-route/src/RouteParser/Std.php @@ -2,27 +2,65 @@ namespace FastRoute\RouteParser; +use FastRoute\BadRouteException; use FastRoute\RouteParser; /** - * Parses routes of the following form: + * Parses route strings of the following form: * - * "/user/{name}/{id:[0-9]+}" + * "/user/{name}[/{id:[0-9]+}]" */ -class Std implements RouteParser { +class Std implements RouteParser +{ const VARIABLE_REGEX = <<<'REGEX' -~\{ - \s* ([a-zA-Z][a-zA-Z0-9_]*) \s* +\{ + \s* ([a-zA-Z_][a-zA-Z0-9_-]*) \s* (?: : \s* ([^{}]*(?:\{(?-1)\}[^{}]*)*) )? -\}~x +\} REGEX; const DEFAULT_DISPATCH_REGEX = '[^/]+'; - public function parse($route) { + public function parse($route) + { + $routeWithoutClosingOptionals = rtrim($route, ']'); + $numOptionals = strlen($route) - strlen($routeWithoutClosingOptionals); + + // Split on [ while skipping placeholders + $segments = preg_split('~' . self::VARIABLE_REGEX . '(*SKIP)(*F) | \[~x', $routeWithoutClosingOptionals); + if ($numOptionals !== count($segments) - 1) { + // If there are any ] in the middle of the route, throw a more specific error message + if (preg_match('~' . self::VARIABLE_REGEX . '(*SKIP)(*F) | \]~x', $routeWithoutClosingOptionals)) { + throw new BadRouteException('Optional segments can only occur at the end of a route'); + } + throw new BadRouteException("Number of opening '[' and closing ']' does not match"); + } + + $currentRoute = ''; + $routeDatas = []; + foreach ($segments as $n => $segment) { + if ($segment === '' && $n !== 0) { + throw new BadRouteException('Empty optional part'); + } + + $currentRoute .= $segment; + $routeDatas[] = $this->parsePlaceholders($currentRoute); + } + return $routeDatas; + } + + /** + * Parses a route string that does not contain optional segments. + * + * @param string + * @return mixed[] + */ + private function parsePlaceholders($route) + { if (!preg_match_all( - self::VARIABLE_REGEX, $route, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER + '~' . self::VARIABLE_REGEX . '~x', $route, $matches, + PREG_OFFSET_CAPTURE | PREG_SET_ORDER )) { return [$route]; } @@ -40,7 +78,7 @@ public function parse($route) { $offset = $set[0][1] + strlen($set[0][0]); } - if ($offset != strlen($route)) { + if ($offset !== strlen($route)) { $routeData[] = substr($route, $offset); } diff --git a/core/components/fastrouter/vendor/nikic/fast-route/src/bootstrap.php b/core/components/fastrouter/vendor/nikic/fast-route/src/bootstrap.php index add216c..0bce3a4 100644 --- a/core/components/fastrouter/vendor/nikic/fast-route/src/bootstrap.php +++ b/core/components/fastrouter/vendor/nikic/fast-route/src/bootstrap.php @@ -4,7 +4,7 @@ require __DIR__ . '/functions.php'; -spl_autoload_register(function($class) { +spl_autoload_register(function ($class) { if (strpos($class, 'FastRoute\\') === 0) { $name = substr($class, strlen('FastRoute')); require __DIR__ . strtr($name, '\\', DIRECTORY_SEPARATOR) . '.php'; diff --git a/core/components/fastrouter/vendor/nikic/fast-route/src/functions.php b/core/components/fastrouter/vendor/nikic/fast-route/src/functions.php index 533c26e..7cc0649 100644 --- a/core/components/fastrouter/vendor/nikic/fast-route/src/functions.php +++ b/core/components/fastrouter/vendor/nikic/fast-route/src/functions.php @@ -2,60 +2,74 @@ namespace FastRoute; -/** - * @param callable $routeDefinitionCallback - * @param array $options - * - * @return Dispatcher - */ -function simpleDispatcher(callable $routeDefinitionCallback, array $options = []) { - $options += [ - 'routeParser' => 'FastRoute\\RouteParser\\Std', - 'dataGenerator' => 'FastRoute\\DataGenerator\\GroupCountBased', - 'dispatcher' => 'FastRoute\\Dispatcher\\GroupCountBased', - ]; - - $routeCollector = new RouteCollector( - new $options['routeParser'], new $options['dataGenerator'] - ); - $routeDefinitionCallback($routeCollector); - - return new $options['dispatcher']($routeCollector->getData()); -} +if (!function_exists('FastRoute\simpleDispatcher')) { + /** + * @param callable $routeDefinitionCallback + * @param array $options + * + * @return Dispatcher + */ + function simpleDispatcher(callable $routeDefinitionCallback, array $options = []) + { + $options += [ + 'routeParser' => 'FastRoute\\RouteParser\\Std', + 'dataGenerator' => 'FastRoute\\DataGenerator\\GroupCountBased', + 'dispatcher' => 'FastRoute\\Dispatcher\\GroupCountBased', + 'routeCollector' => 'FastRoute\\RouteCollector', + ]; -/** - * @param callable $routeDefinitionCallback - * @param array $options - * - * @return Dispatcher - */ -function cachedDispatcher(callable $routeDefinitionCallback, array $options = []) { - $options += [ - 'routeParser' => 'FastRoute\\RouteParser\\Std', - 'dataGenerator' => 'FastRoute\\DataGenerator\\GroupCountBased', - 'dispatcher' => 'FastRoute\\Dispatcher\\GroupCountBased', - 'cacheDisabled' => false, - ]; - - if (!isset($options['cacheFile'])) { - throw new \LogicException('Must specify "cacheFile" option'); - } + /** @var RouteCollector $routeCollector */ + $routeCollector = new $options['routeCollector']( + new $options['routeParser'], new $options['dataGenerator'] + ); + $routeDefinitionCallback($routeCollector); - if (!$options['cacheDisabled'] && file_exists($options['cacheFile'])) { - $dispatchData = require $options['cacheFile']; - return new $options['dispatcher']($dispatchData); + return new $options['dispatcher']($routeCollector->getData()); } - $routeCollector = new RouteCollector( - new $options['routeParser'], new $options['dataGenerator'] - ); - $routeDefinitionCallback($routeCollector); + /** + * @param callable $routeDefinitionCallback + * @param array $options + * + * @return Dispatcher + */ + function cachedDispatcher(callable $routeDefinitionCallback, array $options = []) + { + $options += [ + 'routeParser' => 'FastRoute\\RouteParser\\Std', + 'dataGenerator' => 'FastRoute\\DataGenerator\\GroupCountBased', + 'dispatcher' => 'FastRoute\\Dispatcher\\GroupCountBased', + 'routeCollector' => 'FastRoute\\RouteCollector', + 'cacheDisabled' => false, + ]; + + if (!isset($options['cacheFile'])) { + throw new \LogicException('Must specify "cacheFile" option'); + } + + if (!$options['cacheDisabled'] && file_exists($options['cacheFile'])) { + $dispatchData = require $options['cacheFile']; + if (!is_array($dispatchData)) { + throw new \RuntimeException('Invalid cache file "' . $options['cacheFile'] . '"'); + } - $dispatchData = $routeCollector->getData(); - file_put_contents( - $options['cacheFile'], - 'getData(); + if (!$options['cacheDisabled']) { + file_put_contents( + $options['cacheFile'], + ' $this->getDataGeneratorClass(), - 'dispatcher' => $this->getDispatcherClass() - ]; - } - - /** - * @dataProvider provideFoundDispatchCases - */ - public function testFoundDispatches($method, $uri, $callback, $handler, $argDict) { - $dispatcher = \FastRoute\simpleDispatcher($callback, $this->generateDispatcherOptions()); - list($routedStatus, $routedTo, $routedArgs) = $dispatcher->dispatch($method, $uri); - $this->assertSame($dispatcher::FOUND, $routedStatus); - $this->assertSame($handler, $routedTo); - $this->assertSame($argDict, $routedArgs); - } - - /** - * @dataProvider provideNotFoundDispatchCases - */ - public function testNotFoundDispatches($method, $uri, $callback) { - $dispatcher = \FastRoute\simpleDispatcher($callback, $this->generateDispatcherOptions()); - $this->assertFalse(isset($routeInfo[1]), - "NOT_FOUND result must only contain a single element in the returned info array" - ); - list($routedStatus) = $dispatcher->dispatch($method, $uri); - $this->assertSame($dispatcher::NOT_FOUND, $routedStatus); - } - - /** - * @dataProvider provideMethodNotAllowedDispatchCases - */ - public function testMethodNotAllowedDispatches($method, $uri, $callback, $availableMethods) { - $dispatcher = \FastRoute\simpleDispatcher($callback, $this->generateDispatcherOptions()); - $routeInfo = $dispatcher->dispatch($method, $uri); - $this->assertTrue(isset($routeInfo[1]), - "METHOD_NOT_ALLOWED result must return an array of allowed methods at index 1" - ); - - list($routedStatus, $methodArray) = $dispatcher->dispatch($method, $uri); - $this->assertSame($dispatcher::METHOD_NOT_ALLOWED, $routedStatus); - $this->assertSame($availableMethods, $methodArray); - } - - /** - * @expectedException \FastRoute\BadRouteException - * @expectedExceptionMessage Cannot use the same placeholder "test" twice - */ - public function testDuplicateVariableNameError() { - \FastRoute\simpleDispatcher(function(RouteCollector $r) { - $r->addRoute('GET', '/foo/{test}/{test:\d+}', 'handler0'); - }, $this->generateDispatcherOptions()); - } - - /** - * @expectedException \FastRoute\BadRouteException - * @expectedExceptionMessage Cannot register two routes matching "/user/([^/]+)" for method "GET" - */ - public function testDuplicateVariableRoute() { - \FastRoute\simpleDispatcher(function(RouteCollector $r) { - $r->addRoute('GET', '/user/{id}', 'handler0'); // oops, forgot \d+ restriction ;) - $r->addRoute('GET', '/user/{name}', 'handler1'); - }, $this->generateDispatcherOptions()); - } - - /** - * @expectedException \FastRoute\BadRouteException - * @expectedExceptionMessage Cannot register two routes matching "/user" for method "GET" - */ - public function testDuplicateStaticRoute() { - \FastRoute\simpleDispatcher(function(RouteCollector $r) { - $r->addRoute('GET', '/user', 'handler0'); - $r->addRoute('GET', '/user', 'handler1'); - }, $this->generateDispatcherOptions()); - } - - /** - * @expectedException \FastRoute\BadRouteException - * @expectedExceptionMessage Static route "/user/nikic" is shadowed by previously defined variable route "/user/([^/]+)" for method "GET" - */ - public function testShadowedStaticRoute() { - \FastRoute\simpleDispatcher(function(RouteCollector $r) { - $r->addRoute('GET', '/user/{name}', 'handler0'); - $r->addRoute('GET', '/user/nikic', 'handler1'); - }, $this->generateDispatcherOptions()); - } - - public function provideFoundDispatchCases() { - $cases = []; - - // 0 --------------------------------------------------------------------------------------> - - $callback = function(RouteCollector $r) { - $r->addRoute('GET', '/resource/123/456', 'handler0'); - }; - - $method = 'GET'; - $uri = '/resource/123/456'; - $handler = 'handler0'; - $argDict = []; - - $cases[] = [$method, $uri, $callback, $handler, $argDict]; - - // 1 --------------------------------------------------------------------------------------> - - $callback = function(RouteCollector $r) { - $r->addRoute('GET', '/handler0', 'handler0'); - $r->addRoute('GET', '/handler1', 'handler1'); - $r->addRoute('GET', '/handler2', 'handler2'); - }; - - $method = 'GET'; - $uri = '/handler2'; - $handler = 'handler2'; - $argDict = []; - - $cases[] = [$method, $uri, $callback, $handler, $argDict]; - - // 2 --------------------------------------------------------------------------------------> - - $callback = function(RouteCollector $r) { - $r->addRoute('GET', '/user/{name}/{id:[0-9]+}', 'handler0'); - $r->addRoute('GET', '/user/{id:[0-9]+}', 'handler1'); - $r->addRoute('GET', '/user/{name}', 'handler2'); - }; - - $method = 'GET'; - $uri = '/user/rdlowrey'; - $handler = 'handler2'; - $argDict = ['name' => 'rdlowrey']; - - $cases[] = [$method, $uri, $callback, $handler, $argDict]; - - // 3 --------------------------------------------------------------------------------------> - - // reuse $callback from #2 - - $method = 'GET'; - $uri = '/user/12345'; - $handler = 'handler1'; - $argDict = ['id' => '12345']; - - $cases[] = [$method, $uri, $callback, $handler, $argDict]; - - // 4 --------------------------------------------------------------------------------------> - - // reuse $callback from #3 - - $method = 'GET'; - $uri = '/user/NaN'; - $handler = 'handler2'; - $argDict = ['name' => 'NaN']; - - $cases[] = [$method, $uri, $callback, $handler, $argDict]; - - // 5 --------------------------------------------------------------------------------------> - - // reuse $callback from #4 - - $method = 'GET'; - $uri = '/user/rdlowrey/12345'; - $handler = 'handler0'; - $argDict = ['name' => 'rdlowrey', 'id' => '12345']; - - $cases[] = [$method, $uri, $callback, $handler, $argDict]; - - // 6 --------------------------------------------------------------------------------------> - - $callback = function(RouteCollector $r) { - $r->addRoute('GET', '/user/{id:[0-9]+}', 'handler0'); - $r->addRoute('GET', '/user/12345/extension', 'handler1'); - $r->addRoute('GET', '/user/{id:[0-9]+}.{extension}', 'handler2'); - - }; - - $method = 'GET'; - $uri = '/user/12345.svg'; - $handler = 'handler2'; - $argDict = ['id' => '12345', 'extension' => 'svg']; - - $cases[] = [$method, $uri, $callback, $handler, $argDict]; - - // 7 ----- Test GET method fallback on HEAD route miss ------------------------------------> - - $callback = function(RouteCollector $r) { - $r->addRoute('GET', '/user/{name}', 'handler0'); - $r->addRoute('GET', '/user/{name}/{id:[0-9]+}', 'handler1'); - $r->addRoute('GET', '/static0', 'handler2'); - $r->addRoute('GET', '/static1', 'handler3'); - $r->addRoute('HEAD', '/static1', 'handler4'); - }; - - $method = 'HEAD'; - $uri = '/user/rdlowrey'; - $handler = 'handler0'; - $argDict = ['name' => 'rdlowrey']; - - $cases[] = [$method, $uri, $callback, $handler, $argDict]; - - // 8 ----- Test GET method fallback on HEAD route miss ------------------------------------> - - // reuse $callback from #7 - - $method = 'HEAD'; - $uri = '/user/rdlowrey/1234'; - $handler = 'handler1'; - $argDict = ['name' => 'rdlowrey', 'id' => '1234']; - - $cases[] = [$method, $uri, $callback, $handler, $argDict]; - - // 9 ----- Test GET method fallback on HEAD route miss ------------------------------------> - - // reuse $callback from #8 - - $method = 'HEAD'; - $uri = '/static0'; - $handler = 'handler2'; - $argDict = []; - - $cases[] = [$method, $uri, $callback, $handler, $argDict]; - - // 10 ---- Test existing HEAD route used if available (no fallback) -----------------------> - - // reuse $callback from #9 - - $method = 'HEAD'; - $uri = '/static1'; - $handler = 'handler4'; - $argDict = []; - - $cases[] = [$method, $uri, $callback, $handler, $argDict]; - - // 11 ---- More specified routes are not shadowed by less specific of another method ------> - - $callback = function(RouteCollector $r) { - $r->addRoute('GET', '/user/{name}', 'handler0'); - $r->addRoute('POST', '/user/{name:[a-z]+}', 'handler1'); - }; - - $method = 'POST'; - $uri = '/user/rdlowrey'; - $handler = 'handler1'; - $argDict = ['name' => 'rdlowrey']; - - $cases[] = [$method, $uri, $callback, $handler, $argDict]; - - // 12 ---- Handler of more specific routes is used, if it occurs first --------------------> - - $callback = function(RouteCollector $r) { - $r->addRoute('GET', '/user/{name}', 'handler0'); - $r->addRoute('POST', '/user/{name:[a-z]+}', 'handler1'); - $r->addRoute('POST', '/user/{name}', 'handler2'); - }; - - $method = 'POST'; - $uri = '/user/rdlowrey'; - $handler = 'handler1'; - $argDict = ['name' => 'rdlowrey']; - - $cases[] = [$method, $uri, $callback, $handler, $argDict]; - - // 13 ---- Route with constant suffix -----------------------------------------------------> - - $callback = function(RouteCollector $r) { - $r->addRoute('GET', '/user/{name}', 'handler0'); - $r->addRoute('GET', '/user/{name}/edit', 'handler1'); - }; - - $method = 'GET'; - $uri = '/user/rdlowrey/edit'; - $handler = 'handler1'; - $argDict = ['name' => 'rdlowrey']; - - $cases[] = [$method, $uri, $callback, $handler, $argDict]; - - // x --------------------------------------------------------------------------------------> - - return $cases; - } - - public function provideNotFoundDispatchCases() { - $cases = []; - - // 0 --------------------------------------------------------------------------------------> - - $callback = function(RouteCollector $r) { - $r->addRoute('GET', '/resource/123/456', 'handler0'); - }; - - $method = 'GET'; - $uri = '/not-found'; - - $cases[] = [$method, $uri, $callback]; - - // 1 --------------------------------------------------------------------------------------> - - // reuse callback from #0 - $method = 'POST'; - $uri = '/not-found'; - - $cases[] = [$method, $uri, $callback]; - - // 2 --------------------------------------------------------------------------------------> - - // reuse callback from #1 - $method = 'PUT'; - $uri = '/not-found'; - - $cases[] = [$method, $uri, $callback]; - - // 3 --------------------------------------------------------------------------------------> - - $callback = function(RouteCollector $r) { - $r->addRoute('GET', '/handler0', 'handler0'); - $r->addRoute('GET', '/handler1', 'handler1'); - $r->addRoute('GET', '/handler2', 'handler2'); - }; - - $method = 'GET'; - $uri = '/not-found'; - - $cases[] = [$method, $uri, $callback]; - - // 4 --------------------------------------------------------------------------------------> - - $callback = function(RouteCollector $r) { - $r->addRoute('GET', '/user/{name}/{id:[0-9]+}', 'handler0'); - $r->addRoute('GET', '/user/{id:[0-9]+}', 'handler1'); - $r->addRoute('GET', '/user/{name}', 'handler2'); - }; - - $method = 'GET'; - $uri = '/not-found'; - - $cases[] = [$method, $uri, $callback]; - - // 5 --------------------------------------------------------------------------------------> - - // reuse callback from #4 - $method = 'GET'; - $uri = '/user/rdlowrey/12345/not-found'; - - $cases[] = [$method, $uri, $callback]; - - // 6 --------------------------------------------------------------------------------------> - - // reuse callback from #5 - $method = 'HEAD'; - - $cases[] = array($method, $uri, $callback); - - // x --------------------------------------------------------------------------------------> - - return $cases; - } - - public function provideMethodNotAllowedDispatchCases() { - $cases = []; - - // 0 --------------------------------------------------------------------------------------> - - $callback = function(RouteCollector $r) { - $r->addRoute('GET', '/resource/123/456', 'handler0'); - }; - - $method = 'POST'; - $uri = '/resource/123/456'; - $allowedMethods = ['GET']; - - $cases[] = [$method, $uri, $callback, $allowedMethods]; - - // 1 --------------------------------------------------------------------------------------> - - $callback = function(RouteCollector $r) { - $r->addRoute('GET', '/resource/123/456', 'handler0'); - $r->addRoute('POST', '/resource/123/456', 'handler1'); - $r->addRoute('PUT', '/resource/123/456', 'handler2'); - }; - - $method = 'DELETE'; - $uri = '/resource/123/456'; - $allowedMethods = ['GET', 'POST', 'PUT']; - - $cases[] = [$method, $uri, $callback, $allowedMethods]; - - // 2 --------------------------------------------------------------------------------------> - - $callback = function(RouteCollector $r) { - $r->addRoute('GET', '/user/{name}/{id:[0-9]+}', 'handler0'); - $r->addRoute('POST', '/user/{name}/{id:[0-9]+}', 'handler1'); - $r->addRoute('PUT', '/user/{name}/{id:[0-9]+}', 'handler2'); - $r->addRoute('PATCH', '/user/{name}/{id:[0-9]+}', 'handler3'); - }; - - $method = 'DELETE'; - $uri = '/user/rdlowrey/42'; - $allowedMethods = ['GET', 'POST', 'PUT', 'PATCH']; - - $cases[] = [$method, $uri, $callback, $allowedMethods]; - - // 3 --------------------------------------------------------------------------------------> - - $callback = function(RouteCollector $r) { - $r->addRoute('POST', '/user/{name}', 'handler1'); - $r->addRoute('PUT', '/user/{name:[a-z]+}', 'handler2'); - $r->addRoute('PATCH', '/user/{name:[a-z]+}', 'handler3'); - }; - - $method = 'GET'; - $uri = '/user/rdlowrey'; - $allowedMethods = ['POST', 'PUT', 'PATCH']; - - $cases[] = [$method, $uri, $callback, $allowedMethods]; - - // x --------------------------------------------------------------------------------------> - - return $cases; - } - -} diff --git a/core/components/fastrouter/vendor/nikic/fast-route/test/Dispatcher/GroupCountBasedTest.php b/core/components/fastrouter/vendor/nikic/fast-route/test/Dispatcher/GroupCountBasedTest.php deleted file mode 100644 index 74820fc..0000000 --- a/core/components/fastrouter/vendor/nikic/fast-route/test/Dispatcher/GroupCountBasedTest.php +++ /dev/null @@ -1,13 +0,0 @@ -markTestSkipped('PHP 5.6 required for MARK support'); - } - } - - protected function getDispatcherClass() { - return 'FastRoute\\Dispatcher\\MarkBased'; - } - - protected function getDataGeneratorClass() { - return 'FastRoute\\DataGenerator\\MarkBased'; - } -} diff --git a/core/components/fastrouter/vendor/nikic/fast-route/test/bootstrap.php b/core/components/fastrouter/vendor/nikic/fast-route/test/bootstrap.php deleted file mode 100644 index 27e6d4c..0000000 --- a/core/components/fastrouter/vendor/nikic/fast-route/test/bootstrap.php +++ /dev/null @@ -1,11 +0,0 @@ -