Skip to content

Commit 0980e3a

Browse files
authored
feat(container): support dynamic tags using dynamic initializers (#1120)
1 parent afcfb4d commit 0980e3a

21 files changed

+152
-27
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,7 @@ tests/Unit/Log
1616
log/
1717
node_modules
1818
dist
19-
profile/
19+
profile/
20+
db-main.sqlite
21+
db-tenant-1.sqlite
22+
db-tenant-2.sqlite

src/Tempest/Auth/src/CurrentUserInitializer.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,17 @@
66

77
use Tempest\Container\Container;
88
use Tempest\Container\DynamicInitializer;
9+
use Tempest\Container\Tag;
910
use Tempest\Reflection\ClassReflector;
1011

1112
final readonly class CurrentUserInitializer implements DynamicInitializer
1213
{
13-
public function canInitialize(ClassReflector $class): bool
14+
public function canInitialize(ClassReflector $class, ?string $tag): bool
1415
{
1516
return $class->implements(CanAuthenticate::class);
1617
}
1718

18-
public function initialize(ClassReflector $class, Container $container): object
19+
public function initialize(ClassReflector $class, ?string $tag, Container $container): object
1920
{
2021
$user = $container->get(Authenticator::class)->currentUser();
2122

src/Tempest/Container/src/DynamicInitializer.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
interface DynamicInitializer
1010
{
11-
public function canInitialize(ClassReflector $class): bool;
11+
public function canInitialize(ClassReflector $class, ?string $tag): bool;
1212

13-
public function initialize(ClassReflector $class, Container $container): object;
13+
public function initialize(ClassReflector $class, ?string $tag, Container $container): object;
1414
}

src/Tempest/Container/src/GenericContainer.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ public function has(string $className, ?string $tag = null): bool
9999

100100
public function singleton(string $className, mixed $definition, ?string $tag = null): self
101101
{
102+
if ($definition instanceof HasTag) {
103+
$tag = $definition->tag;
104+
}
105+
102106
$className = $this->resolveTaggedName($className, $tag);
103107

104108
$this->singletons[$className] = $definition;
@@ -270,7 +274,7 @@ private function resolve(string $className, ?string $tag = null, mixed ...$param
270274

271275
$object = match (true) {
272276
$initializer instanceof Initializer => $initializer->initialize($this->clone()),
273-
$initializer instanceof DynamicInitializer => $initializer->initialize($class, $this->clone()),
277+
$initializer instanceof DynamicInitializer => $initializer->initialize($class, $tag, $this->clone()),
274278
};
275279

276280
$singleton = $initializerClass->getAttribute(Singleton::class) ?? $initializerClass->getMethod('initialize')->getAttribute(Singleton::class);
@@ -318,7 +322,7 @@ private function initializerForClass(ClassReflector $target, ?string $tag = null
318322
/** @var DynamicInitializer $initializer */
319323
$initializer = $this->resolve($initializerClass);
320324

321-
if (! $initializer->canInitialize($target)) {
325+
if (! $initializer->canInitialize(class: $target, tag: $tag)) {
322326
continue;
323327
}
324328

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
namespace Tempest\Container;
4+
5+
use UnitEnum;
6+
7+
interface HasTag
8+
{
9+
public null|string|UnitEnum $tag {
10+
get;
11+
}
12+
}

src/Tempest/Container/tests/ContainerTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
use Tempest\Container\Tests\Fixtures\ContainerObjectEInitializer;
3434
use Tempest\Container\Tests\Fixtures\DependencyWithBuiltinDependencies;
3535
use Tempest\Container\Tests\Fixtures\DependencyWithTaggedDependency;
36+
use Tempest\Container\Tests\Fixtures\HasTagObject;
3637
use Tempest\Container\Tests\Fixtures\ImplementsInterfaceA;
3738
use Tempest\Container\Tests\Fixtures\InjectA;
3839
use Tempest\Container\Tests\Fixtures\InjectB;
@@ -557,4 +558,15 @@ public function test_lazy_property_dependency(): void
557558

558559
$this->assertSame('value1', $this->assertSlowerThan(fn () => $instance->dependency->value, $delay));
559560
}
561+
562+
public function test_has_tags_support(): void
563+
{
564+
$container = new GenericContainer();
565+
566+
$container->singleton(HasTagObject::class, new HasTagObject('A', 'tagA'));
567+
$container->singleton(HasTagObject::class, new HasTagObject('B', 'tagB'));
568+
569+
$this->assertSame('A', $container->get(HasTagObject::class, 'tagA')->name);
570+
$this->assertSame('B', $container->get(HasTagObject::class, 'tagB')->name);
571+
}
560572
}

src/Tempest/Container/tests/Fixtures/ContainerObjectEInitializer.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,17 @@
66

77
use Tempest\Container\Container;
88
use Tempest\Container\DynamicInitializer;
9+
use Tempest\Container\Tag;
910
use Tempest\Reflection\ClassReflector;
1011

1112
final class ContainerObjectEInitializer implements DynamicInitializer
1213
{
13-
public function canInitialize(ClassReflector $class): bool
14+
public function canInitialize(ClassReflector $class, ?string $tag): bool
1415
{
1516
return $class->getName() === ContainerObjectE::class;
1617
}
1718

18-
public function initialize(ClassReflector $class, Container $container): object
19+
public function initialize(ClassReflector $class, ?string $tag, Container $container): object
1920
{
2021
return new ContainerObjectE();
2122
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
namespace Tempest\Container\Tests\Fixtures;
4+
5+
use Tempest\Container\HasTag;
6+
use UnitEnum;
7+
8+
final class HasTagObject implements HasTag
9+
{
10+
public function __construct(
11+
public string $name,
12+
public null|string|UnitEnum $tag = null,
13+
) {}
14+
}

src/Tempest/Database/src/Config/DatabaseConfig.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44

55
namespace Tempest\Database\Config;
66

7+
use Tempest\Container\HasTag;
78
use Tempest\Database\Tables\NamingStrategy;
89

9-
interface DatabaseConfig
10+
interface DatabaseConfig extends HasTag
1011
{
1112
public string $dsn {
1213
get;

src/Tempest/Database/src/Config/MysqlConfig.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use SensitiveParameter;
88
use Tempest\Database\Tables\NamingStrategy;
99
use Tempest\Database\Tables\PluralizedSnakeCaseStrategy;
10+
use UnitEnum;
1011

1112
final class MysqlConfig implements DatabaseConfig
1213
{
@@ -35,5 +36,6 @@ public function __construct(
3536
#[SensitiveParameter]
3637
public string $database = 'app',
3738
public NamingStrategy $namingStrategy = new PluralizedSnakeCaseStrategy(),
39+
public null|string|UnitEnum $tag = null,
3840
) {}
3941
}

0 commit comments

Comments
 (0)