Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion system/Router/Attributes/Filter.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,6 @@ public function getFilters(): array
return [$this->by];
}

return [$this->by => $this->having];
return [$this->by . ':' . implode(',', $this->having)];
}
}
11 changes: 11 additions & 0 deletions tests/_support/Router/Controllers/AttributeController.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,17 @@ public function filtered(): ResponseInterface
return $this->response->setBody('Filtered: ' . $body);
}

/**
* Test method with Filter attribute with parameters
*/
#[Filter(by: 'testAttributeFilter', having: ['arg1', 'arg2'])]
public function filteredWithParams(): ResponseInterface
{
$body = $this->request->getBody();

return $this->response->setBody('Filtered: ' . $body);
}

/**
* Test method with Restrict attribute (environment)
*/
Expand Down
10 changes: 8 additions & 2 deletions tests/_support/Router/Filters/TestAttributeFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,23 @@ class TestAttributeFilter implements FilterInterface
{
public function before(RequestInterface $request, $arguments = null)
{
if ($arguments !== null) {
$arguments = '(' . implode(',', $arguments) . ')';
}
// Modify request body to indicate filter ran
$request->setBody('before_filter_ran:');
$request->setBody('before_filter_ran' . $arguments . ':');

return $request;
}

public function after(RequestInterface $request, ResponseInterface $response, $arguments = null)
{
if ($arguments !== null) {
$arguments = '(' . implode(',', $arguments) . ')';
}
// Append to response body to indicate filter ran
$body = $response->getBody();
$response->setBody($body . ':after_filter_ran');
$response->setBody($body . ':after_filter_ran' . $arguments);

return $response;
}
Expand Down
28 changes: 28 additions & 0 deletions tests/system/CodeIgniterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1062,6 +1062,34 @@ public function testRouteAttributeFilterIntegration(): void
$this->assertStringContainsString(':after_filter_ran', (string) $output);
}

public function testRouteAttributeFilterWithParamsIntegration(): void
{
$_SERVER['argv'] = ['index.php', 'attribute/filteredWithParams'];
$_SERVER['argc'] = 2;

Services::superglobals()->setServer('REQUEST_URI', '/attribute/filteredWithParams');
Services::superglobals()->setServer('SCRIPT_NAME', '/index.php');

// Register the test filter
$filterConfig = config('Filters');
$filterConfig->aliases['testAttributeFilter'] = TestAttributeFilter::class;
service('filters', $filterConfig);

// Inject mock router
$routes = service('routes');
$routes->get('attribute/filteredWithParams', '\Tests\Support\Router\Controllers\AttributeController::filteredWithParams');
$router = service('router', $routes, service('incomingrequest'));
Services::injectMock('router', $router);

ob_start();
$this->codeigniter->run();
$output = ob_get_clean();

// Verify filter ran before (modified request body) and after (appended to response)
$this->assertStringContainsString('Filtered: before_filter_ran(arg1,arg2):', (string) $output);
$this->assertStringContainsString(':after_filter_ran(arg1,arg2)', (string) $output);
}

public function testRouteAttributeRestrictIntegration(): void
{
$_SERVER['argv'] = ['index.php', 'attribute/restricted'];
Expand Down
30 changes: 14 additions & 16 deletions tests/system/Router/Attributes/FilterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,7 @@ public function testGetFiltersReturnsArrayWithFilterNameAndArguments(): void
$filters = $filter->getFilters();

$this->assertCount(1, $filters);
$this->assertArrayHasKey('auth', $filters);
$this->assertSame(['admin'], $filters['auth']);
$this->assertSame('auth:admin', $filters[0]);
}

public function testGetFiltersReturnsArrayWithMultipleArguments(): void
Expand All @@ -101,8 +100,7 @@ public function testGetFiltersReturnsArrayWithMultipleArguments(): void
$filters = $filter->getFilters();

$this->assertCount(1, $filters);
$this->assertArrayHasKey('permission', $filters);
$this->assertSame(['posts.edit', 'posts.delete'], $filters['permission']);
$this->assertSame('permission:posts.edit,posts.delete', $filters[0]);
}

public function testGetFiltersWithEmptyHavingReturnsSimpleArray(): void
Expand Down Expand Up @@ -135,13 +133,13 @@ public function testGetFiltersFormatIsConsistentAcrossInstances(): void
$filters1 = $filterWithoutArgs->getFilters();
$filters2 = $filterWithArgs->getFilters();

// Without args: simple array
$this->assertArrayNotHasKey('filter1', $filters1);
$this->assertContains('filter1', $filters1);
// Without args:
$this->assertCount(1, $filters1);
$this->assertSame('filter1', $filters1[0]);

// With args: associative array
$this->assertArrayHasKey('filter2', $filters2);
$this->assertIsArray($filters2['filter2']);
// With args:
$this->assertCount(1, $filters2);
$this->assertSame('filter2:arg1', $filters2[0]);
}

public function testFilterWithNumericArguments(): void
Expand All @@ -150,8 +148,8 @@ public function testFilterWithNumericArguments(): void

$filters = $filter->getFilters();

$this->assertArrayHasKey('rate_limit', $filters);
$this->assertSame([100, 60], $filters['rate_limit']);
$this->assertCount(1, $filters);
$this->assertSame('rate_limit:100,60', $filters[0]);
}

public function testFilterWithMixedTypeArguments(): void
Expand All @@ -160,8 +158,8 @@ public function testFilterWithMixedTypeArguments(): void

$filters = $filter->getFilters();

$this->assertArrayHasKey('custom', $filters);
$this->assertSame(['string', 123, true], $filters['custom']);
$this->assertCount(1, $filters);
$this->assertSame('custom:string,123,1', $filters[0]);
}

public function testFilterWithAssociativeArrayArguments(): void
Expand All @@ -170,8 +168,8 @@ public function testFilterWithAssociativeArrayArguments(): void

$filters = $filter->getFilters();

$this->assertArrayHasKey('configured', $filters);
$this->assertSame(['option1' => 'value1', 'option2' => 'value2'], $filters['configured']);
$this->assertCount(1, $filters);
$this->assertSame('configured:value1,value2', $filters[0]);
}

public function testBeforeDoesNotModifyRequest(): void
Expand Down
6 changes: 5 additions & 1 deletion user_guide_src/source/incoming/controller_attributes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,15 @@ The ``Filters`` attribute allows you to specify one or more filters to be applie

When filters are applied both by an attribute and in the filter configuration file, they will both be applied, but that could lead to unexpected results.

.. note::

Please remember that every parameter applied to the filter will be converted to a string. This behavior affects only filters.

Restrict
--------

The ``Restrict`` attribute allows you to restrict access to the class or method based on the domain, the sub-domain, or
the environment the application is running in. Here's an exmaple of how to use the ``Restrict`` attribute:
the environment the application is running in. Here's an example of how to use the ``Restrict`` attribute:

.. literalinclude:: controller_attributes/004.php

Expand Down
Loading