Skip to content

Commit

Permalink
Task/split observer interface (#284)
Browse files Browse the repository at this point in the history
* Split up Observer into 3 granular interfaces

* Update changelog for removing Observer
  • Loading branch information
cspray authored Feb 26, 2023
1 parent 3681e52 commit b461af3
Show file tree
Hide file tree
Showing 23 changed files with 135 additions and 133 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Added `cspray/annotated-container-adr` dependency for removed Architectural Decision Records.
- Added `cspray/annotated-container-attribute` dependency for removed Attribute.
- Added `Bootstrap\PreAnalysisObserver`, `Bootstrap\PostAnalysisObserver`, and `Bootstrap\ContainerCreatedObserver`.

### Changed

Expand All @@ -21,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Removed Architectural Decision Records and provided Attributes, replaced in separate packages.
- Removed `DefaultAnnotatedTargetDefinitionConverter`, this implementation was moved to the interface it implemented.
- Removed the `Bootstrap\Observer` interface. Use the more granular implementations added instead.

## [v2.0.0-rc2](https://github.com/cspray/annotated-container/tree/v2.0.0-rc2) - 2023-02-11

Expand Down
5 changes: 4 additions & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,14 @@
7. [Using Configuration Objects](./tutorials/07-using-configuration-objects.md)
8. [Autowire Aware Factory](./tutorials/08-autowire-aware-factory.md)
9. [Autowire aware Invoker](./tutorials/09-autowire-aware-invoker.md)
10. [Annotated Container Observer](./tutorials/10-annotated-container-observers.md)

## How To

1. [Add Third-Party Services](./how-to/01-add-third-party-services.md)
2. [Bootstrap Your Container](./how-to/02-bootstrap-your-container.md)

## References

1. [Attributes List](./references/01-attributes-list.md)
1. [Attributes List](./references/01-attributes-list.md)
2. [Functional API](./references/02-functional-api.md)
8 changes: 1 addition & 7 deletions docs/how-to/02-bootstrap-your-container.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,7 @@ Next, update your configuration.
</annotatedContainer>
```

### Step 5 - Provide your Observers (optional)



### Step 6 - Create Your Container
### Step 5 - Create Your Container

Before completing this step go put some Attributes on the services in your codebase!

Expand Down Expand Up @@ -247,8 +243,6 @@ $container = (new Bootstrap(
))->bootstrapContainer();
```

#### Constructing Observer

#### Changing Resolved Paths

By default, boostrapping expects all the path fragments in your configuration to be in the root of your project. You can have explicit control over which absolute path is used by implementing a `Cspray\AnnotatedContainer\Bootstrap\BootstrappingDirectoryResolver` and passed to `$directoryResolver` contruct argument.
Expand Down
15 changes: 0 additions & 15 deletions docs/references/02-annotated-container-lifecycle.md

This file was deleted.

File renamed without changes.
21 changes: 9 additions & 12 deletions docs/tutorials/10-annotated-container-observers.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,32 @@
# Annotated Container Observers

Annotated Container has a boostrapping observer system that allows you to get access to pertinent information during [Annotated Container's lifecycle](../references/02-annotated-container-lifecycle.md). This system could be used to gather information about the compilation process, perform action on the Container post creation, or some other action that might be necessary. Below we'll talk about how to register listeners and perform actions.
Annotated Container has a boostrapping observer system that allows you to get access to pertinent information during the creation of your container. This system could be used to gather information about the compilation process, perform action on the Container post creation, or some other action that might be necessary. Below we'll talk about how to take advantage of this system to bring more complex functionality to applications powered by Annotated Container.

## Registering Observers

First, you'll need to create a `Cspray\AnnotatedContainer\Boostrap\Observer` implementation.
First, you'll need to decide on what type of observer you want to implement. The example will implement all possible interfaces, to show what's possible. You do not have to implement all 3 in your project; you can choose any of them to implement.

```php
<?php declare(strict_types=1);

namespace Acme\Demo;

use Cspray\AnnotatedContainer\Bootstrap\ContainerCreatedObserver;
use Cspray\AnnotatedContainer\Bootstrap\PostAnalysisObserver;
use Cspray\AnnotatedContainer\Bootstrap\PreAnalysisObserver;
use Cspray\AnnotatedContainer\Profiles\ActiveProfiles;
use Cspray\AnnotatedContainer\Bootstrap\Observer;

final class MyContainerObserver implements Observer {
final class MyContainerObserver implements PreAnalysisObserver, PostAnalysisObserver, ContainerCreatedObserver {

public function beforeCompilation(ActiveProfiles $profiles) : void {
public function notifyPreAnalysis(ActiveProfiles $profiles) : void {
// do something before the source code is analyzed and the ContainerDefinition is compiled
}

public function afterCompilation(ActiveProfiles $profiles, ContainerDefinition $containerDefinition) : void {
public function notifyPostAnalysis(ActiveProfiles $profiles, ContainerDefinition $containerDefinition) : void {
// do something after the source is analyzed and the ContainerDefinition is compiled
}

public function beforeContainerCreation(ActiveProfiles $profiles, ContainerDefinition $containerDefinition) : void {
// do something after the ContainerDefinition is compiled, and the ConatinerFactory has been created with all
// configured ParameterStores
}

public function afterContainerCreation(ActiveProfiles $profiles, ContainerDefinition $containerDefinition, AnnotatedContainer $container) : void {
public function notifyContainerCreated(ActiveProfiles $profiles, ContainerDefinition $containerDefinition, AnnotatedContainer $container) : void {
// do something after the AnnotatedContainer has been created based off of the given ContainerDefinition
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,13 @@
namespace Cspray\AnnotatedContainerFixture\VendorScanningInitializers;

use Cspray\AnnotatedContainer\AnnotatedContainer;
use Cspray\AnnotatedContainer\Bootstrap\Observer;
use Cspray\AnnotatedContainer\Bootstrap\ContainerCreatedObserver;
use Cspray\AnnotatedContainer\Definition\ContainerDefinition;
use Cspray\AnnotatedContainer\Profiles\ActiveProfiles;

class DependencyObserver implements Observer {
class DependencyObserver implements ContainerCreatedObserver {

public function beforeCompilation(ActiveProfiles $activeProfiles) : void {
}

public function afterCompilation(ActiveProfiles $activeProfiles, ContainerDefinition $containerDefinition) : void {
}

public function beforeContainerCreation(ActiveProfiles $activeProfiles, ContainerDefinition $containerDefinition) : void {
}

public function afterContainerCreation(ActiveProfiles $activeProfiles, ContainerDefinition $containerDefinition, AnnotatedContainer $container) : void {
public function notifyContainerCreated(ActiveProfiles $activeProfiles, ContainerDefinition $containerDefinition, AnnotatedContainer $container) : void {
$container->get(SomeService::class)->setSomething('called from observer');
}
}
8 changes: 8 additions & 0 deletions known-issues.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@
<code>array</code>
</MoreSpecificReturnType>
</file>
<file src="src/Bootstrap/XmlBootstrappingConfiguration.php">
<InvalidStringClass occurrences="1">
<code>new $observerClass()</code>
</InvalidStringClass>
<PropertyTypeCoercion occurrences="1">
<code>$observers</code>
</PropertyTypeCoercion>
</file>
<file src="src/Cli/Command/BuildCommand.php">
<MixedArrayAccess occurrences="1">
<code>$composer['extra']['annotatedContainer']['configFile']</code>
Expand Down
19 changes: 11 additions & 8 deletions src/Bootstrap/Bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ final class Bootstrap {
private readonly ?DefinitionProviderFactory $definitionProviderFactory;
private readonly ?ObserverFactory $observerFactory;
/**
* @var list<Observer>
* @var list<PreAnalysisObserver|PostAnalysisObserver|ContainerCreatedObserver>
*/
private array $observers = [];

Expand All @@ -47,7 +47,7 @@ public function __construct(
$this->observerFactory = $observerFactory;
}

public function addObserver(Observer $observer) : void {
public function addObserver(PreAnalysisObserver|PostAnalysisObserver|ContainerCreatedObserver $observer) : void {
$this->observers[] = $observer;
}

Expand Down Expand Up @@ -110,13 +110,17 @@ public function isActive(string $profile) : bool {
}

foreach ($this->observers as $observer) {
$observer->beforeCompilation($activeProfiles);
if ($observer instanceof PreAnalysisObserver) {
$observer->notifyPreAnalysis($activeProfiles);
}
}

$containerDefinition = $this->getCompiler($cacheDir)->analyze($compileOptions->build());

foreach ($this->observers as $observer) {
$observer->afterCompilation($activeProfiles, $containerDefinition);
if ($observer instanceof PostAnalysisObserver) {
$observer->notifyPostAnalysis($activeProfiles, $containerDefinition);
}
}

$factoryOptions = ContainerFactoryOptionsBuilder::forActiveProfiles(...$profiles);
Expand All @@ -131,12 +135,11 @@ public function isActive(string $profile) : bool {
$factoryOptions = $factoryOptions->withLogger($logger);
}

foreach ($this->observers as $observer) {
$observer->beforeContainerCreation($activeProfiles, $containerDefinition);
}
$container = $containerFactory->createContainer($containerDefinition, $factoryOptions->build());
foreach ($this->observers as $observer) {
$observer->afterContainerCreation($activeProfiles, $containerDefinition, $container);
if ($observer instanceof ContainerCreatedObserver) {
$observer->notifyContainerCreated($activeProfiles, $containerDefinition, $container);
}
}
return $container;
}
Expand Down
2 changes: 1 addition & 1 deletion src/Bootstrap/BootstrappingConfiguration.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public function getContainerDefinitionProvider() : ?DefinitionProvider;
public function getParameterStores() : array;

/**
* @return list<Observer>
* @return list<PreAnalysisObserver|PostAnalysisObserver|ContainerCreatedObserver>
*/
public function getObservers() : array;

Expand Down
13 changes: 13 additions & 0 deletions src/Bootstrap/ContainerCreatedObserver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Cspray\AnnotatedContainer\Bootstrap;

use Cspray\AnnotatedContainer\AnnotatedContainer;
use Cspray\AnnotatedContainer\Definition\ContainerDefinition;
use Cspray\AnnotatedContainer\Profiles\ActiveProfiles;

interface ContainerCreatedObserver {

public function notifyContainerCreated(ActiveProfiles $activeProfiles, ContainerDefinition $containerDefinition, AnnotatedContainer $container) : void;

}
19 changes: 0 additions & 19 deletions src/Bootstrap/Observer.php

This file was deleted.

2 changes: 1 addition & 1 deletion src/Bootstrap/ObserverFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@

interface ObserverFactory {

public function createObserver(string $observer) : Observer;
public function createObserver(string $observer) : PreAnalysisObserver|PostAnalysisObserver|ContainerCreatedObserver;

}
13 changes: 13 additions & 0 deletions src/Bootstrap/PostAnalysisObserver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Cspray\AnnotatedContainer\Bootstrap;

use Cspray\AnnotatedContainer\Definition\ContainerDefinition;
use Cspray\AnnotatedContainer\Profiles\ActiveProfiles;

interface PostAnalysisObserver {

public function notifyPostAnalysis(ActiveProfiles $activeProfiles, ContainerDefinition $containerDefinition) : void;


}
11 changes: 11 additions & 0 deletions src/Bootstrap/PreAnalysisObserver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace Cspray\AnnotatedContainer\Bootstrap;

use Cspray\AnnotatedContainer\Profiles\ActiveProfiles;

interface PreAnalysisObserver {

public function notifyPreAnalysis(ActiveProfiles $activeProfiles) : void;

}
16 changes: 2 additions & 14 deletions src/Bootstrap/ServiceWiringObserver.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,9 @@
use Cspray\AnnotatedContainer\Definition\ServiceDefinition;
use Cspray\AnnotatedContainer\Profiles\ActiveProfiles;

abstract class ServiceWiringObserver implements Observer {
abstract class ServiceWiringObserver implements ContainerCreatedObserver {

final public function beforeCompilation(ActiveProfiles $activeProfiles) : void {
// noop
}

final public function afterCompilation(ActiveProfiles $activeProfiles, ContainerDefinition $containerDefinition) : void {
// noop
}

final public function beforeContainerCreation(ActiveProfiles $activeProfiles, ContainerDefinition $containerDefinition) : void {
// noop
}

final public function afterContainerCreation(ActiveProfiles $activeProfiles, ContainerDefinition $containerDefinition, AnnotatedContainer $container) : void {
final public function notifyContainerCreated(ActiveProfiles $activeProfiles, ContainerDefinition $containerDefinition, AnnotatedContainer $container) : void {
$serviceGatherer = new class($containerDefinition, $container) implements ServiceGatherer {

private readonly ContainerDefinition $containerDefinition;
Expand Down
15 changes: 13 additions & 2 deletions src/Bootstrap/XmlBootstrappingConfiguration.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ final class XmlBootstrappingConfiguration implements BootstrappingConfiguration
private readonly array $parameterStores;

/**
* @var list<Observer>
* @var list<PreAnalysisObserver|PostAnalysisObserver|ContainerCreatedObserver>
*/
private readonly array $observers;

Expand Down Expand Up @@ -147,7 +147,7 @@ public function __construct(
if (isset($this->observerFactory)) {
$observer = $this->observerFactory->createObserver($observerClass);
} else {
if (!class_exists($observerClass) || !is_subclass_of($observerClass, Observer::class)) {
if (!$this->isObserverType($observerClass)) {
throw InvalidBootstrapConfiguration::fromConfiguredObserverWrongType();
}
$observer = new $observerClass();
Expand Down Expand Up @@ -206,6 +206,17 @@ public function __construct(
}
}

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);

}

public function getScanDirectories() : array {
return $this->directories;
}
Expand Down
9 changes: 7 additions & 2 deletions src/Exception/InvalidBootstrapConfiguration.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

namespace Cspray\AnnotatedContainer\Exception;

use Cspray\AnnotatedContainer\Bootstrap\ContainerCreatedObserver;
use Cspray\AnnotatedContainer\Bootstrap\Observer;
use Cspray\AnnotatedContainer\Bootstrap\PostAnalysisObserver;
use Cspray\AnnotatedContainer\Bootstrap\PreAnalysisObserver;
use Cspray\AnnotatedContainer\StaticAnalysis\DefinitionProvider;
use Cspray\AnnotatedContainer\ContainerFactory\ParameterStore;

Expand Down Expand Up @@ -31,8 +34,10 @@ public static function fromConfiguredParameterStoreWrongType() : self {

public static function fromConfiguredObserverWrongType() : self {
return new self(sprintf(
'All entries in observers must be classes that implement %s',
Observer::class
'All entries in observers must be classes that implement %s, %s, or %s',
PreAnalysisObserver::class,
PostAnalysisObserver::class,
ContainerCreatedObserver::class
));
}

Expand Down
Loading

0 comments on commit b461af3

Please sign in to comment.