Skip to content

Commit

Permalink
feat(ServiceProvider): Add ability to get tagged classes of given imp…
Browse files Browse the repository at this point in the history
…lementation
  • Loading branch information
pionl committed Dec 11, 2023
1 parent 3eab2ee commit 9a1ddb6
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 4 deletions.
6 changes: 3 additions & 3 deletions src/Providers/AbstractBaseServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ public function register(): void
{
parent::register();

/** @var RunAppServiceProviderPipesActionContract $runPipes */
$runPipes = $this->app->make(RunAppServiceProviderPipesActionContract::class);
assert($runPipes instanceof RunAppServiceProviderPipesActionContract);

$runPipes->execute($this->getAppServiceProvider(), $this->registerPipes());
}
Expand All @@ -30,17 +30,17 @@ public function boot(): void
{
parent::boot();

/** @var RunAppServiceProviderPipesActionContract $runPipes */
$runPipes = $this->app->make(RunAppServiceProviderPipesActionContract::class);
assert($runPipes instanceof RunAppServiceProviderPipesActionContract);

$runPipes->execute($this->getAppServiceProvider(), $this->bootPipes());
}

public function getAppServiceProvider(): AppServiceProviderEntity
{
if ($this->appServiceProvider === null) {
/** @var CreateAppServiceProviderAction $action */
$action = $this->app->make($this->getCreateAppServiceProviderActionClass());
assert($action instanceof CreateAppServiceProviderActionContract);

$this->appServiceProvider = $action->execute($this->app, $this);
}
Expand Down
32 changes: 31 additions & 1 deletion src/Providers/AbstractServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

namespace LaraStrict\Providers;

use Closure;
use Illuminate\Contracts\Container\Container;
use LaraStrict\Cache\Contracts\BootContexts;
use LaraStrict\Console\Contracts\HasSchedule;
use LaraStrict\Console\Contracts\HasScheduleOnEnvironments;
Expand All @@ -19,6 +21,7 @@
use LaraStrict\Providers\Pipes\LoadProviderConfig;
use LaraStrict\Providers\Pipes\LoadProviderTranslations;
use LaraStrict\Providers\Pipes\LoadProviderViews;
use LogicException;

abstract class AbstractServiceProvider extends AbstractBaseServiceProvider
{
Expand Down Expand Up @@ -75,6 +78,33 @@ protected function canRegisterSchedule(): bool
return $this instanceof HasSchedule;
}

/**
* Ensures that contextual binding in container will get tagged implementation of given interface.
*
* @template TImplementation of object
* @param class-string<TImplementation> $class
* @return Closure(Container $container):array<TImplementation>
*/
protected function giveTaggedImplementation(string $class): Closure
{
return static function (Container $container) use ($class) {
$taggedServices = $container->tagged($class);
$services = [];
foreach ($taggedServices as $service) {
if ($service instanceof $class === false) {
throw new LogicException(sprintf(
'Tagged implementation for %s must be instance of %s',
$service::class,
$class
));
}

$services[] = $service;
}
return $services;
};
}

/**
* @param array<class-string<AbstractContext>> $contextClasses
*/
Expand All @@ -84,8 +114,8 @@ private function bootContexts(array $contextClasses): void
return;
}

/** @var ContextEventsService $service */
$service = $this->app->make(ContextEventsService::class);
assert($service instanceof ContextEventsService);

foreach ($contextClasses as $context) {
$context::boot($service);
Expand Down
33 changes: 33 additions & 0 deletions tests/Feature/Providers/AbstractServiceProviderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

use Illuminate\Contracts\View\Factory;
use LaraStrict\Core\LaraStrictServiceProvider;
use LaraStrict\Providers\Actions\CreateAppServiceProviderAction;
use Tests\LaraStrict\Feature\Providers\Actions\DITestImplementationAction;
use Tests\LaraStrict\Feature\Providers\Actions\TestImplementationAction;
use Tests\LaraStrict\Feature\Providers\Interfaces\TestImplementationInterface;
use Tests\LaraStrict\Feature\Providers\Translations\TestTranslation;
use Tests\LaraStrict\Feature\TestCase;

Expand Down Expand Up @@ -52,4 +56,33 @@ public function testLoadViewsAndComponents(): void
$result = $viewFactory->make('Providers::layout');
$this->assertEquals('Renders inline component' . PHP_EOL . ' and class component', $result->render());
}

public function testGiveTaggedImplementation(): void
{
$this->app()
->tag([TestImplementationAction::class], [TestImplementationInterface::class]);

$action = $this->app()
->make(DITestImplementationAction::class);
$this->assertInstanceOf(DITestImplementationAction::class, $action);
}

public function testGiveTaggedImplementationFailsOnIncorrectService(): void
{
$this->app()
->tag([
TestImplementationAction::class,
CreateAppServiceProviderAction::class,
], [TestImplementationInterface::class]);

$this->expectExceptionMessage(
sprintf(
'Tagged implementation for %s must be instance of %s',
CreateAppServiceProviderAction::class,
TestImplementationInterface::class
)
);
$this->app()
->make(DITestImplementationAction::class);
}
}
23 changes: 23 additions & 0 deletions tests/Feature/Providers/Actions/DITestImplementationAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace Tests\LaraStrict\Feature\Providers\Actions;

use Tests\LaraStrict\Feature\Providers\Interfaces\TestImplementationInterface;

final class DITestImplementationAction
{
/**
* @param array<TestImplementationInterface> $implementations
*/
public function __construct(
private readonly array $implementations,
) {
}

public function execute(): never
{
dd($this->implementations);
}
}
11 changes: 11 additions & 0 deletions tests/Feature/Providers/Actions/TestImplementationAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

namespace Tests\LaraStrict\Feature\Providers\Actions;

use Tests\LaraStrict\Feature\Providers\Interfaces\TestImplementationInterface;

class TestImplementationAction implements TestImplementationInterface
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

declare(strict_types=1);

namespace Tests\LaraStrict\Feature\Providers\Interfaces;

interface TestImplementationInterface
{
}
12 changes: 12 additions & 0 deletions tests/Feature/Providers/TestServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,23 @@
use LaraStrict\Contracts\HasViewComponents;
use LaraStrict\Contracts\HasViews;
use LaraStrict\Providers\AbstractServiceProvider;
use Tests\LaraStrict\Feature\Providers\Actions\DITestImplementationAction;
use Tests\LaraStrict\Feature\Providers\Interfaces\TestImplementationInterface;

class TestServiceProvider extends AbstractServiceProvider implements HasTranslations, HasViews, HasViewComponents, HasCustomServiceFileName
{
public function getServiceFileName(): string
{
return 'test_provider';
}

public function register(): void
{
parent::register();

$this->app
->when(DITestImplementationAction::class)
->needs('$implementations')
->give($this->giveTaggedImplementation(TestImplementationInterface::class));
}
}

0 comments on commit 9a1ddb6

Please sign in to comment.