Skip to content

Commit 7b3cc70

Browse files
authored
feat(core): add discovery config (#1198)
1 parent f267de2 commit 7b3cc70

File tree

9 files changed

+141
-27
lines changed

9 files changed

+141
-27
lines changed

packages/core/src/Commands/DiscoveryGenerateCommand.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use Tempest\Container\Container;
1212
use Tempest\Container\GenericContainer;
1313
use Tempest\Core\DiscoveryCache;
14+
use Tempest\Core\DiscoveryConfig;
1415
use Tempest\Core\FrameworkKernel;
1516
use Tempest\Core\Kernel;
1617
use Tempest\Core\Kernel\LoadDiscoveryClasses;
@@ -59,6 +60,7 @@ public function generateDiscoveryCache(DiscoveryCacheStrategy $strategy, Closure
5960
$loadDiscoveryClasses = new LoadDiscoveryClasses(
6061
kernel: $kernel,
6162
container: $kernel->container,
63+
discoveryConfig: $kernel->container->get(DiscoveryConfig::class),
6264
discoveryCache: $this->discoveryCache,
6365
);
6466

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Tempest\Core\DiscoveryConfig;
6+
7+
return new DiscoveryConfig();
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
namespace Tempest\Core;
4+
5+
final class DiscoveryConfig
6+
{
7+
private array $skipDiscovery = [];
8+
9+
public function shouldSkip(string $input): bool
10+
{
11+
return $this->skipDiscovery[$input] ?? false;
12+
}
13+
14+
public function skipClasses(string ...$classNames): self
15+
{
16+
foreach ($classNames as $className) {
17+
$this->skipDiscovery[$className] = true;
18+
}
19+
20+
return $this;
21+
}
22+
23+
public function skipPaths(string ...$paths): self
24+
{
25+
foreach ($paths as $path) {
26+
$path = str_replace(['\\', '/'], DIRECTORY_SEPARATOR, $path);
27+
28+
$realpath = realpath($path);
29+
30+
if ($realpath === false) {
31+
continue;
32+
}
33+
34+
$this->skipDiscovery[$realpath] = true;
35+
}
36+
37+
return $this;
38+
}
39+
}

packages/core/src/Kernel/LoadDiscoveryClasses.php

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use Tempest\Cache\DiscoveryCacheStrategy;
1212
use Tempest\Container\Container;
1313
use Tempest\Core\DiscoveryCache;
14+
use Tempest\Core\DiscoveryConfig;
1415
use Tempest\Core\DiscoveryDiscovery;
1516
use Tempest\Core\Kernel;
1617
use Tempest\Discovery\DiscoversPath;
@@ -29,6 +30,7 @@ final class LoadDiscoveryClasses
2930
public function __construct(
3031
private readonly Kernel $kernel,
3132
private readonly Container $container,
33+
private readonly DiscoveryConfig $discoveryConfig,
3234
private readonly DiscoveryCache $discoveryCache,
3335
) {}
3436

@@ -100,6 +102,7 @@ private function buildDiscovery(string $discoveryClass): Discovery
100102
/** @var SplFileInfo $file */
101103
foreach ($files as $file) {
102104
$fileName = $file->getFilename();
105+
103106
if ($fileName === '') {
104107
continue;
105108
}
@@ -112,7 +115,11 @@ private function buildDiscovery(string $discoveryClass): Discovery
112115
continue;
113116
}
114117

115-
$input = $file->getPathname();
118+
$input = $file->getRealPath();
119+
120+
if ($this->shouldSkipBasedOnConfig($input)) {
121+
continue;
122+
}
116123

117124
// We assume that any PHP file that starts with an uppercase letter will be a class
118125
if ($file->getExtension() === 'php' && ucfirst($fileName) === $fileName) {
@@ -131,14 +138,18 @@ private function buildDiscovery(string $discoveryClass): Discovery
131138
}
132139
}
133140

141+
if ($this->shouldSkipBasedOnConfig($input)) {
142+
continue;
143+
}
144+
134145
if ($input instanceof ClassReflector) {
135146
// If the input is a class, we'll call `discover`
136147
if (! $this->shouldSkipDiscoveryForClass($discovery, $input)) {
137148
$discovery->discover($location, $input);
138149
}
139150
} elseif ($discovery instanceof DiscoversPath) {
140151
// If the input is NOT a class, AND the discovery class can discover paths, we'll call `discoverPath`
141-
$discovery->discoverPath($location, realpath($input));
152+
$discovery->discoverPath($location, $input);
142153
}
143154
}
144155
}
@@ -160,6 +171,15 @@ private function applyDiscovery(Discovery $discovery): void
160171
$this->appliedDiscovery[$discovery::class] = true;
161172
}
162173

174+
private function shouldSkipBasedOnConfig(ClassReflector|string $input): bool
175+
{
176+
if ($input instanceof ClassReflector) {
177+
$input = $input->getName();
178+
}
179+
180+
return $this->discoveryConfig->shouldSkip($input);
181+
}
182+
163183
/**
164184
* Check whether discovery for a specific class should be skipped based on the #[SkipDiscovery] attribute
165185
*/

