Skip to content

Commit

Permalink
Add Injector::implementations() to select implementations for a given…
Browse files Browse the repository at this point in the history
… type
  • Loading branch information
thekid committed Jul 16, 2024
1 parent 15b74e7 commit 5a9fa79
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 1 deletion.
46 changes: 46 additions & 0 deletions src/main/php/inject/Implementations.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php namespace inject;

use lang\Generic;

/** @test inject.unittest.ImplementationsTest */
#[Generic(self: 'T')]
class Implementations {
private $inject, $bindings;

/**
* Creates a new instance
*
* @param inject.Injector $inject
* @param [:inject.Binding] $bindings
*/
public function __construct(Injector $inject, array $bindings) {
$this->inject= $inject;
$this->bindings= $bindings;
}

/**
* Returns the default implementation
*
* @return T
*/
#[Generic(return: 'T')]
public function default() {
return current($this->bindings)->resolve($this->inject);
}

/**
* Returns the implementation for a given name
*
* @param string $name
* @return T
* @throws inject.ProvisionException if there is no such implementation
*/
#[Generic(return: 'T')]
public function named($name) {
if ($binding= $this->bindings[$name] ?? null) {
return $binding->resolve($this->inject);
}

throw new ProvisionException('No implementation named "'.$name.'"');
}
}
16 changes: 16 additions & 0 deletions src/main/php/inject/Injector.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,22 @@ public function bind($type, $impl, $name= null) {
return $this;
}

/**
* Returns implementations for a given type
*
* @param string|lang.Type $type
* @return inject.Implementations
* @throws inject.ProvisionException
*/
public function implementations($type) {
$t= $type instanceof Type ? $type : Type::forName($type);
if ($bindings= $this->bindings[$t->literal()] ?? null) {
return new Implementations($this, $bindings);
}

throw new ProvisionException('No implementations for type '.$t);
}

/**
* Returns the lookup if it provides a value, null otherwise
*
Expand Down
46 changes: 46 additions & 0 deletions src/test/php/inject/unittest/ImplementationsTest.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php namespace inject\unittest;

use inject\unittest\fixture\{URI, Endpoint};
use inject\{Injector, ProvisionException};
use test\{Assert, Before, Expect, Test, Values};

class ImplementationsTest {
private $uris;

#[Before]
private function uris() {
$this->uris= [
'dev' => new URI('http://localhost'),
'prod' => new URI('https://example.com'),
];
}

/** @return inject.Injector */
private function fixture() {
$fixture= new Injector();
foreach ($this->uris as $name => $uri) {
$fixture->bind(URI::class, $uri, $name);
}
return $fixture;
}

#[Test, Values(['dev', 'prod'])]
public function implementations_named($name) {
Assert::equals($this->uris[$name], $this->fixture()->implementations(URI::class)->named($name));
}

#[Test]
public function default_implementation() {
Assert::equals($this->uris['dev'], $this->fixture()->implementations(URI::class)->default());
}

#[Test, Expect(ProvisionException::class)]
public function no_implementations() {
$this->fixture()->implementations(Endpoint::class);
}

#[Test, Expect(ProvisionException::class)]
public function unknown_implementation() {
$this->fixture()->implementations(URI::class)->named('stage');
}
}
3 changes: 3 additions & 0 deletions src/test/php/inject/unittest/fixture/Creation.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,7 @@ class Creation {

/** Create fluent interface for URIs */
public function __construct(URI $uri) { /* ... */ }

/** @return string */
public function create() { /* ... */ }
}
5 changes: 4 additions & 1 deletion src/test/php/inject/unittest/fixture/URI.class.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
<?php namespace inject\unittest\fixture;

class URI {
private $backing;

/** @param string|inject.unittest.fixture.Creation $arg */
public function __construct($arg) { /* ... */ }
public function __construct($arg) {
$this->backing= $arg instanceof Creation ? $arg->create() : (string)$arg;
}
}

0 comments on commit 5a9fa79

Please sign in to comment.