Skip to content

Commit

Permalink
Improve functions API to allow emitting events (#356)
Browse files Browse the repository at this point in the history
  • Loading branch information
cspray authored Mar 4, 2024
1 parent 66e0603 commit da3884b
Show file tree
Hide file tree
Showing 22 changed files with 478 additions and 34 deletions.
6 changes: 5 additions & 1 deletion fixture_src/Fixtures.php
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,8 @@ public static function duplicateNamedServiceDifferentProfiles() : DuplicateNamed
return new DuplicateNamedServiceDifferentProfilesFixture();
}

}
public static function thirdPartyKitchenSink() : ThirdPartyKitchenSinkFixture {
return new ThirdPartyKitchenSinkFixture();
}

}
7 changes: 7 additions & 0 deletions fixture_src/ThirdPartyKitchenSink/NonAnnotatedInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php declare(strict_types=1);

namespace Cspray\AnnotatedContainerFixture\ThirdPartyKitchenSink;

interface NonAnnotatedInterface {

}
25 changes: 25 additions & 0 deletions fixture_src/ThirdPartyKitchenSink/NonAnnotatedService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php declare(strict_types=1);

namespace Cspray\AnnotatedContainerFixture\ThirdPartyKitchenSink;

class NonAnnotatedService implements NonAnnotatedInterface {

private bool $initCalled = false;

private function __construct(
public readonly string $value
) {}

public function init() {
$this->initCalled = true;
}

public static function create(string $value) : self {
return new self($value);
}

public function isInitCalled() : bool {
return $this->initCalled;
}

}
18 changes: 18 additions & 0 deletions fixture_src/ThirdPartyKitchenSinkFixture.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php declare(strict_types=1);

namespace Cspray\AnnotatedContainerFixture;

use Cspray\AnnotatedContainerFixture\ThirdPartyKitchenSink\NonAnnotatedService;
use Cspray\Typiphy\ObjectType;

class ThirdPartyKitchenSinkFixture implements Fixture {

public function getPath() : string {
return __DIR__ . '/ThirdPartyKitchenSink';
}

public function nonAnnotatedService() : ObjectType {
return objectType(NonAnnotatedService::class);
}

}
2 changes: 1 addition & 1 deletion phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
</exclude>
<report>
<text outputFile="php://stdout" showOnlySummary="true" />
<html outputDirectory="build/code-coverage/html" />
<!-- <html outputDirectory="build/code-coverage/html" /> -->
</report>
</coverage>
</phpunit>
63 changes: 63 additions & 0 deletions src/Event/Emitter.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
use Cspray\AnnotatedContainer\Event\Listener\ContainerFactory\ServicePrepared;
use Cspray\AnnotatedContainer\Event\Listener\ContainerFactory\ServiceShared;
use Cspray\AnnotatedContainer\Event\Listener\StaticAnalysis\AddedAliasDefinition;
use Cspray\AnnotatedContainer\Event\Listener\StaticAnalysis\AddedInjectDefinitionFromApi;
use Cspray\AnnotatedContainer\Event\Listener\StaticAnalysis\AddedServiceDefinitionFromApi;
use Cspray\AnnotatedContainer\Event\Listener\StaticAnalysis\AddedServiceDelegateDefinitionFromApi;
use Cspray\AnnotatedContainer\Event\Listener\StaticAnalysis\AddedServicePrepareDefinitionFromApi;
use Cspray\AnnotatedContainer\Event\Listener\StaticAnalysis\AfterContainerAnalysis;
use Cspray\AnnotatedContainer\Event\Listener\StaticAnalysis\AnalyzedContainerDefinitionFromCache;
use Cspray\AnnotatedContainer\Event\Listener\StaticAnalysis\AnalyzedInjectDefinitionFromAttribute;
Expand Down Expand Up @@ -75,6 +79,26 @@ final class Emitter implements StaticAnalysisEmitter, BootstrapEmitter, Containe
*/
private array $addedAliasDefinitions = [];

/**
* @var list<AddedInjectDefinitionFromApi>
*/
private array $addedInjectDefinitions = [];

/**
* @var list<AddedServiceDefinitionFromApi>
*/
private array $addedServiceDefinitions = [];

/**
* @var list<AddedServiceDelegateDefinitionFromApi>
*/
private array $addedServiceDelegateDefinitions = [];

/**
* @var list<AddedServicePrepareDefinitionFromApi>
*/
private array $addedServicePrepareDefinitions = [];

