diff --git a/src/Drivers/Decorator.php b/src/Drivers/Decorator.php index f9e2f4f..96767eb 100644 --- a/src/Drivers/Decorator.php +++ b/src/Drivers/Decorator.php @@ -72,6 +72,13 @@ class Decorator implements CanListStoredFeatures, Driver */ protected $cache; + /** + * Map of feature names to their implementations. + * + * @var array + */ + protected $nameMap = []; + /** * Create a new driver decorator instance. * @@ -122,6 +129,10 @@ public function define($feature, $resolver = null): void $this->container->make($feature)->name ?? $feature, new LazilyResolvedFeature($feature), ]; + + $this->nameMap[$feature] = $resolver->feature; + } else { + $this->nameMap[$feature] = $resolver; } $this->driver->define($feature, function ($scope) use ($feature, $resolver) { @@ -488,6 +499,27 @@ public function name($feature) return $this->resolveFeature($feature); } + /** + * Retrieve the feature's class. + * + * @param string $feature + * @return mixed + */ + public function instance($name) + { + $feature = $this->nameMap[$name] ?? $name; + + if (is_string($feature) && class_exists($feature)) { + return $this->container->make($feature); + } + + if ($feature instanceof Closure || $feature instanceof Lottery) { + return $feature; + } + + return fn () => $feature; + } + /** * Resolve the feature name and ensure it is defined. * diff --git a/tests/Feature/ArrayDriverTest.php b/tests/Feature/ArrayDriverTest.php index f23b442..a0169df 100644 --- a/tests/Feature/ArrayDriverTest.php +++ b/tests/Feature/ArrayDriverTest.php @@ -2,6 +2,7 @@ namespace Tests\Feature; +use Closure; use Illuminate\Container\Container; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Config; @@ -1154,6 +1155,29 @@ public function test_it_can_list_stored_features() $this->assertSame(Feature::stored(), ['bar']); } + + public function test_it_can_resolve_feature_instance() + { + Feature::define(MyFeature::class); + $this->assertInstanceOf(MyFeature::class, Feature::instance('my-feature')); + $this->assertInstanceOf(MyFeature::class, Feature::instance(MyFeature::class)); + + Feature::define(MyUnnamedFeature::class); + $this->assertInstanceOf(MyUnnamedFeature::class, Feature::instance(MyUnnamedFeature::class)); + + Feature::define('closure-based-feature', $closure = fn () => true); + $this->assertSame($closure, Feature::instance('closure-based-feature')); + + Feature::define('value-based-feature', '123'); + $feature = Feature::instance('value-based-feature'); + $this->assertInstanceOf(Closure::class, $feature); + $this->assertSame('123', $feature()); + + Feature::define('lottery-based-feature', Lottery::odds(1, 1)->winner(fn () => '345')); + $feature = Feature::instance('lottery-based-feature'); + $this->assertInstanceOf(Lottery::class, $feature); + $this->assertSame('345', $feature()); + } } class MyFeature