diff --git a/packages/core/src/Kernel/LoadDiscoveryClasses.php b/packages/core/src/Kernel/LoadDiscoveryClasses.php index 6c7e2c65e3..b001132626 100644 --- a/packages/core/src/Kernel/LoadDiscoveryClasses.php +++ b/packages/core/src/Kernel/LoadDiscoveryClasses.php @@ -4,6 +4,7 @@ namespace Tempest\Core\Kernel; +use Exception; use Tempest\Container\Container; use Tempest\Core\DiscoveryCache; use Tempest\Core\DiscoveryCacheStrategy; @@ -198,11 +199,27 @@ private function scan(DiscoveryLocation $location, array $discoveries, string $p // Resolve `#[SkipDiscovery]` for this class $skipDiscovery = $input->getAttribute(SkipDiscovery::class); - if ($skipDiscovery !== null && $skipDiscovery->except === []) { - $this->shouldSkipForClass[$className] = true; - } elseif ($skipDiscovery !== null) { - foreach ($skipDiscovery->except as $except) { - $this->shouldSkipForClass[$className][$except] = true; + if ($skipDiscovery !== null) { + $when = false; + // Evaluate conditional skip + if ($skipDiscovery->when !== null) { + try { + $when = (bool) $this->container->invoke($skipDiscovery->when); + } catch (Throwable $throw) { + throw new Exception($throw->getMessage(), 0, $throw); + } + } + + $shouldApply = $skipDiscovery->when === null || $when; + + if ($shouldApply) { + if ($skipDiscovery->except === []) { + $this->shouldSkipForClass[$className] = true; + } else { + foreach ($skipDiscovery->except as $except) { + $this->shouldSkipForClass[$className][$except] = true; + } + } } } diff --git a/packages/discovery/src/SkipDiscovery.php b/packages/discovery/src/SkipDiscovery.php index fe8e56d0d0..90c05aa61c 100644 --- a/packages/discovery/src/SkipDiscovery.php +++ b/packages/discovery/src/SkipDiscovery.php @@ -5,6 +5,7 @@ namespace Tempest\Discovery; use Attribute; +use Closure; /** * Instruct Tempest to not discover this class. @@ -15,8 +16,10 @@ public function __construct( /** * Allows the specified `Discovery` classes to still discover this class. - * @var array> + * @param array> + * @param Closure|null */ public array $except = [], + public ?Closure $when = null, ) {} } diff --git a/tests/Fixtures/Discovery/ConditionallyHiddenDatabaseMigration.php b/tests/Fixtures/Discovery/ConditionallyHiddenDatabaseMigration.php new file mode 100644 index 0000000000..9dcef39d85 --- /dev/null +++ b/tests/Fixtures/Discovery/ConditionallyHiddenDatabaseMigration.php @@ -0,0 +1,26 @@ +primary(); + } +} diff --git a/tests/Integration/Core/LoadDiscoveryClassesTest.php b/tests/Integration/Core/LoadDiscoveryClassesTest.php index 29a21db43b..bf4df63745 100644 --- a/tests/Integration/Core/LoadDiscoveryClassesTest.php +++ b/tests/Integration/Core/LoadDiscoveryClassesTest.php @@ -10,6 +10,7 @@ use Tempest\Database\Migrations\RunnableMigrations; use Tempest\Discovery\DiscoveryLocation; use Tempest\Support\Arr; +use Tests\Tempest\Fixtures\Discovery\ConditionallyHiddenDatabaseMigration; use Tests\Tempest\Fixtures\Discovery\HiddenDatabaseMigration; use Tests\Tempest\Fixtures\Discovery\HiddenMigratableDatabaseMigration; use Tests\Tempest\Fixtures\GlobalHiddenDiscovery; @@ -81,4 +82,11 @@ public function only_load_specific_discovery_classes(): void $this->assertTrue($dependency->discovered); } + + #[Test] + public function does_not_load_conditionally_hidden_classes(): void + { + $migrations = $this->container->get(RunnableMigrations::class); + $this->assertFalse(Arr\contains($migrations, fn ($m) => $m instanceof ConditionallyHiddenDatabaseMigration)); + } }