diff --git a/system/Filters/Filters.php b/system/Filters/Filters.php index 31e96432a714..5cef2f08ad1a 100644 --- a/system/Filters/Filters.php +++ b/system/Filters/Filters.php @@ -62,6 +62,24 @@ class Filters 'after' => [], ]; + /** + * The collection of filters' class names that will + * be used to execute in each position. + * + * @var array + */ + protected $filtersClass = [ + 'before' => [], + 'after' => [], + ]; + + /** + * Any arguments to be passed to filtersClass. + * + * @var array + */ + protected $argumentsClass = []; + /** * The original config file * @@ -179,72 +197,49 @@ public function run(string $uri, string $position = 'before') { $this->initialize(strtolower($uri)); - foreach ($this->filters[$position] as $alias => $rules) + foreach ($this->filtersClass[$position] as $className) { - if (is_numeric($alias) && is_string($rules)) - { - $alias = $rules; - } + $class = new $className(); - if (! array_key_exists($alias, $this->config->aliases)) + if (! $class instanceof FilterInterface) { - throw FilterException::forNoAlias($alias); + throw FilterException::forIncorrectInterface(get_class($class)); } - if (is_array($this->config->aliases[$alias])) + if ($position === 'before') { - $classNames = $this->config->aliases[$alias]; - } - else - { - $classNames = [$this->config->aliases[$alias]]; - } + $result = $class->before($this->request, $this->argumentsClass[$className] ?? null); - foreach ($classNames as $className) - { - $class = new $className(); - - if (! $class instanceof FilterInterface) + if ($result instanceof RequestInterface) { - throw FilterException::forIncorrectInterface(get_class($class)); + $this->request = $result; + continue; } - if ($position === 'before') + // If the response object was sent back, + // then send it and quit. + if ($result instanceof ResponseInterface) { - $result = $class->before($this->request, $this->arguments[$alias] ?? null); - - if ($result instanceof RequestInterface) - { - $this->request = $result; - continue; - } - - // If the response object was sent back, - // then send it and quit. - if ($result instanceof ResponseInterface) - { - // short circuit - bypass any other filters - return $result; - } - - // Ignore an empty result - if (empty($result)) - { - continue; - } - + // short circuit - bypass any other filters return $result; } - - if ($position === 'after') + // Ignore an empty result + if (empty($result)) { - $result = $class->after($this->request, $this->response, $this->arguments[$alias] ?? null); + continue; + } - if ($result instanceof ResponseInterface) - { - $this->response = $result; - continue; - } + return $result; + } + + if ($position === 'after') + { + $result = $class->after($this->request, $this->response, $this->argumentsClass[$className] ?? null); + + if ($result instanceof ResponseInterface) + { + $this->response = $result; + continue; } } } @@ -296,6 +291,9 @@ public function initialize(string $uri = null) $this->filters['after'][] = 'toolbar'; } + $this->processAliasesToClass('before'); + $this->processAliasesToClass('after'); + $this->initialized = true; return $this; @@ -313,6 +311,16 @@ public function getFilters(): array return $this->filters; } + /** + * Returns the filtersClass array. + * + * @return array + */ + public function getFiltersClass(): array + { + return $this->filtersClass; + } + /** * Adds a new alias to the config file. * MUST be called prior to initialize(); @@ -380,16 +388,22 @@ public function enableFilter(string $name, string $when = 'before') throw FilterException::forNoAlias($name); } + $classNames = (array) $this->config->aliases[$name]; + + foreach ($classNames as $className) + { + $this->argumentsClass[$className] = $this->arguments[$name] ?? null; + } + if (! isset($this->filters[$when][$name])) { - $this->filters[$when][] = $name; + $this->filters[$when][] = $name; + $this->filtersClass[$when] = array_merge($this->filtersClass[$when], $classNames); } return $this; } - //-------------------------------------------------------------------- - /** * Returns the arguments for a specified key, or all. * @@ -530,6 +544,38 @@ protected function processFilters(string $uri = null) } } + /** + * Maps filter aliases to the equivalent filter classes + * + * @throws FilterException + * + * @return void + */ + protected function processAliasesToClass(string $position) + { + foreach ($this->filters[$position] as $alias => $rules) + { + if (is_numeric($alias) && is_string($rules)) + { + $alias = $rules; + } + + if (! array_key_exists($alias, $this->config->aliases)) + { + throw FilterException::forNoAlias($alias); + } + + if (is_array($this->config->aliases[$alias])) + { + $this->filtersClass[$position] = array_merge($this->filtersClass[$position], $this->config->aliases[$alias]); + } + else + { + $this->filtersClass[$position][] = $this->config->aliases[$alias]; + } + } + } + /** * Check paths for match for URI * diff --git a/system/View/View.php b/system/View/View.php index f388a0bee7ee..a2f506a39948 100644 --- a/system/View/View.php +++ b/system/View/View.php @@ -261,7 +261,7 @@ public function render(string $view, array $options = null, bool $saveData = nul $this->logPerformance($this->renderVars['start'], microtime(true), $this->renderVars['view']); - if ($this->debug && (! isset($options['debug']) || $options['debug'] === true)) + if (($this->debug && (! isset($options['debug']) || $options['debug'] === true)) && in_array('CodeIgniter\Filters\DebugToolbar', service('filters')->getFiltersClass()['after'], true)) { $toolbarCollectors = config(\Config\Toolbar::class)->collectors; diff --git a/tests/system/Filters/FiltersTest.php b/tests/system/Filters/FiltersTest.php index 36efe961d47f..186beb87c4b7 100644 --- a/tests/system/Filters/FiltersTest.php +++ b/tests/system/Filters/FiltersTest.php @@ -45,6 +45,7 @@ protected function setUp(): void public function testProcessMethodDetectsCLI() { $config = [ + 'aliases' => ['foo' => ''], 'methods' => [ 'cli' => ['foo'], ], @@ -66,6 +67,7 @@ public function testProcessMethodDetectsGetRequests() $_SERVER['REQUEST_METHOD'] = 'GET'; $config = [ + 'aliases' => ['foo' => ''], 'methods' => [ 'get' => ['foo'], ], @@ -88,6 +90,10 @@ public function testProcessMethodRespectsMethod() $_SERVER['REQUEST_METHOD'] = 'GET'; $config = [ + 'aliases' => [ + 'foo' => '', + 'bar' => '', + ], 'methods' => [ 'post' => ['foo'], 'get' => ['bar'], @@ -108,6 +114,10 @@ public function testProcessMethodIgnoresMethod() $_SERVER['REQUEST_METHOD'] = 'DELETE'; $config = [ + 'aliases' => [ + 'foo' => '', + 'bar' => '', + ], 'methods' => [ 'post' => ['foo'], 'get' => ['bar'], @@ -130,6 +140,11 @@ public function testProcessMethodProcessGlobals() $_SERVER['REQUEST_METHOD'] = 'GET'; $config = [ + 'aliases' => [ + 'foo' => '', + 'bar' => '', + 'baz' => '', + ], 'globals' => [ 'before' => [ 'foo' => ['bar'], // not excluded @@ -175,6 +190,11 @@ public function testProcessMethodProcessGlobalsWithExcept(array $except) $_SERVER['REQUEST_METHOD'] = 'GET'; $config = [ + 'aliases' => [ + 'foo' => '', + 'bar' => '', + 'baz' => '', + ], 'globals' => [ 'before' => [ 'foo' => ['except' => $except], @@ -205,6 +225,11 @@ public function testProcessMethodProcessesFiltersBefore() $_SERVER['REQUEST_METHOD'] = 'GET'; $config = [ + 'aliases' => [ + 'foo' => '', + 'bar' => '', + 'baz' => '', + ], 'filters' => [ 'foo' => [ 'before' => ['admin/*'], @@ -230,6 +255,11 @@ public function testProcessMethodProcessesFiltersAfter() $_SERVER['REQUEST_METHOD'] = 'GET'; $config = [ + 'aliases' => [ + 'foo' => '', + 'bar' => '', + 'baz' => '', + ], 'filters' => [ 'foo' => [ 'before' => ['admin/*'], @@ -257,6 +287,14 @@ public function testProcessMethodProcessesCombined() $_SERVER['REQUEST_METHOD'] = 'GET'; $config = [ + 'aliases' => [ + 'foog' => '', + 'barg' => '', + 'bazg' => '', + 'foo' => '', + 'bar' => '', + 'foof' => '', + ], 'globals' => [ 'before' => [ 'foog' => ['except' => ['admin/*']], @@ -299,6 +337,12 @@ public function testProcessMethodProcessesCombinedAfterForToolbar() $_SERVER['REQUEST_METHOD'] = 'GET'; $config = [ + 'aliases' => [ + 'toolbar' => '', + 'bazg' => '', + 'bar' => '', + 'foof' => '', + ], 'globals' => [ 'after' => [ 'toolbar', @@ -495,6 +539,11 @@ public function testBeforeExceptString() $_SERVER['REQUEST_METHOD'] = 'GET'; $config = [ + 'aliases' => [ + 'foo' => '', + 'bar' => '', + 'baz' => '', + ], 'globals' => [ 'before' => [ 'foo' => ['except' => 'admin/*'], @@ -523,6 +572,11 @@ public function testBeforeExceptInapplicable() $_SERVER['REQUEST_METHOD'] = 'GET'; $config = [ + 'aliases' => [ + 'foo' => '', + 'bar' => '', + 'baz' => '', + ], 'globals' => [ 'before' => [ 'foo' => ['except' => 'george/*'], @@ -552,6 +606,11 @@ public function testAfterExceptString() $_SERVER['REQUEST_METHOD'] = 'GET'; $config = [ + 'aliases' => [ + 'foo' => '', + 'bar' => '', + 'baz' => '', + ], 'globals' => [ 'before' => [ 'bar' @@ -580,6 +639,11 @@ public function testAfterExceptInapplicable() $_SERVER['REQUEST_METHOD'] = 'GET'; $config = [ + 'aliases' => [ + 'foo' => '', + 'bar' => '', + 'baz' => '', + ], 'globals' => [ 'before' => [ 'bar' @@ -774,6 +838,12 @@ public function testMatchesURICaseInsensitively() $_SERVER['REQUEST_METHOD'] = 'GET'; $config = [ + 'aliases' => [ + 'foo' => '', + 'bar' => '', + 'frak' => '', + 'baz' => '', + ], 'globals' => [ 'before' => [ 'foo' => ['except' => 'Admin/*'], @@ -816,6 +886,11 @@ public function testFilterMatching() $_SERVER['REQUEST_METHOD'] = 'GET'; $config = [ + 'aliases' => [ + 'foo' => '', + 'bar' => '', + 'frak' => '', + ], 'filters' => [ 'frak' => [ 'before' => ['admin*'], @@ -846,6 +921,11 @@ public function testGlobalFilterMatching() $_SERVER['REQUEST_METHOD'] = 'GET'; $config = [ + 'aliases' => [ + 'foo' => '', + 'one' => '', + 'two' => '', + ], 'globals' => [ 'before' => [ 'foo' => ['except' => 'admin*'], @@ -883,6 +963,12 @@ public function testCombinedFilterMatching() $_SERVER['REQUEST_METHOD'] = 'GET'; $config = [ + 'aliases' => [ + 'foo' => '', + 'one' => '', + 'frak' => '', + 'two' => '', + ], 'globals' => [ 'before' => [ 'foo' => ['except' => 'admin*'], @@ -926,6 +1012,11 @@ public function testSegmentedFilterMatching() $_SERVER['REQUEST_METHOD'] = 'GET'; $config = [ + 'aliases' => [ + 'foo' => '', + 'one' => '', + 'frak' => '', + ], 'globals' => [ 'before' => [ 'foo' => ['except' => 'admin*'], @@ -983,4 +1074,33 @@ public function testFilterAlitasMultiple() $this->assertEquals('http://exampleMultipleCSP.com', $request->csp); } + public function testFilterClass() + { + $config = [ + 'aliases' => [ + 'multipleTest' => [ + 'CodeIgniter\Filters\fixtures\Multiple1', + 'CodeIgniter\Filters\fixtures\Multiple2', + ], + ], + 'globals' => [ + 'after' => [ + 'multipleTest', + ], + ], + ]; + $filters = new Filters((object) $config, $this->request, $this->response); + $uri = 'admin/foo/bar'; + + $filters->run($uri, 'before'); + $expected = [ + 'after' => [ + 'CodeIgniter\Filters\fixtures\Multiple1', + 'CodeIgniter\Filters\fixtures\Multiple2', + ], + 'before' => [], + ]; + $this->assertEquals($expected, $filters->getFiltersClass()); + } + }