packages/core/src/Kernel/LoadDiscoveryLocations.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ public function __construct(
2222
public function __invoke(): void
2323
{
2424
$this->kernel->discoveryLocations = [
25-
...$this->kernel->discoveryLocations,
2625
...$this->discoverCorePackages(),
2726
...$this->discoverVendorPackages(),
2827
...$this->discoverAppNamespaces(),
28+
...$this->kernel->discoveryLocations,
2929
];
3030
}
3131

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
use Tempest\Core\DiscoveryConfig;
4+
use Tests\Tempest\Fixtures\GlobalHiddenDiscovery;
5+
6+
return new DiscoveryConfig()
7+
->skipClasses(GlobalHiddenDiscovery::class)
8+
->skipPaths(__DIR__ . '/../../Fixtures/GlobalHiddenPathDiscovery.php');
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
namespace Tests\Tempest\Fixtures;
4+
5+
use Tempest\Discovery\Discovery;
6+
use Tempest\Discovery\DiscoveryLocation;
7+
use Tempest\Discovery\IsDiscovery;
8+
use Tempest\Reflection\ClassReflector;
9+
10+
final class GlobalHiddenDiscovery implements Discovery
11+
{
12+
public static bool $discovered = false;
13+
14+
use IsDiscovery;
15+
16+
public function discover(DiscoveryLocation $location, ClassReflector $class): void
17+
{
18+
}
19+
20+
public function apply(): void
21+
{
22+
self::$discovered = true;
23+
}
24+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
namespace Tests\Tempest\Fixtures;
4+
5+
use Tempest\Discovery\Discovery;
6+
use Tempest\Discovery\DiscoveryLocation;
7+
use Tempest\Discovery\IsDiscovery;
8+
use Tempest\Reflection\ClassReflector;
9+
10+
final class GlobalHiddenPathDiscovery implements Discovery
11+
{
12+
public static bool $discovered = false;
13+
14+
use IsDiscovery;
15+
16+
public function discover(DiscoveryLocation $location, ClassReflector $class): void
17+
{
18+
}
19+
20+
public function apply(): void
21+
{
22+
self::$discovered = true;
23+
}
24+
}

tests/Integration/Core/LoadDiscoveryClassesTest.php

Lines changed: 14 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@
55
namespace Tests\Tempest\Integration\Core;
66

77
use PHPUnit\Framework\Attributes\Test;
8+
use Tempest\Core\DiscoveryConfig;
89
use Tempest\Database\DatabaseMigration;
9-
use Tempest\Database\MigrationDiscovery;
1010
use Tempest\Database\Migrations\RunnableMigrations;
11-
use Tempest\Discovery\DiscoveryLocation;
1211
use Tests\Tempest\Fixtures\Discovery\HiddenDatabaseMigration;
1312
use Tests\Tempest\Fixtures\Discovery\HiddenMigratableDatabaseMigration;
13+
use Tests\Tempest\Fixtures\GlobalHiddenDiscovery;
14+
use Tests\Tempest\Fixtures\GlobalHiddenPathDiscovery;
1415
use Tests\Tempest\Integration\FrameworkIntegrationTestCase;
1516

1617
use function Tempest\get;
@@ -23,37 +24,26 @@ final class LoadDiscoveryClassesTest extends FrameworkIntegrationTestCase
2324
#[Test]
2425
public function do_not_discover(): void
2526
{
26-
$this->kernel->discoveryClasses = [
27-
MigrationDiscovery::class,
28-
];
29-
30-
$this->kernel->discoveryLocations = [
31-
new DiscoveryLocation(
32-
'Tests\Tempest\Fixtures',
33-
__DIR__ . '../../Fixtures/Discovery',
34-
),
35-
];
36-
3727
$migrations = get(RunnableMigrations::class);
3828

3929
$this->assertNotContains(HiddenDatabaseMigration::class, $migrations);
4030
}
4131

4232
#[Test]
43-
public function do_not_discover_except(): void
33+
public function do_not_discover_global_class(): void
4434
{
45-
$this->kernel->discoveryClasses = [
46-
MigrationDiscovery::class,
47-
// TODO: update tests to add `PublishDiscovery` when it's merged
48-
];
35+
$this->assertFalse(GlobalHiddenDiscovery::$discovered);
36+
}
4937

50-
$this->kernel->discoveryLocations = [
51-
new DiscoveryLocation(
52-
'Tests\Tempest\Fixtures',
53-
__DIR__ . '../../Fixtures/Discovery',
54-
),
55-
];
38+
#[Test]
39+
public function do_not_discover_global_path(): void
40+
{
41+
$this->assertFalse(GlobalHiddenPathDiscovery::$discovered);
42+
}
5643

44+
#[Test]
45+
public function do_not_discover_except(): void
46+
{
5747
$migrations = get(RunnableMigrations::class);
5848

5949
$foundMigrations = array_filter(

0 commit comments

Comments
 (0)