Containers - add ability to purge/release factories; override factories in scoped

orm-types
Garrett Mills 3 years ago
parent cd9bec7c5e
commit dab3d006c8
Signed by: garrettmills
GPG Key ID: D2BF5FBA8298F246

@ -47,6 +47,25 @@ export class Container {
this.registerSingleton('injector', this)
}
/**
* Purge all factories and instances of the given key from this container.
* @param key
*/
purge(key: DependencyKey): this {
this.factories = this.factories.filter(x => !x.match(key))
this.release(key)
return this
}
/**
* Remove all stored instances of the given key from this container.
* @param key
*/
release(key: DependencyKey): this {
this.instances = this.instances.filter(x => x.key !== key)
return this
}
/**
* Register a basic instantiable class as a standard Factory with this container.
* @param {Instantiable} dependency

@ -1,5 +1,6 @@
import {Container, MaybeDependency, MaybeFactory} from './Container'
import {DependencyKey} from './types'
import {DependencyKey, Instantiable} from './types'
import {AbstractFactory} from './factory/AbstractFactory'
/**
* A container that uses some parent container as a base, but
@ -30,6 +31,8 @@ export class ScopedContainer extends Container {
return new ScopedContainer(container)
}
private resolveParentScope = true
constructor(
private parentContainer: Container,
) {
@ -38,11 +41,11 @@ export class ScopedContainer extends Container {
}
hasInstance(key: DependencyKey): boolean {
return super.hasInstance(key) || this.parentContainer.hasInstance(key)
return super.hasInstance(key) || (this.resolveParentScope && this.parentContainer.hasInstance(key))
}
hasKey(key: DependencyKey): boolean {
return super.hasKey(key) || this.parentContainer.hasKey(key)
return super.hasKey(key) || (this.resolveParentScope && this.parentContainer.hasKey(key))
}
getExistingInstance(key: DependencyKey): MaybeDependency {
@ -51,7 +54,9 @@ export class ScopedContainer extends Container {
return inst
}
return this.parentContainer.getExistingInstance(key)
if ( this.resolveParentScope ) {
return this.parentContainer.getExistingInstance(key)
}
}
resolve(key: DependencyKey): MaybeFactory<any> {
@ -60,6 +65,77 @@ export class ScopedContainer extends Container {
return factory
}
return this.parentContainer?.resolve(key)
if ( this.resolveParentScope ) {
return this.parentContainer.resolve(key)
}
}
/**
* Register a basic instantiable class as a standard Factory with this container.
* @param {Instantiable} dependency
*/
register(dependency: Instantiable<any>): this {
return this.withoutParentScopes(() => super.register(dependency))
}
/**
* Register the given function as a factory within the container.
* @param {string} name - unique name to identify the factory in the container
* @param {function} producer - factory to produce a value
*/
registerProducer(name: DependencyKey, producer: () => any): this {
return this.withoutParentScopes(() => super.registerProducer(name, producer))
}
/**
* Register a basic instantiable class as a standard Factory with this container,
* identified by a string name rather than static class.
* @param {string} name - unique name to identify the factory in the container
* @param {Instantiable} dependency
*/
registerNamed(name: string, dependency: Instantiable<any>): this {
return this.withoutParentScopes(() => super.registerNamed(name, dependency))
}
/**
* Register a value as a singleton in the container. It will not be instantiated, but
* can be injected by its unique name.
* @param {string} key - unique name to identify the singleton in the container
* @param value
*/
registerSingleton<T>(key: DependencyKey, value: T): this {
return this.withoutParentScopes(() => super.registerSingleton(key, value))
}
/**
* Register a static class to the container along with its already-instantiated
* instance that will be used to resolve the class.
* @param staticClass
* @param instance
*/
registerSingletonInstance<T>(staticClass: Instantiable<T>, instance: T): this {
return this.withoutParentScopes(() => super.registerSingletonInstance(staticClass, instance))
}
/**
* Register a given factory with the container.
* @param {AbstractFactory} factory
*/
registerFactory(factory: AbstractFactory<unknown>): this {
return this.withoutParentScopes(() => super.registerFactory(factory))
}
/**
* Execute a closure on this container, disabling parent-resolution.
* Effectively, the closure will have access to this container as if
* it were NOT a scoped container, and only contained its factories.
* @param closure
*/
withoutParentScopes<T>(closure: () => T): T {
const oldResolveParentScope = this.resolveParentScope
this.resolveParentScope = false
const value: T = closure()
this.resolveParentScope = oldResolveParentScope
return value
}
}

Loading…
Cancel
Save