/**
* @var list<AnalyzedContainerDefinitionFromCache>
*/
Expand Down Expand Up @@ -167,6 +191,22 @@ public function addAddedAliasDefinitionListener(AddedAliasDefinition $listener)
$this->addedAliasDefinitions[] = $listener;
}

public function addAddedInjectDefinitionFromApiListener(AddedInjectDefinitionFromApi $listener) : void {
$this->addedInjectDefinitions[] = $listener;
}

public function addAddedServiceDefinitionFromApiListener(AddedServiceDefinitionFromApi $listener) : void {
$this->addedServiceDefinitions[] = $listener;
}

public function addAddedServiceDelegateDefinitionFromApiListener(AddedServiceDelegateDefinitionFromApi $listener) : void {
$this->addedServiceDelegateDefinitions[] = $listener;
}

public function addAddedServicePrepareDefinitionFromApiListener(AddedServicePrepareDefinitionFromApi $listener) : void {
$this->addedServicePrepareDefinitions[] = $listener;
}

public function addAfterContainerAnalysisListener(AfterContainerAnalysis $listener) : void {
$this->afterContainerAnalysis[] = $listener;
}
Expand Down Expand Up @@ -325,4 +365,27 @@ public function emitAfterContainerCreation(Profiles $profiles, ContainerDefiniti
}
}

public function emitAddedInjectDefinitionFromApi(InjectDefinition $injectDefinition) : void {
foreach ($this->addedInjectDefinitions as $addedInjectDefinition) {
$addedInjectDefinition->handleAddedInjectDefinitionFromApi($injectDefinition);
}
}

public function emitAddedServiceDefinitionFromApi(ServiceDefinition $serviceDefinition) : void {
foreach ($this->addedServiceDefinitions as $addedServiceDefinition) {
$addedServiceDefinition->handleAddedServiceDefinitionFromApi($serviceDefinition);
}
}

public function emitAddedServiceDelegateDefinitionFromApi(ServiceDelegateDefinition $serviceDelegateDefinition) : void {
foreach ($this->addedServiceDelegateDefinitions as $addedServiceDelegateDefinition) {
$addedServiceDelegateDefinition->handleAddedServiceDelegateDefinitionFromApi($serviceDelegateDefinition);
}
}

public function emitAddedServicePrepareDefinitionFromApi(ServicePrepareDefinition $servicePrepareDefinition) : void {
foreach ($this->addedServicePrepareDefinitions as $addedServicePrepareDefinition) {
$addedServicePrepareDefinition->handleAddedServicePrepareDefinitionFromApi($servicePrepareDefinition);
}
}
}
11 changes: 11 additions & 0 deletions src/Event/Listener/StaticAnalysis/AddedInjectDefinitionFromApi.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php declare(strict_types=1);

namespace Cspray\AnnotatedContainer\Event\Listener\StaticAnalysis;

use Cspray\AnnotatedContainer\Definition\InjectDefinition;

