Skip to content

Commit 2aaeb3f

Browse files
authored
Merge branch 'main' into discovery-config
2 parents 0bd4dcf + 9b31ecc commit 2aaeb3f

File tree

88 files changed

+1686
-550
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

88 files changed

+1686
-550
lines changed

composer.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,9 @@
185185
"Tests\\Tempest\\": "tests"
186186
}
187187
},
188+
"bin": [
189+
"packages/console/bin/tempest"
190+
],
188191
"config": {
189192
"allow-plugins": {
190193
"carthage-software/mago": true

packages/console/src/ConsoleApplication.php

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,14 @@
77
use Tempest\Console\Actions\ExecuteConsoleCommand;
88
use Tempest\Console\Input\ConsoleArgumentBag;
99
use Tempest\Container\Container;
10-
use Tempest\Core\AppConfig;
1110
use Tempest\Core\Application;
1211
use Tempest\Core\Kernel;
1312
use Tempest\Core\Tempest;
14-
use Tempest\Log\Channels\AppendLogChannel;
15-
use Tempest\Log\LogConfig;
16-
use Throwable;
17-
18-
use function Tempest\Support\path;
1913

2014
final readonly class ConsoleApplication implements Application
2115
{
2216
public function __construct(
2317
private Container $container,
24-
private AppConfig $appConfig,
2518
private ConsoleArgumentBag $argumentBag,
2619
) {}
2720

@@ -44,22 +37,14 @@ public static function boot(
4437

4538
public function run(): void
4639
{
47-
try {
48-
$exitCode = $this->container->get(ExecuteConsoleCommand::class)($this->argumentBag->getCommandName());
49-
50-
$exitCode = is_int($exitCode) ? $exitCode : $exitCode->value;
40+
$exitCode = $this->container->get(ExecuteConsoleCommand::class)($this->argumentBag->getCommandName());
5141

52-
if ($exitCode < 0 || $exitCode > 255) {
53-
throw new InvalidExitCode($exitCode);
54-
}
42+
$exitCode = is_int($exitCode) ? $exitCode : $exitCode->value;
5543

56-
$this->container->get(Kernel::class)->shutdown($exitCode);
57-
} catch (Throwable $throwable) {
58-
foreach ($this->appConfig->errorHandlers as $exceptionHandler) {
59-
$exceptionHandler->handleException($throwable);
60-
}
61-
62-
throw $throwable;
44+
if ($exitCode < 0 || $exitCode > 255) {
45+
throw new InvalidExitCode($exitCode);
6346
}
47+
48+
$this->container->get(Kernel::class)->shutdown($exitCode);
6449
}
6550
}

packages/console/src/Exceptions/ConsoleErrorHandler.php renamed to packages/console/src/Exceptions/ConsoleExceptionHandler.php

Lines changed: 39 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -8,69 +8,70 @@
88
use Tempest\Console\ExitCode;
99
use Tempest\Console\HasExitCode;
1010
use Tempest\Console\Input\ConsoleArgumentBag;
11+
use Tempest\Container\Container;
1112
use Tempest\Container\Tag;
12-
use Tempest\Core\ErrorHandler;
13+
use Tempest\Core\AppConfig;
14+
use Tempest\Core\ExceptionHandler;
1315
use Tempest\Core\Kernel;
1416
use Tempest\Highlight\Escape;
1517
use Tempest\Highlight\Highlighter;
1618
use Throwable;
1719

1820
use function Tempest\Support\str;
1921

20-
final readonly class ConsoleErrorHandler implements ErrorHandler
22+
final readonly class ConsoleExceptionHandler implements ExceptionHandler
2123
{
2224
public function __construct(
25+
private AppConfig $appConfig,
26+
private Container $container,
2327
private Kernel $kernel,
2428
#[Tag('console')]
2529
private Highlighter $highlighter,
2630
private Console $console,
2731
private ConsoleArgumentBag $argumentBag,
2832
) {}
2933

30-
public function handleException(Throwable $throwable): void
34+
public function handle(Throwable $throwable): void
3135
{
32-
ll(exception: $throwable->getMessage());
33-
34-
$this->console
35-
->writeln()
36-
->error($throwable::class)
37-
->when(
38-
condition: $throwable->getMessage(),
39-
callback: fn (Console $console) => $console->error($throwable->getMessage()),
40-
)
41-
->writeln()
42-
->writeln('In ' . $this->formatFileWithLine($throwable->getFile() . ':' . $throwable->getLine()))
43-
->writeln($this->getSnippet($throwable->getFile(), $throwable->getLine()))
44-
->writeln();
45-
46-
if ($this->argumentBag->get('-v') !== null) {
47-
foreach ($throwable->getTrace() as $i => $trace) {
48-
$this->console->writeln("<style='bold fg-blue'>#{$i}</style> " . $this->formatTrace($trace));
36+
try {
37+
foreach ($this->appConfig->exceptionProcessors as $processor) {
38+
$handler = $this->container->get($processor);
39+
$throwable = $handler->process($throwable);
4940
}
5041

51-
$this->console->writeln();
52-
} else {
5342
$this->console
54-
->writeln('<style="fg-blue bold">#0</style> ' . $this->formatTrace($throwable->getTrace()[0]))
55-
->writeln('<style="fg-blue bold">#1</style> ' . $this->formatTrace($throwable->getTrace()[1]))
5643
->writeln()
57-
->writeln(' <style="dim">Run with -v to show more.</style>')
44+
->error($throwable::class)
45+
->when(
46+
condition: $throwable->getMessage(),
47+
callback: fn (Console $console) => $console->error($throwable->getMessage()),
48+
)
49+
->writeln()
50+
->writeln('In ' . $this->formatFileWithLine($throwable->getFile() . ':' . $throwable->getLine()))
51+
->writeln($this->getSnippet($throwable->getFile(), $throwable->getLine()))
5852
->writeln();
59-
}
60-
61-
$exitCode = ($throwable instanceof HasExitCode) ? $throwable->getExitCode() : ExitCode::ERROR;
62-
63-
$this->kernel->shutdown($exitCode->value);
64-
}
6553

66-
public function handleError(int $errNo, string $errstr, string $errFile, int $errLine): void
67-
{
68-
ll(error: $errstr);
54+
if ($this->argumentBag->get('-v') !== null) {
55+
foreach ($throwable->getTrace() as $i => $trace) {
56+
$this->console->writeln("<style='bold fg-blue'>#{$i}</style> " . $this->formatTrace($trace));
57+
}
58+
59+
$this->console->writeln();
60+
} else {
61+
$this->console
62+
->writeln('<style="fg-blue bold">#0</style> ' . $this->formatTrace($throwable->getTrace()[0]))
63+
->writeln('<style="fg-blue bold">#1</style> ' . $this->formatTrace($throwable->getTrace()[1]))
64+
->writeln()
65+
->writeln(' <style="dim">Run with -v to show more.</style>')
66+
->writeln();
67+
}
68+
} finally {
69+
$exitCode = ($throwable instanceof HasExitCode)
70+
? $throwable->getExitCode()
71+
: ExitCode::ERROR;
6972

70-
$this->console
71-
->writeln()
72-
->error($errstr)
73-
->writeln($this->getSnippet($errFile, $errLine));
73+
$this->kernel->shutdown($exitCode->value);
74+
}
7475
}
7576

7677
private function getSnippet(string $file, int $lineNumber): string

packages/console/src/Initializers/ConsoleApplicationInitializer.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ public function initialize(Container $container): ConsoleApplication
1919
{
2020
$application = new ConsoleApplication(
2121
container: $container,
22-
appConfig: $container->get(AppConfig::class),
2322
argumentBag: $container->get(ConsoleArgumentBag::class),
2423
);
2524

packages/console/src/Testing/ConsoleTester.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
use Tempest\Console\Actions\ExecuteConsoleCommand;
1111
use Tempest\Console\Components\InteractiveComponentRenderer;
1212
use Tempest\Console\Console;
13-
use Tempest\Console\Exceptions\ConsoleErrorHandler;
13+
use Tempest\Console\Exceptions\ConsoleExceptionHandler;
1414
use Tempest\Console\ExitCode;
1515
use Tempest\Console\GenericConsole;
1616
use Tempest\Console\Input\ConsoleArgumentBag;
@@ -76,7 +76,7 @@ public function call(string|Closure|array $command, string|array $arguments = []
7676
$clone->container->singleton(Console::class, $console);
7777

7878
$appConfig = $this->container->get(AppConfig::class);
79-
$appConfig->errorHandlers[] = $clone->container->get(ConsoleErrorHandler::class);
79+
$appConfig->exceptionProcessors[] = $clone->container->get(ConsoleExceptionHandler::class);
8080

8181
$clone->output = $memoryOutputBuffer;
8282
$clone->input = $memoryInputBuffer;
@@ -319,7 +319,7 @@ public function withPrompting(): self
319319

320320
public function dd(): self
321321
{
322-
ld($this->output->asFormattedString());
322+
ld($this->output->asUnformattedString());
323323

324324
return $this;
325325
}

packages/container/src/Container.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ interface Container
1212
{
1313
public function register(string $className, callable $definition): self;
1414

15-
public function unregister(string $className): self;
15+
public function unregister(string $className, bool $tagged = false): self;
1616

1717
public function singleton(string $className, mixed $definition, ?string $tag = null): self;
1818

packages/container/src/GenericContainer.php

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,13 @@ public function setDefinitions(array $definitions): self
4444
return $this;
4545
}
4646

47+
public function setSingletons(array $singletons): self
48+
{
49+
$this->singletons = new ArrayIterator($singletons);
50+
51+
return $this;
52+
}
53+
4754
public function setInitializers(array $initializers): self
4855
{
4956
$this->initializers = new ArrayIterator($initializers);
@@ -85,10 +92,20 @@ public function register(string $className, callable $definition): self
8592
return $this;
8693
}
8794

88-
public function unregister(string $className): self
95+
public function unregister(string $className, bool $tagged = false): self
8996
{
9097
unset($this->definitions[$className], $this->singletons[$className]);
9198

99+
if ($tagged) {
100+
$singletons = array_filter(
101+
array: $this->getSingletons(),
102+
callback: static fn (mixed $_, string $key) => ! str_starts_with($key, "{$className}#"),
103+
mode: \ARRAY_FILTER_USE_BOTH,
104+
);
105+
106+
$this->setSingletons($singletons);
107+
}
108+
92109
return $this;
93110
}
94111

@@ -241,6 +258,28 @@ public function addInitializer(ClassReflector|string $initializerClass): Contain
241258
return $this;
242259
}
243260

261+
public function removeInitializer(ClassReflector|string $initializerClass): Container
262+
{
263+
if (! ($initializerClass instanceof ClassReflector)) {
264+
$initializerClass = new ClassReflector($initializerClass);
265+
}
266+
267+
if ($initializerClass->getType()->matches(DynamicInitializer::class)) {
268+
$index = array_find_key(
269+
array: $this->dynamicInitializers->getArrayCopy(),
270+
callback: static fn (string $className) => $className === $initializerClass->getName(),
271+
);
272+
273+
unset($this->dynamicInitializers[$index]);
274+
275+
return $this;
276+
}
277+
278+
unset($this->initializers[$initializerClass->getName()]);
279+
280+
return $this;
281+
}
282+
244283
private function resolve(string $className, ?string $tag = null, mixed ...$params): ?object
245284
{
246285
$class = new ClassReflector($className);

packages/container/tests/ContainerTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,25 @@ public function test_unregister_singleton(): void
443443
$container->get(InterfaceA::class);
444444
}
445445

446+
public function test_unregister_tagged(): void
447+
{
448+
$container = new GenericContainer();
449+
450+
$container->singleton(
451+
TaggedDependency::class,
452+
new TaggedDependency('web'),
453+
tag: 'web',
454+
);
455+
456+
$this->assertInstanceOf(TaggedDependency::class, $container->get(TaggedDependency::class, 'web'));
457+
458+
$container->unregister(TaggedDependency::class, tagged: true);
459+
460+
$this->expectException(CannotResolveTaggedDependency::class);
461+
462+
$container->get(TaggedDependency::class, 'web');
463+
}
464+
446465
public function test_has(): void
447466
{
448467
$container = new GenericContainer();

packages/core/src/AppConfig.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
namespace Tempest\Core;
66

7+
use Tempest\Core\Exceptions\LogExceptionProcessor;
8+
79
use function Tempest\env;
810

911
final class AppConfig
@@ -16,10 +18,8 @@ public function __construct(
1618
?Environment $environment = null,
1719
?string $baseUri = null,
1820

19-
/** @var \Tempest\Core\ErrorHandler[] */
20-
public array $errorHandlers = [
21-
// …,
22-
],
21+
/** @var class-string<\Tempest\Core\ExceptionProcessor>[] */
22+
public array $exceptionProcessors = [],
2323
) {
2424
$this->environment = $environment ?? Environment::fromEnv();
2525

packages/core/src/ErrorHandler.php

Lines changed: 0 additions & 14 deletions
This file was deleted.

0 commit comments

Comments
 (0)