From 70fee44ba07a2cde252d6a6e5e195bdd7aeb9f1d Mon Sep 17 00:00:00 2001 From: Charles Sprayberry Date: Sun, 3 Mar 2024 23:32:49 -0500 Subject: [PATCH 1/2] Remove observers, add events to container factory --- annotated-container.xsd | 7 - composer.json | 1 - .../cspray/package/src/DependencyObserver.php | 15 - src/Bootstrap/Bootstrap.php | 88 +---- src/Bootstrap/BootstrappingConfiguration.php | 6 - src/Bootstrap/ContainerAnalyticsObserver.php | 12 - src/Bootstrap/ContainerCreatedObserver.php | 16 - src/Bootstrap/ObserverFactory.php | 12 - src/Bootstrap/PostAnalysisObserver.php | 16 - src/Bootstrap/PreAnalysisObserver.php | 14 - ...Observer.php => ServiceWiringListener.php} | 19 +- src/Bootstrap/ThirdPartyInitializer.php | 6 - .../XmlBootstrappingConfiguration.php | 45 +-- src/Cli/Command/InitCommand.php | 17 - src/Cli/Command/ValidateCommand.php | 20 +- .../AbstractContainerFactory.php | 15 +- .../IlluminateContainerFactory.php | 7 +- test/Unit/BootstrapTest.php | 340 ++++++------------ test/Unit/Cli/Command/InitCommandTest.php | 83 ----- test/Unit/ContainerFactoryTestCase.php | 24 +- .../AurynContainerFactoryTest.php | 5 +- .../IlluminateContainerFactoryTest.php | 5 +- .../PhpDiContainerFactoryTest.php | 5 +- .../Helper/StubContainerFactoryListener.php | 26 ++ .../XmlBootstrappingConfigurationTest.php | 98 ----- 25 files changed, 207 insertions(+), 695 deletions(-) delete mode 100644 fixture_src/VendorScanningInitializers/vendor/cspray/package/src/DependencyObserver.php delete mode 100644 src/Bootstrap/ContainerAnalyticsObserver.php delete mode 100644 src/Bootstrap/ContainerCreatedObserver.php delete mode 100644 src/Bootstrap/ObserverFactory.php delete mode 100644 src/Bootstrap/PostAnalysisObserver.php delete mode 100644 src/Bootstrap/PreAnalysisObserver.php rename src/Bootstrap/{ServiceWiringObserver.php => ServiceWiringListener.php} (87%) create mode 100644 test/Unit/Helper/StubContainerFactoryListener.php diff --git a/annotated-container.xsd b/annotated-container.xsd index 1d8e9e87..7f65b3e4 100644 --- a/annotated-container.xsd +++ b/annotated-container.xsd @@ -33,7 +33,6 @@ - @@ -75,12 +74,6 @@ - - - - - - diff --git a/composer.json b/composer.json index 166005db..ad33edb2 100644 --- a/composer.json +++ b/composer.json @@ -54,7 +54,6 @@ }, "files": [ "fixture_src/VendorScanningInitializers/vendor/cspray/package/other_src/DependencyDefinitionProvider.php", - "fixture_src/VendorScanningInitializers/vendor/cspray/package/src/DependencyObserver.php", "fixture_src/VendorScanningInitializers/vendor/cspray/package/src/FirstInitializer.php", "fixture_src/VendorScanningInitializers/vendor/cspray/package/src/SecondInitializer.php", "fixture_src/VendorScanningInitializers/vendor/cspray/package/src/SomeService.php", diff --git a/fixture_src/VendorScanningInitializers/vendor/cspray/package/src/DependencyObserver.php b/fixture_src/VendorScanningInitializers/vendor/cspray/package/src/DependencyObserver.php deleted file mode 100644 index 76451b48..00000000 --- a/fixture_src/VendorScanningInitializers/vendor/cspray/package/src/DependencyObserver.php +++ /dev/null @@ -1,15 +0,0 @@ -get(SomeService::class)->setSomething('called from observer'); - } -} \ No newline at end of file diff --git a/src/Bootstrap/Bootstrap.php b/src/Bootstrap/Bootstrap.php index b60ce272..70445286 100644 --- a/src/Bootstrap/Bootstrap.php +++ b/src/Bootstrap/Bootstrap.php @@ -6,6 +6,8 @@ use Cspray\AnnotatedContainer\AnnotatedContainer; use Cspray\AnnotatedContainer\Definition\ContainerDefinition; use Cspray\AnnotatedContainer\Event\BootstrapEmitter; +use Cspray\AnnotatedContainer\Event\ContainerFactoryEmitter; +use Cspray\AnnotatedContainer\Event\Emitter; use Cspray\AnnotatedContainer\Profiles; use Cspray\AnnotatedContainer\StaticAnalysis\AnnotatedTargetContainerDefinitionAnalyzer; use Cspray\AnnotatedContainer\StaticAnalysis\CacheAwareContainerDefinitionAnalyzer; @@ -35,31 +37,22 @@ final class Bootstrap { private readonly ?DefinitionProviderFactory $definitionProviderFactory; - private readonly ?ObserverFactory $observerFactory; - - private readonly ?ContainerFactory $containerFactory; + private readonly ContainerFactory $containerFactory; private readonly Stopwatch $stopwatch; - /** - * @var list - */ - private array $observers = []; - public function __construct( + ContainerFactory $containerFactory, BootstrapEmitter $emitter = null, BootstrappingDirectoryResolver $directoryResolver = null, ParameterStoreFactory $parameterStoreFactory = null, DefinitionProviderFactory $definitionProviderFactory = null, - ObserverFactory $observerFactory = null, Stopwatch $stopwatch = null, - ContainerFactory $containerFactory = null ) { $this->emitter = $emitter; $this->directoryResolver = $directoryResolver ?? $this->defaultDirectoryResolver(); $this->parameterStoreFactory = $parameterStoreFactory ?? new DefaultParameterStoreFactory(); $this->definitionProviderFactory = $definitionProviderFactory; - $this->observerFactory = $observerFactory; $this->stopwatch = $stopwatch ?? new Stopwatch(); $this->containerFactory = $containerFactory; } @@ -73,10 +66,6 @@ private function defaultDirectoryResolver() : BootstrappingDirectoryResolver { return new RootDirectoryBootstrappingDirectoryResolver($rootDir); } - public function addObserver(PreAnalysisObserver|PostAnalysisObserver|ContainerCreatedObserver|ContainerAnalyticsObserver $observer) : void { - $this->observers[] = $observer; - } - public function bootstrapContainer( Profiles $profiles, string $configurationFile = 'annotated-container.xml' @@ -89,16 +78,9 @@ public function bootstrapContainer( $this->emitter?->emitBeforeBootstrap($configuration); - foreach ($configuration->getObservers() as $observer) { - $this->addObserver($observer); - } - - $this->notifyPreAnalysis($profiles); - $analysisPrepped = $this->stopwatch->mark(); $containerDefinition = $this->runStaticAnalysis($configuration, $analysisOptions); - $this->notifyPostAnalysis($profiles, $containerDefinition); $analysisCompleted = $this->stopwatch->mark(); @@ -108,11 +90,8 @@ public function bootstrapContainer( $containerDefinition, ); - $this->notifyContainerCreated($profiles, $containerDefinition, $container); - $metrics = $this->stopwatch->stop(); $analytics = $this->createAnalytics($metrics, $analysisPrepped, $analysisCompleted); - $this->notifyAnalytics($analytics); $this->emitter?->emitAfterBootstrap( $configuration, @@ -129,7 +108,6 @@ private function bootstrappingConfiguration(string $configurationFile) : Bootstr return new XmlBootstrappingConfiguration( $configFile, parameterStoreFactory: $this->parameterStoreFactory, - observerFactory: $this->observerFactory, definitionProviderFactory: $this->definitionProviderFactory ); } @@ -149,14 +127,6 @@ private function analysisOptions(BootstrappingConfiguration $configuration) : Co return $analysisOptions->build(); } - private function notifyPreAnalysis(Profiles $activeProfiles) : void { - foreach ($this->observers as $observer) { - if ($observer instanceof PreAnalysisObserver) { - $observer->notifyPreAnalysis($activeProfiles); - } - } - } - private function runStaticAnalysis( BootstrappingConfiguration $configuration, ContainerDefinitionAnalysisOptions $analysisOptions @@ -181,56 +151,18 @@ private function containerDefinitionAnalyzer(?string $cacheDir) : ContainerDefin return $compiler; } - private function notifyPostAnalysis(Profiles $activeProfiles, ContainerDefinition $containerDefinition) : void { - foreach ($this->observers as $observer) { - if ($observer instanceof PostAnalysisObserver) { - $observer->notifyPostAnalysis($activeProfiles, $containerDefinition); - } - } - } - private function createContainer( BootstrappingConfiguration $configuration, Profiles $activeProfiles, ContainerDefinition $containerDefinition, ) : AnnotatedContainer { - $containerFactory = $this->containerFactory(); - foreach ($configuration->getParameterStores() as $parameterStore) { - $containerFactory->addParameterStore($parameterStore); + $this->containerFactory->addParameterStore($parameterStore); } $factoryOptions = ContainerFactoryOptionsBuilder::forProfiles($activeProfiles); - return $containerFactory->createContainer($containerDefinition, $factoryOptions->build()); - } - - private function containerFactory() : ContainerFactory { - if ($this->containerFactory !== null) { - return $this->containerFactory; - } - - if (class_exists(Injector::class)) { - return new AurynContainerFactory(); - } - - if (class_exists(Container::class)) { - return new PhpDiContainerFactory(); - } - - throw BackingContainerNotFound::fromMissingImplementation(); - } - - private function notifyContainerCreated( - Profiles $activeProfiles, - ContainerDefinition $containerDefinition, - AnnotatedContainer $container - ) : void { - foreach ($this->observers as $observer) { - if ($observer instanceof ContainerCreatedObserver) { - $observer->notifyContainerCreated($activeProfiles, $containerDefinition, $container); - } - } + return $this->containerFactory->createContainer($containerDefinition, $factoryOptions->build()); } private function createAnalytics( @@ -246,12 +178,4 @@ private function createAnalytics( ); } - private function notifyAnalytics(ContainerAnalytics $analytics) : void { - foreach ($this->observers as $observer) { - if ($observer instanceof ContainerAnalyticsObserver) { - $observer->notifyAnalytics($analytics); - } - } - } - } diff --git a/src/Bootstrap/BootstrappingConfiguration.php b/src/Bootstrap/BootstrappingConfiguration.php index b816a14b..35b793bf 100644 --- a/src/Bootstrap/BootstrappingConfiguration.php +++ b/src/Bootstrap/BootstrappingConfiguration.php @@ -23,10 +23,4 @@ public function getContainerDefinitionProvider() : ?DefinitionProvider; */ public function getParameterStores() : array; - /** - * @return list - * @deprecated - */ - public function getObservers() : array; - } diff --git a/src/Bootstrap/ContainerAnalyticsObserver.php b/src/Bootstrap/ContainerAnalyticsObserver.php deleted file mode 100644 index e72e2e26..00000000 --- a/src/Bootstrap/ContainerAnalyticsObserver.php +++ /dev/null @@ -1,12 +0,0 @@ -containerDefinition = new ProfilesAwareContainerDefinition($containerDefinition, $activeProfiles); } + /** + * @param string $type + * @return list + */ public function getServicesForType(string $type) : array { - /** @var array $services */ + /** @var list $services */ $services = []; foreach ($this->containerDefinition->getServiceDefinitions() as $serviceDefinition) { if ($serviceDefinition->isAbstract()) { @@ -85,7 +89,4 @@ public function getDefinition() : ServiceDefinition { }; $this->wireServices($container, $serviceGatherer); } - - abstract protected function wireServices(AnnotatedContainer $container, ServiceGatherer $gatherer) : void; - } \ No newline at end of file diff --git a/src/Bootstrap/ThirdPartyInitializer.php b/src/Bootstrap/ThirdPartyInitializer.php index bc0cdbfb..a2a0beb4 100644 --- a/src/Bootstrap/ThirdPartyInitializer.php +++ b/src/Bootstrap/ThirdPartyInitializer.php @@ -13,12 +13,6 @@ abstract public function getPackageName() : string; */ abstract public function getRelativeScanDirectories() : array; - /** - * @return list - * @deprecated - */ - abstract public function getObserverClasses() : array; - abstract public function getDefinitionProviderClass() : ?string; } \ No newline at end of file diff --git a/src/Bootstrap/XmlBootstrappingConfiguration.php b/src/Bootstrap/XmlBootstrappingConfiguration.php index 50ad2540..2373b002 100644 --- a/src/Bootstrap/XmlBootstrappingConfiguration.php +++ b/src/Bootstrap/XmlBootstrappingConfiguration.php @@ -28,15 +28,9 @@ final class XmlBootstrappingConfiguration implements BootstrappingConfiguration */ private readonly array $parameterStores; - /** - * @var list - */ - private readonly array $observers; - public function __construct( private readonly string $xmlFile, private readonly ?ParameterStoreFactory $parameterStoreFactory = null, - private readonly ?ObserverFactory $observerFactory = null, private readonly ?DefinitionProviderFactory $definitionProviderFactory = null ) { if (!file_exists($this->xmlFile)) { @@ -134,23 +128,6 @@ public function __construct( } } - $observers = []; - $observerNodes = $xpath->query('/ac:annotatedContainer/ac:observers/ac:observer/text()'); - if ($observerNodes instanceof DOMNodeList) { - foreach ($observerNodes as $observerNode) { - $observerClass = (string) $observerNode->nodeValue; - if (isset($this->observerFactory)) { - $observer = $this->observerFactory->createObserver($observerClass); - } else { - if (!$this->isObserverType($observerClass)) { - throw InvalidBootstrapConfiguration::fromConfiguredObserverWrongType($observerClass); - } - $observer = new $observerClass(); - } - $observers[] = $observer; - } - } - /** @var DOMNodeList $cacheDirNodes */ $cacheDirNodes = $xpath->query('/ac:annotatedContainer/ac:cacheDir'); $cache = null; @@ -162,25 +139,12 @@ public function __construct( $this->definitionProvider = $definitionProvider; $this->cacheDir = $cache; $this->parameterStores = $parameterStores; - $this->observers = $observers; } finally { libxml_clear_errors(); libxml_use_internal_errors(false); } } - private function isObserverType(string $observerClass) : bool { - if (!class_exists($observerClass)) { - return false; - } - - return is_subclass_of($observerClass, PreAnalysisObserver::class) || - is_subclass_of($observerClass, PostAnalysisObserver::class) || - is_subclass_of($observerClass, ContainerCreatedObserver::class) || - is_subclass_of($observerClass, ContainerAnalyticsObserver::class); - - } - public function getScanDirectories() : array { return $this->directories; } @@ -201,11 +165,4 @@ public function getCacheDirectory() : ?string { return $this->cacheDir; } - /** - * @return list - * @deprecated - */ - public function getObservers() : array { - return $this->observers; - } -} \ No newline at end of file +} diff --git a/src/Cli/Command/InitCommand.php b/src/Cli/Command/InitCommand.php index e426051e..6071f1fb 100644 --- a/src/Cli/Command/InitCommand.php +++ b/src/Cli/Command/InitCommand.php @@ -340,17 +340,6 @@ private function generateAndSaveConfiguration(Input $input, array $composer, str } } - /** @var string|array|null $observers */ - $observers = $input->getOption('observer'); - $observersNode = $root->appendChild($dom->createElementNS(self::XML_SCHEMA, 'observers')); - if ($observers !== null) { - $observers = is_string($observers) ? [$observers] : $observers; - /** @var string $observer */ - foreach ($observers as $observer) { - $observersNode->appendChild($dom->createElementNS(self::XML_SCHEMA, 'observer', $observer)); - } - } - $vendor = $scanDirectories->appendChild( $dom->createElementNS(self::XML_SCHEMA, 'vendor') ); @@ -381,12 +370,6 @@ private function generateAndSaveConfiguration(Input $input, array $composer, str $dom->createElementNS(self::XML_SCHEMA, 'definitionProvider', $providerClass) ); } - - foreach ($thirdPartyInitializer->getObserverClasses() as $observerClass) { - $observersNode->appendChild( - $dom->createElementNS(self::XML_SCHEMA, 'observer', $observerClass) - ); - } } /** @var string|null $cacheDirOpt */ diff --git a/src/Cli/Command/ValidateCommand.php b/src/Cli/Command/ValidateCommand.php index 6095574a..a7e40a33 100644 --- a/src/Cli/Command/ValidateCommand.php +++ b/src/Cli/Command/ValidateCommand.php @@ -6,7 +6,9 @@ use Cspray\AnnotatedContainer\AnnotatedContainer; use Cspray\AnnotatedContainer\Autowire\AutowireableParameterSet; use Cspray\AnnotatedContainer\Bootstrap\Bootstrap; +use Cspray\AnnotatedContainer\Bootstrap\BootstrappingConfiguration; use Cspray\AnnotatedContainer\Bootstrap\BootstrappingDirectoryResolver; +use Cspray\AnnotatedContainer\Bootstrap\ContainerAnalytics; use Cspray\AnnotatedContainer\Bootstrap\PostAnalysisObserver; use Cspray\AnnotatedContainer\Cli\Command; use Cspray\AnnotatedContainer\Cli\Exception\ConfigurationNotFound; @@ -16,6 +18,8 @@ use Cspray\AnnotatedContainer\ContainerFactory\ContainerFactoryOptions; use Cspray\AnnotatedContainer\ContainerFactory\ParameterStore; use Cspray\AnnotatedContainer\Definition\ContainerDefinition; +use Cspray\AnnotatedContainer\Event\Emitter; +use Cspray\AnnotatedContainer\Event\Listener\Bootstrap\AfterBootstrap; use Cspray\AnnotatedContainer\Exception\UnsupportedOperation; use Cspray\AnnotatedContainer\LogicalConstraint\Check\DuplicateServiceDelegate; use Cspray\AnnotatedContainer\LogicalConstraint\Check\DuplicateServiceName; @@ -122,17 +126,21 @@ public function handle(Input $input, TerminalOutput $output) : int { throw ConfigurationNotFound::fromMissingFile($configFile); } + $emitter = new Emitter(); + $bootstrap = new Bootstrap( + emitter: $emitter, directoryResolver: $this->directoryResolver, containerFactory: $this->noOpContainerFactory() ); $containerDefinition = null; - $infoCapturingObserver = $this->infoCapturingObserver(static function(ContainerDefinition $definition) use(&$containerDefinition) { + $infoCapturingListener = $this->infoCapturingListener(static function(ContainerDefinition $definition) use(&$containerDefinition) { $containerDefinition = $definition; }); - $bootstrap->addObserver($infoCapturingObserver); + + $emitter->addAfterBootstrapListener($infoCapturingListener); $inputProfiles = $input->getOption('profile') ?? ['default']; if (is_string($inputProfiles)) { @@ -219,10 +227,10 @@ public function addParameterStore(ParameterStore $parameterStore) : void { /** * @param Closure(ContainerDefinition):void $closure - * @return PostAnalysisObserver + * @return AfterBootstrap */ - private function infoCapturingObserver(Closure $closure) : PostAnalysisObserver { - return new class($closure) implements PostAnalysisObserver { + private function infoCapturingListener(Closure $closure) : AfterBootstrap { + return new class($closure) implements AfterBootstrap { /** * @param Closure(ContainerDefinition):void $closure */ @@ -230,7 +238,7 @@ public function __construct( private readonly Closure $closure ) {} - public function notifyPostAnalysis(Profiles $activeProfiles, ContainerDefinition $containerDefinition) : void { + public function handleAfterBootstrap(BootstrappingConfiguration $bootstrappingConfiguration, ContainerDefinition $containerDefinition, AnnotatedContainer $container, ContainerAnalytics $containerAnalytics) : void { ($this->closure)($containerDefinition); } }; diff --git a/src/ContainerFactory/AbstractContainerFactory.php b/src/ContainerFactory/AbstractContainerFactory.php index 6187c64a..96a027b6 100644 --- a/src/ContainerFactory/AbstractContainerFactory.php +++ b/src/ContainerFactory/AbstractContainerFactory.php @@ -12,6 +12,7 @@ use Cspray\AnnotatedContainer\Definition\ServiceDefinition; use Cspray\AnnotatedContainer\Definition\ServiceDelegateDefinition; use Cspray\AnnotatedContainer\Definition\ServicePrepareDefinition; +use Cspray\AnnotatedContainer\Event\ContainerFactoryEmitter; use Cspray\AnnotatedContainer\Exception\ParameterStoreNotFound; use Cspray\AnnotatedContainer\Profiles; use Cspray\Typiphy\ObjectType; @@ -21,6 +22,7 @@ abstract class AbstractContainerFactory implements ContainerFactory { protected readonly AliasDefinitionResolver $aliasDefinitionResolver; + private readonly ?ContainerFactoryEmitter $emitter; /** * @var ParameterStore[] @@ -28,21 +30,28 @@ abstract class AbstractContainerFactory implements ContainerFactory { private array $parameterStores = []; public function __construct( - AliasDefinitionResolver $aliasDefinitionResolver = null + ContainerFactoryEmitter $emitter = null, + AliasDefinitionResolver $aliasDefinitionResolver = null, ) { // Injecting environment variables is something we have supported since early versions. // We don't require adding this parameter store explicitly to continue providing this functionality // without the end-user having to change how they construct their ContainerFactory. $this->addParameterStore(new EnvironmentParameterStore()); $this->aliasDefinitionResolver = $aliasDefinitionResolver ?? new StandardAliasDefinitionResolver(); + $this->emitter = $emitter; } final public function createContainer(ContainerDefinition $containerDefinition, ContainerFactoryOptions $containerFactoryOptions = null) : AnnotatedContainer { $activeProfiles = $containerFactoryOptions?->getProfiles() ?? Profiles::fromList(['default']); - $state = $this->createContainerState($containerDefinition, $activeProfiles); + $this->emitter?->emitBeforeContainerCreation($activeProfiles, $containerDefinition); - $container = $this->createAnnotatedContainer($state, $activeProfiles); + $container = $this->createAnnotatedContainer( + $this->createContainerState($containerDefinition, $activeProfiles), + $activeProfiles + ); + + $this->emitter?->emitAfterContainerCreation($activeProfiles, $containerDefinition, $container); return $container; } diff --git a/src/ContainerFactory/IlluminateContainerFactory.php b/src/ContainerFactory/IlluminateContainerFactory.php index 8cec9a7c..cafdc1b2 100644 --- a/src/ContainerFactory/IlluminateContainerFactory.php +++ b/src/ContainerFactory/IlluminateContainerFactory.php @@ -12,6 +12,7 @@ use Cspray\AnnotatedContainer\Definition\ServiceDefinition; use Cspray\AnnotatedContainer\Definition\ServiceDelegateDefinition; use Cspray\AnnotatedContainer\Definition\ServicePrepareDefinition; +use Cspray\AnnotatedContainer\Event\ContainerFactoryEmitter; use Cspray\AnnotatedContainer\Exception\ServiceNotFound; use Cspray\AnnotatedContainer\Profiles; use Cspray\Typiphy\ObjectType; @@ -22,9 +23,11 @@ final class IlluminateContainerFactory extends AbstractContainerFactory { public function __construct( private readonly Container $container = new \Illuminate\Container\Container(), - AliasDefinitionResolver $aliasDefinitionResolver = null + ContainerFactoryEmitter $emitter = null, + AliasDefinitionResolver $aliasDefinitionResolver = null, + ) { - parent::__construct($aliasDefinitionResolver); + parent::__construct($emitter, $aliasDefinitionResolver); } protected function getContainerFactoryState() : ContainerFactoryState { diff --git a/test/Unit/BootstrapTest.php b/test/Unit/BootstrapTest.php index 8bd642de..f5e6bff0 100644 --- a/test/Unit/BootstrapTest.php +++ b/test/Unit/BootstrapTest.php @@ -4,6 +4,7 @@ use Cspray\AnnotatedContainer\AnnotatedContainer; use Cspray\AnnotatedContainer\Bootstrap\Bootstrap; +use Cspray\AnnotatedContainer\Bootstrap\BootstrappingConfiguration; use Cspray\AnnotatedContainer\Bootstrap\ContainerAnalytics; use Cspray\AnnotatedContainer\Bootstrap\ContainerAnalyticsObserver; use Cspray\AnnotatedContainer\Bootstrap\ContainerCreatedObserver; @@ -13,10 +14,12 @@ use Cspray\AnnotatedContainer\Bootstrap\PreAnalysisObserver; use Cspray\AnnotatedContainer\Bootstrap\ServiceFromServiceDefinition; use Cspray\AnnotatedContainer\Bootstrap\ServiceGatherer; -use Cspray\AnnotatedContainer\Bootstrap\ServiceWiringObserver; +use Cspray\AnnotatedContainer\Bootstrap\ServiceWiringListener; +use Cspray\AnnotatedContainer\ContainerFactory\AurynContainerFactory; use Cspray\AnnotatedContainer\ContainerFactory\ContainerFactory; use Cspray\AnnotatedContainer\Definition\ContainerDefinition; use Cspray\AnnotatedContainer\Event\Emitter; +use Cspray\AnnotatedContainer\Event\Listener\Bootstrap\AfterBootstrap; use Cspray\AnnotatedContainer\Profiles; use Cspray\AnnotatedContainer\StaticAnalysis\DefinitionProvider; use Cspray\AnnotatedContainer\ContainerFactory\ParameterStore; @@ -63,7 +66,9 @@ public function testBootstrapSingleConcreteServiceNoCache() : void { ->withContent($goodXml) ->at($this->vfs); - $bootstrap = new Bootstrap(directoryResolver: $directoryResolver); + $bootstrap = new Bootstrap( + new AurynContainerFactory(), directoryResolver: $directoryResolver + ); $container = $bootstrap->bootstrapContainer(Profiles::fromList(['default'])); $service = $container->get(Fixtures::singleConcreteService()->fooImplementation()->getName()); @@ -96,7 +101,10 @@ public function testBootstrapSingleConcreteServiceWithCache() : void { VirtualFilesystem::newDirectory('.annotated-container-cache') ->at($this->vfs); - $bootstrap = new Bootstrap(directoryResolver: $directoryResolver); + $bootstrap = new Bootstrap( + new AurynContainerFactory(), + directoryResolver: $directoryResolver + ); $bootstrap->bootstrapContainer(Profiles::fromList(['default'])); $expected = md5(Fixtures::singleConcreteService()->getPath()); @@ -124,7 +132,10 @@ public function testBootstrapWithValidDefinitionProvider() : void { ->withContent($goodXml) ->at($this->vfs); - $bootstrap = new Bootstrap(directoryResolver: $directoryResolver); + $bootstrap = new Bootstrap( + new AurynContainerFactory(), + directoryResolver: $directoryResolver + ); $container = $bootstrap->bootstrapContainer(Profiles::fromList(['default'])); $service = $container->get(Fixtures::thirdPartyServices()->fooInterface()->getName()); @@ -152,7 +163,10 @@ public function testBootstrapWithParameterStores() : void { ->withContent($goodXml) ->at($this->vfs); - $bootstrap = new Bootstrap(directoryResolver: $directoryResolver); + $bootstrap = new Bootstrap( + new AurynContainerFactory(), + directoryResolver: $directoryResolver + ); $container = $bootstrap->bootstrapContainer(Profiles::fromList(['default'])); $service = $container->get(Fixtures::injectCustomStoreServices()->scalarInjector()->getName()); @@ -178,7 +192,10 @@ public function testBootstrapResolvesProfileServices() : void { ->withContent($goodXml) ->at($this->vfs); - $bootstrap = new Bootstrap(directoryResolver: $directoryResolver); + $bootstrap = new Bootstrap( + new AurynContainerFactory(), + directoryResolver: $directoryResolver + ); $container = $bootstrap->bootstrapContainer(profiles: Profiles::fromList(['default', 'dev'])); $service = $container->get(Fixtures::profileResolvedServices()->fooInterface()->getName()); self::assertInstanceOf(Fixtures::profileResolvedServices()->devImplementation()->getName(), $service); @@ -202,7 +219,10 @@ public function testBootstrapSingleConcreteServiceUsesCustomFileName() : void { ->withContent($goodXml) ->at($this->vfs); - $bootstrap = new Bootstrap(directoryResolver: $directoryResolver); + $bootstrap = new Bootstrap( + new AurynContainerFactory(), + directoryResolver: $directoryResolver + ); $container = $bootstrap->bootstrapContainer(profiles: Profiles::fromList(['default']), configurationFile: 'my-container.xml.dist'); $service = $container->get(Fixtures::singleConcreteService()->fooImplementation()->getName()); @@ -245,7 +265,11 @@ public function createProvider(string $identifier) : DefinitionProvider { } }; - $container = (new Bootstrap(directoryResolver: $directoryResolver, definitionProviderFactory: $factory))->bootstrapContainer(Profiles::fromList(['default'])); + $container = (new Bootstrap( + new AurynContainerFactory(), + directoryResolver: $directoryResolver, + definitionProviderFactory: $factory + ))->bootstrapContainer(Profiles::fromList(['default'])); $service = $container->get(Fixtures::thirdPartyServices()->fooInterface()->getName()); @@ -284,107 +308,17 @@ public function createParameterStore(string $identifier) : ParameterStore { } }; - $container = (new Bootstrap(directoryResolver: $directoryResolver, parameterStoreFactory: $factory))->bootstrapContainer(Profiles::fromList(['default'])); + $container = (new Bootstrap( + new AurynContainerFactory(), + directoryResolver: $directoryResolver, + parameterStoreFactory: $factory + ))->bootstrapContainer(Profiles::fromList(['default'])); $service = $container->get(Fixtures::injectCustomStoreServices()->scalarInjector()->getName()); self::assertSame('ac-ackey', $service->key); } - public function testBootstrapObserverInvokedCorrectOrder() : void { - $directoryResolver = new FixtureBootstrappingDirectoryResolver(); - - $goodXml = << - - - - SingleConcreteService - - - -XML; - - VirtualFilesystem::newFile('annotated-container.xml') - ->withContent($goodXml) - ->at($this->vfs); - - $bootstrap = new Bootstrap(directoryResolver: $directoryResolver); - - $bootstrap->addObserver($subject = new StubBootstrapObserver()); - - $bootstrap->bootstrapContainer(Profiles::fromList(['default'])); - - self::assertCount(3, $subject->getInvokedMethods()); - self::assertSame([ - [sprintf('%s::%s', StubBootstrapObserver::class, 'notifyPreAnalysis')], - [sprintf('%s::%s', StubBootstrapObserver::class, 'notifyPostAnalysis')], - [sprintf('%s::%s', StubBootstrapObserver::class, 'notifyContainerCreated')] - ], $subject->getInvokedMethods()); - } - - public function testBootstrapMultipleObservers() : void { - $directoryResolver = new FixtureBootstrappingDirectoryResolver(); - - $goodXml = << - - - - SingleConcreteService - - - -XML; - - VirtualFilesystem::newFile('annotated-container.xml') - ->withContent($goodXml) - ->at($this->vfs); - - $bootstrap = new Bootstrap(directoryResolver: $directoryResolver); - - $bootstrap->addObserver($one = new StubBootstrapObserver()); - $bootstrap->addObserver($two = new StubBootstrapObserver()); - $bootstrap->addObserver($three = new StubBootstrapObserver()); - - $bootstrap->bootstrapContainer(Profiles::fromList(['default'])); - - self::assertCount(3, $one->getInvokedMethods()); - self::assertCount(3, $two->getInvokedMethods()); - self::assertCount(3, $three->getInvokedMethods()); - } - - public function testObserversAddedFromConfiguration() : void { - $directoryResolver = new FixtureBootstrappingDirectoryResolver(); - - $goodXml = << - - - - SingleConcreteService - - - - Cspray\AnnotatedContainer\Unit\Helper\StubBootstrapObserver - - -XML; - - VirtualFilesystem::newFile('annotated-container.xml') - ->withContent($goodXml) - ->at($this->vfs); - - $bootstrap = new Bootstrap(directoryResolver: $directoryResolver); - $bootstrap->bootstrapContainer(Profiles::fromList(['default'])); - - $observers = (new \ReflectionObject($bootstrap))->getProperty('observers')->getValue($bootstrap); - - self::assertCount(1, $observers); - self::assertInstanceOf(StubBootstrapObserver::class, $observers[0]); - self::assertCount(3, $observers[0]->getInvokedMethods()); - } - public function testServiceWiringObserver() : void { $directoryResolver = new FixtureBootstrappingDirectoryResolver(); @@ -403,9 +337,15 @@ public function testServiceWiringObserver() : void { ->withContent($goodXml) ->at($this->vfs); - $bootstrap = new Bootstrap(directoryResolver: $directoryResolver); + $emitter = new Emitter(); + + $bootstrap = new Bootstrap( + new AurynContainerFactory($emitter), + emitter: $emitter, + directoryResolver: $directoryResolver + ); - $observer = new class extends ServiceWiringObserver { + $listener = new class extends ServiceWiringListener { private ?AnnotatedContainer $container = null; private array $services = []; @@ -423,17 +363,18 @@ protected function wireServices(AnnotatedContainer $container, ServiceGatherer $ $this->services = $gatherer->getServicesForType(Fixtures::ambiguousAliasedServices()->fooInterface()->getName()); } }; - $bootstrap->addObserver($observer); + + $emitter->addAfterContainerCreationListener($listener); $container = $bootstrap->bootstrapContainer(Profiles::fromList(['default'])); - $actual = $observer->getServices(); + $actual = $listener->getServices(); $actualServices = array_map(fn(ServiceFromServiceDefinition $fromServiceDefinition) => $fromServiceDefinition->getService(), $actual); usort($actualServices, fn($a, $b) => $a::class <=> $b::class); - self::assertSame($container, $observer->getAnnotatedContainer()); + self::assertSame($container, $listener->getAnnotatedContainer()); self::assertSame([ $container->get(Fixtures::ambiguousAliasedServices()->barImplementation()->getName()), $container->get(Fixtures::ambiguousAliasedServices()->bazImplementation()->getName()), @@ -459,9 +400,15 @@ public function testServiceWiringObserverByAttributes() : void { ->withContent($goodXml) ->at($this->vfs); - $bootstrap = new Bootstrap(directoryResolver: $directoryResolver); + $emitter = new Emitter(); + + $bootstrap = new Bootstrap( + new AurynContainerFactory($emitter), + emitter: $emitter, + directoryResolver: $directoryResolver + ); - $observer = new class extends ServiceWiringObserver { + $listener = new class extends ServiceWiringListener { private ?AnnotatedContainer $container = null; private array $services = []; @@ -479,14 +426,15 @@ protected function wireServices(AnnotatedContainer $container, ServiceGatherer $ $this->services = $gatherer->getServicesWithAttribute(Repository::class); } }; - $bootstrap->addObserver($observer); + + $emitter->addAfterContainerCreationListener($listener); $container = $bootstrap->bootstrapContainer(Profiles::fromList(['default', 'test'])); - $actual = $observer->getServices(); + $actual = $listener->getServices(); $actualServices = array_map(fn(ServiceFromServiceDefinition $fromServiceDefinition) => $fromServiceDefinition->getService(), $actual); - self::assertSame($container, $observer->getAnnotatedContainer()); + self::assertSame($container, $listener->getAnnotatedContainer()); self::assertSame([ $container->get(Fixtures::customServiceAttribute()->myRepo()->getName()), ], $actualServices); @@ -510,9 +458,15 @@ public function testServiceWiringObserverByTypeProfileAware() : void { ->withContent($goodXml) ->at($this->vfs); - $bootstrap = new Bootstrap(directoryResolver: $directoryResolver); + $emitter = new Emitter(); - $observer = new class extends ServiceWiringObserver { + $bootstrap = new Bootstrap( + new AurynContainerFactory($emitter), + emitter: $emitter, + directoryResolver: $directoryResolver + ); + + $listener = new class extends ServiceWiringListener { private ?AnnotatedContainer $container = null; private array $services = []; @@ -530,17 +484,18 @@ protected function wireServices(AnnotatedContainer $container, ServiceGatherer $ $this->services = $gatherer->getServicesForType(Fixtures::profileResolvedServices()->fooInterface()->getName()); } }; - $bootstrap->addObserver($observer); + + $emitter->addAfterContainerCreationListener($listener); $container = $bootstrap->bootstrapContainer(Profiles::fromList(['default', 'prod'])); - $actual = $observer->getServices(); + $actual = $listener->getServices(); $actualServices = array_map(fn(ServiceFromServiceDefinition $fromServiceDefinition) => $fromServiceDefinition->getService(), $actual); usort($actualServices, fn($a, $b) => $a::class <=> $b::class); - self::assertSame($container, $observer->getAnnotatedContainer()); + self::assertSame($container, $listener->getAnnotatedContainer()); self::assertSame([ $container->get(Fixtures::profileResolvedServices()->prodImplementation()->getName()), ], $actualServices); @@ -564,9 +519,15 @@ public function testServiceWiringObserverByAttributesProfileAware() : void { ->withContent($goodXml) ->at($this->vfs); - $bootstrap = new Bootstrap(directoryResolver: $directoryResolver); + $emitter = new Emitter(); + + $bootstrap = new Bootstrap( + new AurynContainerFactory($emitter), + emitter: $emitter, + directoryResolver: $directoryResolver + ); - $observer = new class extends ServiceWiringObserver { + $listener = new class extends ServiceWiringListener { private ?AnnotatedContainer $container = null; private array $services = []; @@ -584,88 +545,14 @@ protected function wireServices(AnnotatedContainer $container, ServiceGatherer $ $this->services = $gatherer->getServicesWithAttribute(Repository::class); } }; - $bootstrap->addObserver($observer); + + $emitter->addAfterContainerCreationListener($listener); // The Repository is only active under 'test' profile and should not be included $container = $bootstrap->bootstrapContainer(Profiles::fromList(['default', 'dev'])); - self::assertSame($container, $observer->getAnnotatedContainer()); - self::assertEmpty($observer->getServices()); - } - - public function testObserverFactoryRespected() : void { - $directoryResolver = new FixtureBootstrappingDirectoryResolver(); - - $goodXml = << - - - - SingleConcreteService - - - - Passed to ObserverFactory - - -XML; - - VirtualFilesystem::newFile('annotated-container.xml') - ->withContent($goodXml) - ->at($this->vfs); - - $observerFactory = $this->getMockBuilder(ObserverFactory::class)->getMock(); - $observerFactory->expects($this->once()) - ->method('createObserver') - ->with('Passed to ObserverFactory') - ->willReturn($this->getMockBuilder(PreAnalysisObserver::class)->getMock()); - - (new Bootstrap( - directoryResolver: $directoryResolver, - observerFactory: $observerFactory - ))->bootstrapContainer(Profiles::fromList(['default'])); - } - - public function testContainerAnalyticsObserverNotifiedAfterContainerCreated() : void { - $directoryResolver = new FixtureBootstrappingDirectoryResolver(); - - $goodXml = << - - - - SingleConcreteService - - - -XML; - - VirtualFilesystem::newFile('annotated-container.xml') - ->withContent($goodXml) - ->at($this->vfs); - - $observer = new class implements ContainerCreatedObserver, ContainerAnalyticsObserver { - private array $calls = []; - - public function notifyAnalytics(ContainerAnalytics $analytics) : void { - $this->calls[] = __FUNCTION__; - } - - public function notifyContainerCreated(Profiles $activeProfiles, ContainerDefinition $containerDefinition, AnnotatedContainer $container) : void { - $this->calls[] = __FUNCTION__; - } - - public function getCalls() : array { - return $this->calls; - } - }; - - $subject = new Bootstrap(directoryResolver: $directoryResolver); - $subject->addObserver($observer); - - $subject->bootstrapContainer(Profiles::fromList(['default'])); - - self::assertSame(['notifyContainerCreated', 'notifyAnalytics'], $observer->getCalls()); + self::assertSame($container, $listener->getAnnotatedContainer()); + self::assertEmpty($listener->getServices()); } public function testContainerAnalyticsHasExpectedTotalDuration() : void { @@ -686,27 +573,32 @@ public function testContainerAnalyticsHasExpectedTotalDuration() : void { ->withContent($goodXml) ->at($this->vfs); - $observer = new class implements ContainerAnalyticsObserver { - private ?ContainerAnalytics $analytics = null; + $emitter = new Emitter(); - public function notifyAnalytics(ContainerAnalytics $analytics) : void { - $this->analytics = $analytics; - } + $listener = new class implements AfterBootstrap { + private ?ContainerAnalytics $analytics = null; public function getAnalytics() : ?ContainerAnalytics { return $this->analytics; } + + public function handleAfterBootstrap(BootstrappingConfiguration $bootstrappingConfiguration, ContainerDefinition $containerDefinition, AnnotatedContainer $container, ContainerAnalytics $containerAnalytics,) : void { + $this->analytics = $containerAnalytics; + } }; $subject = new Bootstrap( + new AurynContainerFactory(), + emitter: $emitter, directoryResolver: $directoryResolver, stopwatch: new Stopwatch(new KnownIncrementingPreciseTime()) ); - $subject->addObserver($observer); + + $emitter->addAfterBootstrapListener($listener); $subject->bootstrapContainer(Profiles::fromList(['default'])); - $analytics = $observer->getAnalytics(); + $analytics = $listener->getAnalytics(); self::assertNotNull($analytics); self::assertSame(3, $analytics->totalTime->timeTakenInNanoseconds()); @@ -715,38 +607,6 @@ public function getAnalytics() : ?ContainerAnalytics { self::assertSame(1, $analytics->timeTakenCreatingContainer->timeTakenInNanoseconds()); } - public function testContainerAnalyticsObserverInConfigurationRespected() : void { - $directoryResolver = new FixtureBootstrappingDirectoryResolver(); - - $goodXml = << - - - - SingleConcreteService - - - - Cspray\AnnotatedContainer\Unit\Helper\StubAnalyticsObserver - - -XML; - - VirtualFilesystem::newFile('annotated-container.xml') - ->withContent($goodXml) - ->at($this->vfs); - - $subject = new Bootstrap( - directoryResolver: $directoryResolver, - ); - - StubAnalyticsObserver::$analytics = null; - - $subject->bootstrapContainer(Profiles::fromList(['default'])); - - self::assertNotNull(StubAnalyticsObserver::$analytics); - } - public function testContainerFactoryPassedToConstructorTakesPriority() : void { $directoryResolver = new FixtureBootstrappingDirectoryResolver(); @@ -803,7 +663,11 @@ public function testBootstrapEventsTriggeredInCorrectOrder() : void { $emitter->addBeforeBootstrapListener($listener); $emitter->addAfterBootstrapListener($listener); - $bootstrap = new Bootstrap(emitter: $emitter, directoryResolver: $directoryResolver); + $bootstrap = new Bootstrap( + new AurynContainerFactory(), + emitter: $emitter, + directoryResolver: $directoryResolver + ); $bootstrap->bootstrapContainer(Profiles::fromList(['default'])); self::assertSame( diff --git a/test/Unit/Cli/Command/InitCommandTest.php b/test/Unit/Cli/Command/InitCommandTest.php index cb3d4a92..4fe0d923 100644 --- a/test/Unit/Cli/Command/InitCommandTest.php +++ b/test/Unit/Cli/Command/InitCommandTest.php @@ -295,9 +295,6 @@ public function testInitDefaultFileComposerJsonPresentCreatesConfigurationFile() Cspray\AnnotatedContainerFixture\VendorScanningInitializers\DependencyDefinitionProvider - - Cspray\AnnotatedContainerFixture\VendorScanningInitializers\DependencyObserver - .annotated-container-cache @@ -355,7 +352,6 @@ public function testDefaultInitTakesConfigurationNameFromOption() : void { - .annotated-container-cache @@ -399,7 +395,6 @@ public function testConfigFileFromComposerRespected() : void { - .annotated-container-cache @@ -461,7 +456,6 @@ public function testHandlesCacheDirAlreadyPresent() : void { - .annotated-container-cache @@ -502,7 +496,6 @@ public function testRespectCacheDirProvidedAsOption() : void { - my-cache-dir @@ -544,7 +537,6 @@ public function testRespectsNestedCacheDir() : void { - path/cache/my-cache-dir @@ -580,7 +572,6 @@ public function testSingleDefinitionProviderRespected() : void { ConsumerClass - .annotated-container-cache @@ -616,7 +607,6 @@ public function testSingleParameterStoreRespected() : void { MyParameterStoreClass - .annotated-container-cache @@ -653,7 +643,6 @@ public function testMultipleParameterStoresRespected() : void { MyParameterStoreClassOne MyParameterStoreClassTwo - .annotated-container-cache @@ -661,78 +650,6 @@ public function testMultipleParameterStoresRespected() : void { self::assertStringEqualsFile('vfs://root/annotated-container.xml', $expected); } - public function testSingleObserverRespected() : void { - VirtualFilesystem::newFile('composer.json') - ->withContent(json_encode([ - 'autoload' => [ - 'psr-0' => [ - 'Namespace\\' => 'src' - ] - ], - ], JSON_THROW_ON_ERROR))->at($this->vfs); - - $input = new StubInput(['observer' => 'MyObserverClass'], ['init']); - $exitCode = $this->subject->handle($input, $this->output); - - self::assertSame(0, $exitCode); - - $expected = << - - - - src - - - - - - MyObserverClass - - .annotated-container-cache - - -XML; - self::assertStringEqualsFile('vfs://root/annotated-container.xml', $expected); - } - - public function testMultipleObserversRespected() : void { - VirtualFilesystem::newFile('composer.json') - ->withContent(json_encode([ - 'autoload' => [ - 'psr-0' => [ - 'Namespace\\' => 'src' - ] - ], - ], JSON_THROW_ON_ERROR))->at($this->vfs); - - $input = new StubInput(['observer' => ['MyObserverClassOne', 'MyObserverClassTwo']], ['init']); - $exitCode = $this->subject->handle($input, $this->output); - - self::assertSame(0, $exitCode); - - $expected = << - - - - src - - - - - - MyObserverClassOne - MyObserverClassTwo - - .annotated-container-cache - - -XML; - self::assertStringEqualsFile('vfs://root/annotated-container.xml', $expected); - } - - public function testConfigFileBooleanThrowsException() : void { $this->expectException(InvalidOptionType::class); $this->expectExceptionMessage('The option "config-file" MUST NOT be a flag-only option.'); diff --git a/test/Unit/ContainerFactoryTestCase.php b/test/Unit/ContainerFactoryTestCase.php index abc42b55..82f1cfea 100644 --- a/test/Unit/ContainerFactoryTestCase.php +++ b/test/Unit/ContainerFactoryTestCase.php @@ -5,6 +5,8 @@ use Cspray\AnnotatedContainer\Autowire\AutowireableFactory; use Cspray\AnnotatedContainer\Autowire\AutowireableInvoker; use Cspray\AnnotatedContainer\ContainerFactory\IlluminateContainerFactory; +use Cspray\AnnotatedContainer\Event\Emitter; +use Cspray\AnnotatedContainer\Event\Listener\ContainerFactory\BeforeContainerCreation; use Cspray\AnnotatedContainer\Exception\InvalidAlias; use Cspray\AnnotatedContainer\Profiles; use Cspray\AnnotatedContainer\StaticAnalysis\AnnotatedTargetContainerDefinitionAnalyzer; @@ -21,6 +23,7 @@ use Cspray\AnnotatedContainer\Exception\ParameterStoreNotFound; use Cspray\AnnotatedContainer\Serializer\ContainerDefinitionSerializer; use Cspray\AnnotatedContainer\AnnotatedContainer; +use Cspray\AnnotatedContainer\Unit\Helper\StubContainerFactoryListener; use Cspray\AnnotatedContainerFixture; use Cspray\AnnotatedContainerFixture\Fixture; use Cspray\AnnotatedContainerFixture\Fixtures; @@ -43,7 +46,7 @@ abstract class ContainerFactoryTestCase extends TestCase { private Profiles $activeProfiles; - abstract protected function getContainerFactory() : ContainerFactory; + abstract protected function getContainerFactory(Emitter $emitter = new Emitter()) : ContainerFactory; abstract protected function getBackingContainerInstanceOf() : ObjectType; @@ -58,13 +61,14 @@ private function getContainer( string $dir, Profiles $profiles = null, ParameterStore $parameterStore = null, + Emitter $emitter = new Emitter() ) : AnnotatedContainer { $compiler = $this->getContainerDefinitionCompiler(); $optionsBuilder = ContainerDefinitionAnalysisOptionsBuilder::scanDirectories($dir); $containerDefinition = $compiler->analyze($optionsBuilder->build()); $containerOptions = ContainerFactoryOptionsBuilder::forProfiles($profiles ?? Profiles::fromList(['default'])); - $factory = $this->getContainerFactory(); + $factory = $this->getContainerFactory($emitter); if ($parameterStore !== null) { $factory->addParameterStore($parameterStore); } @@ -462,4 +466,20 @@ public function testDeserializingContainerWithInjectAllowsServiceCreation(Fixtur $assertions($containerFactory, $deserialize); } + public function testContainerCreationEventsEmitted() : void { + $emitter = new Emitter(); + + $listener = new StubContainerFactoryListener(); + $emitter->addBeforeContainerCreationListener($listener); + $emitter->addAfterContainerCreationListener($listener); + + $this->getContainer( + Fixtures::singleConcreteService()->getPath(), + Profiles::fromList(['default']), + emitter: $emitter + ); + + self::assertSame(['BeforeContainerCreation', 'AfterContainerCreation'], $listener->getTriggeredEvents()); + } + } diff --git a/test/Unit/ContainerFactoryTests/AurynContainerFactoryTest.php b/test/Unit/ContainerFactoryTests/AurynContainerFactoryTest.php index 4985bb5f..a4ead4f8 100644 --- a/test/Unit/ContainerFactoryTests/AurynContainerFactoryTest.php +++ b/test/Unit/ContainerFactoryTests/AurynContainerFactoryTest.php @@ -5,14 +5,15 @@ use Auryn\Injector; use Cspray\AnnotatedContainer\ContainerFactory\AurynContainerFactory; use Cspray\AnnotatedContainer\ContainerFactory\ContainerFactory; +use Cspray\AnnotatedContainer\Event\Emitter; use Cspray\AnnotatedContainer\Unit\ContainerFactoryTestCase; use Cspray\Typiphy\ObjectType; use function Cspray\Typiphy\objectType; class AurynContainerFactoryTest extends ContainerFactoryTestCase { - protected function getContainerFactory() : ContainerFactory { - return new AurynContainerFactory(); + protected function getContainerFactory(Emitter $emitter = new Emitter()) : ContainerFactory { + return new AurynContainerFactory(emitter: $emitter); } protected function getBackingContainerInstanceOf() : ObjectType { diff --git a/test/Unit/ContainerFactoryTests/IlluminateContainerFactoryTest.php b/test/Unit/ContainerFactoryTests/IlluminateContainerFactoryTest.php index ca7c033a..f7d2693c 100644 --- a/test/Unit/ContainerFactoryTests/IlluminateContainerFactoryTest.php +++ b/test/Unit/ContainerFactoryTests/IlluminateContainerFactoryTest.php @@ -4,6 +4,7 @@ use Cspray\AnnotatedContainer\ContainerFactory\ContainerFactory; use Cspray\AnnotatedContainer\ContainerFactory\IlluminateContainerFactory; +use Cspray\AnnotatedContainer\Event\Emitter; use Cspray\AnnotatedContainer\Unit\ContainerFactoryTestCase; use Cspray\Typiphy\ObjectType; use Illuminate\Contracts\Container\Container; @@ -11,8 +12,8 @@ class IlluminateContainerFactoryTest extends ContainerFactoryTestCase { - protected function getContainerFactory() : ContainerFactory { - return new IlluminateContainerFactory(); + protected function getContainerFactory(Emitter $emitter = new Emitter()) : ContainerFactory { + return new IlluminateContainerFactory(emitter: $emitter); } protected function getBackingContainerInstanceOf() : ObjectType { diff --git a/test/Unit/ContainerFactoryTests/PhpDiContainerFactoryTest.php b/test/Unit/ContainerFactoryTests/PhpDiContainerFactoryTest.php index 44633ed4..8594413e 100644 --- a/test/Unit/ContainerFactoryTests/PhpDiContainerFactoryTest.php +++ b/test/Unit/ContainerFactoryTests/PhpDiContainerFactoryTest.php @@ -4,6 +4,7 @@ use Cspray\AnnotatedContainer\ContainerFactory\ContainerFactory; use Cspray\AnnotatedContainer\ContainerFactory\PhpDiContainerFactory; +use Cspray\AnnotatedContainer\Event\Emitter; use Cspray\AnnotatedContainer\Unit\ContainerFactoryTestCase; use Cspray\Typiphy\ObjectType; use DI\Container; @@ -11,8 +12,8 @@ class PhpDiContainerFactoryTest extends ContainerFactoryTestCase { - protected function getContainerFactory() : ContainerFactory { - return new PhpDiContainerFactory(); + protected function getContainerFactory(Emitter $emitter = new Emitter()) : ContainerFactory { + return new PhpDiContainerFactory(emitter: $emitter); } protected function getBackingContainerInstanceOf() : ObjectType { diff --git a/test/Unit/Helper/StubContainerFactoryListener.php b/test/Unit/Helper/StubContainerFactoryListener.php new file mode 100644 index 00000000..f34c7840 --- /dev/null +++ b/test/Unit/Helper/StubContainerFactoryListener.php @@ -0,0 +1,26 @@ +triggeredEvents[] = 'AfterContainerCreation'; + } + + public function handleBeforeContainerCreation(Profiles $profiles, ContainerDefinition $containerDefinition) : void { + $this->triggeredEvents[] = 'BeforeContainerCreation'; + } + + public function getTriggeredEvents() : array { + return $this->triggeredEvents; + } +} \ No newline at end of file diff --git a/test/Unit/XmlBootstrappingConfigurationTest.php b/test/Unit/XmlBootstrappingConfigurationTest.php index 07999da3..29b50b3c 100644 --- a/test/Unit/XmlBootstrappingConfigurationTest.php +++ b/test/Unit/XmlBootstrappingConfigurationTest.php @@ -393,104 +393,6 @@ public function createProvider(string $identifier) : DefinitionProvider { self::assertContainsOnlyInstancesOf(StubDefinitionProviderWithDependencies::class, $provider->getDefinitionProviders()); } - public function testObserversContainsNonClassThrowsException() : void { - $badXml = << - - - - src - - - - something not a class - - -XML; - - VirtualFilesystem::newFile('annotated-container.xml') - ->withContent($badXml) - ->at($this->vfs); - - $this->expectException(InvalidBootstrapConfiguration::class); - $this->expectExceptionMessage(sprintf( - 'The entry something not a class in observers does not implement one of the following interfaces %s, %s, %s or %s', - PreAnalysisObserver::class, - PostAnalysisObserver::class, - ContainerCreatedObserver::class, - ContainerAnalyticsObserver::class - )); - new XmlBootstrappingConfiguration( - 'vfs://root/annotated-container.xml', - ); - } - - public function testObserversContainsNotObserverThrowsException() : void { - $badXml = << - - - - src - - - - Cspray\AnnotatedContainer\Helper\StubDefinitionProvider - - -XML; - - VirtualFilesystem::newFile('annotated-container.xml') - ->withContent($badXml) - ->at($this->vfs); - - $this->expectException(InvalidBootstrapConfiguration::class); - $this->expectExceptionMessage(sprintf( - 'The entry Cspray\AnnotatedContainer\Helper\StubDefinitionProvider in observers does not implement one of the following interfaces %s, %s, %s or %s', - PreAnalysisObserver::class, - PostAnalysisObserver::class, - ContainerCreatedObserver::class, - ContainerAnalyticsObserver::class - )); - new XmlBootstrappingConfiguration( - 'vfs://root/annotated-container.xml', - ); - } - - public function testObserverFactoryPresentRespected() : void { - $goodXml = << - - - - src - - - - Cspray\AnnotatedContainer\Unit\Helper\StubBootstrapObserverWithDependencies - - -XML; - - $observerFactory = new class implements ObserverFactory { - public function createObserver(string $observer) : PreAnalysisObserver|PostAnalysisObserver|ContainerCreatedObserver { - return new $observer('from observer factory'); - } - }; - - VirtualFilesystem::newFile('annotated-container.xml') - ->withContent($goodXml) - ->at($this->vfs); - - $config = new XmlBootstrappingConfiguration( - 'vfs://root/annotated-container.xml', - observerFactory: $observerFactory - ); - - self::assertCount(1, $config->getObservers()); - self::assertInstanceOf(StubBootstrapObserverWithDependencies::class, $config->getObservers()[0]); - } - public function testVendorScanDirectoriesIncludedInList() : void { $goodXml = << From cd3cf0addf561cd4551c3588e2447af6cf4f71ef Mon Sep 17 00:00:00 2001 From: Charles Sprayberry Date: Sun, 3 Mar 2024 23:41:58 -0500 Subject: [PATCH 2/2] Resolve static analysis issues --- known-issues.xml | 62 +++---------------- phpunit.xml | 2 +- src/Bootstrap/ServiceWiringListener.php | 2 +- src/Cli/Command/ValidateCommand.php | 10 +-- src/Exception/BackingContainerNotFound.php | 11 ---- .../InvalidBootstrapConfiguration.php | 13 +--- src/Exception/InvalidLogFile.php | 12 ---- src/Exception/UnsupportedOperation.php | 11 ---- 8 files changed, 15 insertions(+), 108 deletions(-) delete mode 100644 src/Exception/BackingContainerNotFound.php delete mode 100644 src/Exception/InvalidLogFile.php delete mode 100644 src/Exception/UnsupportedOperation.php diff --git a/known-issues.xml b/known-issues.xml index cfb9e21f..6c74dcdb 100644 --- a/known-issues.xml +++ b/known-issues.xml @@ -1,22 +1,5 @@ - - - ?ObserverFactory - ObserverFactory - PreAnalysisObserver|PostAnalysisObserver|ContainerCreatedObserver|ContainerAnalyticsObserver $observer - array - private array $observers = []; - - - getObservers - - - - - list<PreAnalysisObserver|PostAnalysisObserver|ContainerCreatedObserver|ContainerAnalyticsObserver> - - $composerData['extra'] @@ -35,34 +18,13 @@ isDot - - - PreAnalysisObserver|PostAnalysisObserver|ContainerCreatedObserver - - - - - ServiceWiringObserver - - - $services - - - array - - - - - array - list<PreAnalysisObserver|PostAnalysisObserver|ContainerCreatedObserver|ContainerAnalyticsObserver> - private - - - new $observerClass() - - - $observers - + + + $service + + + $service + @@ -85,9 +47,6 @@ - - getObserverClasses - $composer $configName @@ -109,13 +68,6 @@ - - PostAnalysisObserver - PostAnalysisObserver - - - class($closure) implements PostAnalysisObserver { - $configOption $configOption diff --git a/phpunit.xml b/phpunit.xml index 329abfc0..50ab67ff 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -29,7 +29,7 @@ - + diff --git a/src/Bootstrap/ServiceWiringListener.php b/src/Bootstrap/ServiceWiringListener.php index de73fdf4..7a02a8a5 100644 --- a/src/Bootstrap/ServiceWiringListener.php +++ b/src/Bootstrap/ServiceWiringListener.php @@ -28,7 +28,7 @@ public function __construct( } /** - * @param string $type + * @param class-string $type * @return list */ public function getServicesForType(string $type) : array { diff --git a/src/Cli/Command/ValidateCommand.php b/src/Cli/Command/ValidateCommand.php index a7e40a33..f6f812ab 100644 --- a/src/Cli/Command/ValidateCommand.php +++ b/src/Cli/Command/ValidateCommand.php @@ -199,23 +199,23 @@ public function createContainer(ContainerDefinition $containerDefinition, Contai return new class implements AnnotatedContainer { public function getBackingContainer() : object { - throw UnsupportedOperation::fromMethodNotSupported(__METHOD__); + throw new \RuntimeException(__METHOD__); } public function make(string $classType, AutowireableParameterSet $parameters = null) : object { - throw UnsupportedOperation::fromMethodNotSupported(__METHOD__); + throw new \RuntimeException(__METHOD__); } public function invoke(callable $callable, AutowireableParameterSet $parameters = null) : mixed { - throw UnsupportedOperation::fromMethodNotSupported(__METHOD__); + throw new \RuntimeException(__METHOD__); } public function get(string $id) { - throw UnsupportedOperation::fromMethodNotSupported(__METHOD__); + throw new \RuntimeException(__METHOD__); } public function has(string $id) : bool { - throw UnsupportedOperation::fromMethodNotSupported(__METHOD__); + throw new \RuntimeException(__METHOD__); } }; } diff --git a/src/Exception/BackingContainerNotFound.php b/src/Exception/BackingContainerNotFound.php deleted file mode 100644 index 246864c2..00000000 --- a/src/Exception/BackingContainerNotFound.php +++ /dev/null @@ -1,11 +0,0 @@ -