interface AddedInjectDefinitionFromApi {

public function handleAddedInjectDefinitionFromApi(InjectDefinition $injectDefinition) : void;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php declare(strict_types=1);

namespace Cspray\AnnotatedContainer\Event\Listener\StaticAnalysis;

use Cspray\AnnotatedContainer\Definition\ServiceDefinition;

interface AddedServiceDefinitionFromApi {

public function handleAddedServiceDefinitionFromApi(ServiceDefinition $serviceDefinition) : void;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php declare(strict_types=1);

namespace Cspray\AnnotatedContainer\Event\Listener\StaticAnalysis;

use Cspray\AnnotatedContainer\Definition\ServiceDelegateDefinition;

interface AddedServiceDelegateDefinitionFromApi {

public function handleAddedServiceDelegateDefinitionFromApi(ServiceDelegateDefinition $serviceDelegateDefinition) : void;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php declare(strict_types=1);

namespace Cspray\AnnotatedContainer\Event\Listener\StaticAnalysis;

use Cspray\AnnotatedContainer\Definition\ServicePrepareDefinition;

interface AddedServicePrepareDefinitionFromApi {

public function handleAddedServicePrepareDefinitionFromApi(ServicePrepareDefinition $servicePrepareDefinition) : void;

}
9 changes: 8 additions & 1 deletion src/Event/StaticAnalysisEmitter.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,21 @@ public function emitAnalyzedInjectDefinitionFromAttribute(
InjectDefinition $injectDefinition,
) : void;

public function emitAddedInjectDefinitionFromApi(InjectDefinition $injectDefinition) : void;

public function emitAddedServiceDefinitionFromApi(ServiceDefinition $serviceDefinition) : void;

public function emitAddedServiceDelegateDefinitionFromApi(ServiceDelegateDefinition $serviceDelegateDefinition) : void;

public function emitAddedServicePrepareDefinitionFromApi(ServicePrepareDefinition $servicePrepareDefinition) : void;

public function emitAddedAliasDefinition(AliasDefinition $aliasDefinition) : void;

public function emitAnalyzedContainerDefinitionFromCache(
ContainerDefinition $definition,
string $cacheFile
) : void;


public function emitAfterContainerAnalysis(
ContainerDefinitionAnalysisOptions $analysisOptions,
ContainerDefinition $containerDefinition,
Expand Down
10 changes: 5 additions & 5 deletions src/Function/definitions.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,25 +50,25 @@ function service(DefinitionProviderContext $context, ObjectType $type, ?string $
$serviceDefinitionBuilder = $serviceDefinitionBuilder->withProfiles($profiles);

$serviceDefinition = $serviceDefinitionBuilder->build();
$context->setBuilder($context->getBuilder()->withServiceDefinition($serviceDefinition));
$context->addServiceDefinition($serviceDefinition);
return $serviceDefinition;
}

function alias(DefinitionProviderContext $context, ObjectType $abstract, ObjectType $concrete) : AliasDefinition {
$aliasDefinition = AliasDefinitionBuilder::forAbstract($abstract)->withConcrete($concrete)->build();
$context->setBuilder($context->getBuilder()->withAliasDefinition($aliasDefinition));
$context->addAliasDefinition($aliasDefinition);
return $aliasDefinition;
}

function serviceDelegate(DefinitionProviderContext $context, ObjectType $service, ObjectType $factoryClass, string $factoryMethod) : ServiceDelegateDefinition {
$serviceDelegateDefinition = ServiceDelegateDefinitionBuilder::forService($service)->withDelegateMethod($factoryClass, $factoryMethod)->build();
$context->setBuilder($context->getBuilder()->withServiceDelegateDefinition($serviceDelegateDefinition));
$context->addServiceDelegateDefinition($serviceDelegateDefinition);
return $serviceDelegateDefinition;
}

function servicePrepare(DefinitionProviderContext $context, ObjectType $service, string $method) : ServicePrepareDefinition {
$servicePrepareDefinition = ServicePrepareDefinitionBuilder::forMethod($service, $method)->build();
$context->setBuilder($context->getBuilder()->withServicePrepareDefinition($servicePrepareDefinition));
$context->addServicePrepareDefinition($servicePrepareDefinition);
return $servicePrepareDefinition;
}

Expand All @@ -86,6 +86,6 @@ function injectMethodParam(DefinitionProviderContext $context, ObjectType $servi
}

$injectDefinition = $injectDefinitionBuilder->build();
$context->setBuilder($context->getBuilder()->withInjectDefinition($injectDefinition));
$context->addInjectDefinition($injectDefinition);
return $injectDefinition;
}
35 changes: 30 additions & 5 deletions src/StaticAnalysis/AnnotatedTargetContainerDefinitionAnalyzer.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Cspray\AnnotatedContainer\StaticAnalysis;

use Cspray\AnnotatedContainer\Definition\AliasDefinition;
use Cspray\AnnotatedContainer\Definition\AliasDefinitionBuilder;
use Cspray\AnnotatedContainer\Definition\ContainerDefinition;
use Cspray\AnnotatedContainer\Definition\ContainerDefinitionBuilder;
Expand Down Expand Up @@ -214,16 +215,40 @@ private function addThirdPartyServices(
) : ContainerDefinitionBuilder {
$definitionProvider = $compileOptions->getDefinitionProvider();
if ($definitionProvider !== null) {
$context = new class($builder) implements DefinitionProviderContext {
public function __construct(private ContainerDefinitionBuilder $builder) {
}
$context = new class($builder, $this->emitter) implements DefinitionProviderContext {
public function __construct(
private ContainerDefinitionBuilder $builder,
private ?StaticAnalysisEmitter $analysisEmitter = null
) {}

public function getBuilder() : ContainerDefinitionBuilder {
return $this->builder;
}

public function setBuilder(ContainerDefinitionBuilder $containerDefinitionBuilder) : void {
$this->builder = $containerDefinitionBuilder;
public function addServiceDefinition(ServiceDefinition $serviceDefinition) : void {
$this->builder = $this->builder->withServiceDefinition($serviceDefinition);
$this->analysisEmitter?->emitAddedServiceDefinitionFromApi($serviceDefinition);
}

public function addServicePrepareDefinition(ServicePrepareDefinition $servicePrepareDefinition) : void {
$this->builder = $this->builder->withServicePrepareDefinition($servicePrepareDefinition);
$this->analysisEmitter?->emitAddedServicePrepareDefinitionFromApi($servicePrepareDefinition);
}

public function addServiceDelegateDefinition(ServiceDelegateDefinition $serviceDelegateDefinition) : void {
$this->builder = $this->builder->withServiceDelegateDefinition($serviceDelegateDefinition);
$this->analysisEmitter?->emitAddedServiceDelegateDefinitionFromApi($serviceDelegateDefinition);
}

public function addInjectDefinition(InjectDefinition $injectDefinition) : void {
$this->builder = $this->builder->withInjectDefinition($injectDefinition);
$this->analysisEmitter?->emitAddedInjectDefinitionFromApi($injectDefinition);
}

public function addAliasDefinition(AliasDefinition $aliasDefinition) : void {
$this->builder = $this->builder->withAliasDefinition($aliasDefinition);
// We do not emit adding an alias definition here, it is handled by the analyzer after all services
// are added or parsed
}
};
$definitionProvider->consume($context);
Expand Down
23 changes: 14 additions & 9 deletions src/StaticAnalysis/DefinitionProviderContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@

namespace Cspray\AnnotatedContainer\StaticAnalysis;

use Cspray\AnnotatedContainer\Definition\AliasDefinition;
use Cspray\AnnotatedContainer\Definition\ContainerDefinitionBuilder;
use Cspray\AnnotatedContainer\Definition\InjectDefinition;
use Cspray\AnnotatedContainer\Definition\ServiceDefinition;
use Cspray\AnnotatedContainer\Definition\ServiceDelegateDefinition;
use Cspray\AnnotatedContainer\Definition\ServicePrepareDefinition;

/**
* An object that allows the functional API for creating definition instances to work with the immutable
Expand All @@ -20,14 +25,14 @@ interface DefinitionProviderContext {
*/
public function getBuilder() : ContainerDefinitionBuilder;

/**
* Change the current builder; this should be called after the functional API has adjusted the existing builder and
* a new immutable instance has been created.
*
* @param ContainerDefinitionBuilder $containerDefinitionBuilder
* @return void
*/
public function setBuilder(ContainerDefinitionBuilder $containerDefinitionBuilder) : void;
public function addServiceDefinition(ServiceDefinition $serviceDefinition) : void;

public function addServicePrepareDefinition(ServicePrepareDefinition $servicePrepareDefinition) : void;

public function addServiceDelegateDefinition(ServiceDelegateDefinition $serviceDelegateDefinition) : void;

public function addInjectDefinition(InjectDefinition $injectDefinition) : void;

public function addAliasDefinition(AliasDefinition $aliasDefinition) : void;

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ protected function setUp() : void {
$emitter->addAnalyzedServiceDelegateDefinitionFromAttributeListener($this->stubAnalysisListener);
$emitter->addAnalyzedServicePrepareDefinitionFromAttributeListener($this->stubAnalysisListener);
$emitter->addAddedAliasDefinitionListener($this->stubAnalysisListener);
$emitter->addAddedInjectDefinitionFromApiListener($this->stubAnalysisListener);
$emitter->addAddedServiceDefinitionFromApiListener($this->stubAnalysisListener);
$emitter->addAddedServiceDelegateDefinitionFromApiListener($this->stubAnalysisListener);
$emitter->addAddedServicePrepareDefinitionFromApiListener($this->stubAnalysisListener);
$emitter->addAfterContainerAnalysisListener($this->stubAnalysisListener);

$analyzer = new AnnotatedTargetContainerDefinitionAnalyzer(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,10 @@ protected function serviceDelegateProvider() : array {
}

protected function assertEmittedEvents(AnalysisEventCollection $analysisEventCollection) : void {
self::assertCount(3, $analysisEventCollection);
self::assertCount(4, $analysisEventCollection);
self::assertSame(AnalysisEvent::BeforeContainerAnalysis, $analysisEventCollection->first());
self::assertCount(1, $analysisEventCollection->filter(AnalysisEvent::AnalyzedServiceDelegateDefinitionFromAttribute));
self::assertCount(1, $analysisEventCollection->filter(AnalysisEvent::AddedServiceDefinitionFromApi));
self::assertSame(AnalysisEvent::AfterContainerAnalysis, $analysisEventCollection->last());
}

Expand Down
Loading

0 comments on commit da3884b

Please sign in to comment.