Skip to content

Commit

Permalink
Ability to exclude routes using attributes instead of re-defining rou…
Browse files Browse the repository at this point in the history
…tes resolution method (#594)

* attributes to exclude routes

* Fix styling

---------

Co-authored-by: romalytvynenko <[email protected]>
  • Loading branch information
romalytvynenko and romalytvynenko authored Oct 22, 2024
1 parent 65e2842 commit 1a7547b
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 0 deletions.
11 changes: 11 additions & 0 deletions src/Attributes/ExcludeAllRoutesFromDocs.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace Dedoc\Scramble\Attributes;

use Attribute;

/**
* Excludes all routes of a controller from the API documentation. Applies to controller's methods.
*/
#[Attribute(Attribute::TARGET_CLASS)]
class ExcludeAllRoutesFromDocs {}
11 changes: 11 additions & 0 deletions src/Attributes/ExcludeRouteFromDocs.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace Dedoc\Scramble\Attributes;

use Attribute;

/**
* Excludes a route from API documentation. Applies to controller's methods.
*/
#[Attribute(Attribute::TARGET_METHOD | Attribute::TARGET_FUNCTION)]
class ExcludeRouteFromDocs {}
27 changes: 27 additions & 0 deletions src/Generator.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace Dedoc\Scramble;

use Dedoc\Scramble\Attributes\ExcludeAllRoutesFromDocs;
use Dedoc\Scramble\Attributes\ExcludeRouteFromDocs;
use Dedoc\Scramble\Exceptions\RouteAware;
use Dedoc\Scramble\Infer\Services\FileParser;
use Dedoc\Scramble\OpenApiVisitor\SchemaEnforceVisitor;
Expand Down Expand Up @@ -146,6 +148,31 @@ private function getRoutes(GeneratorConfig $config): Collection
})
->filter($config->routes())
->filter(fn (Route $r) => $r->getAction('controller'))
->filter(function (Route $route) {
if (! is_string($route->getAction('uses'))) {
return true;
}

try {
$classReflection = new \ReflectionClass(explode('@', $route->getAction('uses'))[0]);

if (count($classReflection->getAttributes(ExcludeAllRoutesFromDocs::class))) {
return false;
}
} catch (Throwable) {
}

try {
$reflection = new \ReflectionMethod(...explode('@', $route->getAction('uses')));

if (count($reflection->getAttributes(ExcludeRouteFromDocs::class))) {
return false;
}
} catch (Throwable) {
}

return true;
})
->values();
}

Expand Down
52 changes: 52 additions & 0 deletions tests/Generator/RoutesFilteringTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

use Dedoc\Scramble\Attributes\ExcludeAllRoutesFromDocs;
use Dedoc\Scramble\Attributes\ExcludeRouteFromDocs;
use Dedoc\Scramble\Scramble;
use Illuminate\Routing\Route;
use Illuminate\Support\Facades\Route as RouteFacade;

function RoutesFilteringTest_generateForRoutes($callback)
{
$routesUris = array_map(
fn (Route $r) => $r->uri,
$callback()
);

Scramble::routes(fn (Route $r) => in_array($r->uri, $routesUris));

return app()->make(\Dedoc\Scramble\Generator::class)();
}

it('filters routes with ExcludeRouteFromDocs attribute', function () {
$documentation = RoutesFilteringTest_generateForRoutes(fn () => [
RouteFacade::post('foo', [RoutesFilteringTest_ControllerA::class, 'foo']),
RouteFacade::post('bar', [RoutesFilteringTest_ControllerA::class, 'bar']),
]);

expect(array_keys($documentation['paths']))->toBe(['/foo']);
});
class RoutesFilteringTest_ControllerA
{
public function foo() {}

#[ExcludeRouteFromDocs]
public function bar() {}
}

it('filters all controller routes with ExcludeAllRoutesFromDocs attribute', function () {
$documentation = RoutesFilteringTest_generateForRoutes(fn () => [
RouteFacade::post('foo', [RoutesFilteringTest_ControllerB::class, 'foo']),
RouteFacade::post('bar', [RoutesFilteringTest_ControllerB::class, 'bar']),
]);

expect(array_keys($documentation['paths'] ?? []))->toBe([]);
});

#[ExcludeAllRoutesFromDocs]
class RoutesFilteringTest_ControllerB
{
public function foo() {}

public function bar() {}
}

0 comments on commit 1a7547b

Please sign in to comment.