add: adding support manager
This commit is contained in:
parent
9dc7b8940a
commit
85a4517440
2 changed files with 258 additions and 0 deletions
136
packages/support/lib/src/manager.dart
Normal file
136
packages/support/lib/src/manager.dart
Normal file
|
@ -0,0 +1,136 @@
|
|||
import 'package:platform_container/container.dart';
|
||||
import 'package:platform_support/src/fluent.dart';
|
||||
|
||||
/// Base class for managing drivers with different implementations.
|
||||
///
|
||||
/// This class provides a foundation for managing different implementations of a service,
|
||||
/// similar to Laravel's Manager class. It handles driver creation, caching, and custom
|
||||
/// driver registration.
|
||||
abstract class Manager {
|
||||
/// The container instance.
|
||||
final Container container;
|
||||
|
||||
/// The configuration repository instance.
|
||||
final Fluent config;
|
||||
|
||||
/// The registered custom driver creators.
|
||||
final Map<String, dynamic Function(Container)> _customCreators = {};
|
||||
|
||||
/// The array of created "drivers".
|
||||
final Map<String, dynamic> _drivers = {};
|
||||
|
||||
/// Create a new manager instance.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [container]: The container instance to use for resolving dependencies
|
||||
Manager(this.container) : config = container.make<Fluent>();
|
||||
|
||||
/// Get the default driver name.
|
||||
///
|
||||
/// This method must be implemented by concrete managers to specify which
|
||||
/// driver should be used by default. Returns null if no default driver is set.
|
||||
String? getDefaultDriver();
|
||||
|
||||
/// Get a driver instance.
|
||||
///
|
||||
/// This method returns an instance of the requested driver. If the driver
|
||||
/// has already been created, it returns the cached instance. Otherwise,
|
||||
/// it creates a new instance.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [driver]: The name of the driver to get. If null, uses default driver.
|
||||
///
|
||||
/// Returns:
|
||||
/// The driver instance.
|
||||
///
|
||||
/// Throws:
|
||||
/// - [ArgumentError] if no driver name is provided and no default exists
|
||||
T driver<T>([String? driver]) {
|
||||
driver ??= getDefaultDriver();
|
||||
|
||||
if (driver == null) {
|
||||
throw ArgumentError(
|
||||
'Unable to resolve NULL driver for [${runtimeType}].');
|
||||
}
|
||||
|
||||
return _drivers.putIfAbsent(driver, () => createDriver(driver!)) as T;
|
||||
}
|
||||
|
||||
/// Create a new driver instance.
|
||||
///
|
||||
/// This method creates a new instance of the requested driver. It first checks
|
||||
/// for custom creators, then looks for a create{Driver}Driver method.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [driver]: The name of the driver to create
|
||||
///
|
||||
/// Returns:
|
||||
/// The new driver instance
|
||||
///
|
||||
/// Throws:
|
||||
/// - [ArgumentError] if the driver is not supported
|
||||
dynamic createDriver(String driver) {
|
||||
// Check for custom creator
|
||||
if (_customCreators.containsKey(driver)) {
|
||||
return _customCreators[driver]!(container);
|
||||
}
|
||||
|
||||
// Look for create{Driver}Driver method
|
||||
var methodName =
|
||||
'create${driver[0].toUpperCase()}${driver.substring(1)}Driver';
|
||||
var result = callDriverCreator(methodName);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
throw ArgumentError('Driver [$driver] not supported.');
|
||||
}
|
||||
|
||||
/// Call a driver creator method.
|
||||
///
|
||||
/// This method must be implemented by concrete managers to handle calling
|
||||
/// the appropriate creator method based on the method name.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [method]: The name of the creator method to call
|
||||
///
|
||||
/// Returns:
|
||||
/// The created driver instance, or null if the method doesn't exist
|
||||
dynamic callDriverCreator(String method);
|
||||
|
||||
/// Register a custom driver creator.
|
||||
///
|
||||
/// This method allows registering custom driver creators that will be used
|
||||
/// instead of the default creation logic.
|
||||
///
|
||||
/// Parameters:
|
||||
/// - [driver]: The name of the driver
|
||||
/// - [creator]: The function that creates the driver
|
||||
///
|
||||
/// Returns:
|
||||
/// This manager instance for method chaining
|
||||
Manager extend(String driver, dynamic Function(Container) creator) {
|
||||
_customCreators[driver] = creator;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// Get all of the created drivers.
|
||||
///
|
||||
/// Returns a map of all driver instances that have been created.
|
||||
Map<String, dynamic> getDrivers() => Map.unmodifiable(_drivers);
|
||||
|
||||
/// Get the container instance used by the manager.
|
||||
Container getContainer() => container;
|
||||
|
||||
/// Forget all of the resolved driver instances.
|
||||
///
|
||||
/// This method clears the driver cache, forcing new instances to be created
|
||||
/// on next access.
|
||||
///
|
||||
/// Returns:
|
||||
/// This manager instance for method chaining
|
||||
Manager forgetDrivers() {
|
||||
_drivers.clear();
|
||||
return this;
|
||||
}
|
||||
}
|
122
packages/support/test/manager_test.dart
Normal file
122
packages/support/test/manager_test.dart
Normal file
|
@ -0,0 +1,122 @@
|
|||
import 'package:platform_container/container.dart';
|
||||
import 'package:platform_container/mirrors.dart';
|
||||
import 'package:platform_support/src/fluent.dart';
|
||||
import 'package:platform_support/src/manager.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
// Test driver interface
|
||||
abstract class TestDriver {
|
||||
String getName();
|
||||
}
|
||||
|
||||
// Test driver implementations
|
||||
class LocalDriver implements TestDriver {
|
||||
@override
|
||||
String getName() => 'local';
|
||||
}
|
||||
|
||||
class CloudDriver implements TestDriver {
|
||||
final String region;
|
||||
CloudDriver(this.region);
|
||||
@override
|
||||
String getName() => 'cloud:$region';
|
||||
}
|
||||
|
||||
// Test manager implementation
|
||||
class TestManager extends Manager {
|
||||
TestManager(Container container) : super(container);
|
||||
|
||||
@override
|
||||
String? getDefaultDriver() {
|
||||
var attributes = config.getAttributes();
|
||||
print('Config attributes: $attributes'); // Debug print
|
||||
return config.get('test.driver');
|
||||
}
|
||||
|
||||
@override
|
||||
dynamic callDriverCreator(String method) {
|
||||
print('Creating driver with method: $method'); // Debug print
|
||||
switch (method) {
|
||||
case 'createLocalDriver':
|
||||
return LocalDriver();
|
||||
case 'createCloudDriver':
|
||||
var region = config.get('test.cloud.region', 'us-east-1');
|
||||
return CloudDriver(region);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
String getName() => driver<TestDriver>().getName();
|
||||
}
|
||||
|
||||
void main() {
|
||||
group('Manager', () {
|
||||
late Container container;
|
||||
late TestManager manager;
|
||||
|
||||
setUp(() {
|
||||
container = Container(MirrorsReflector());
|
||||
var attributes = {
|
||||
'test': {'driver': 'local'}
|
||||
}; // Nested attributes
|
||||
var config = Fluent(attributes);
|
||||
print('Setting up config with attributes: $attributes'); // Debug print
|
||||
container.registerSingleton<Fluent>(config);
|
||||
manager = TestManager(container);
|
||||
});
|
||||
|
||||
test('uses default driver when no driver specified', () {
|
||||
var driver = manager.driver<TestDriver>();
|
||||
expect(driver.getName(), equals('local'));
|
||||
});
|
||||
|
||||
test('creates driver instance', () {
|
||||
var driver = manager.driver<TestDriver>('local');
|
||||
expect(driver.getName(), equals('local'));
|
||||
});
|
||||
|
||||
test('caches driver instances', () {
|
||||
var driver1 = manager.driver<TestDriver>('local');
|
||||
var driver2 = manager.driver<TestDriver>('local');
|
||||
expect(identical(driver1, driver2), isTrue);
|
||||
});
|
||||
|
||||
test('supports custom driver creators', () {
|
||||
manager.extend('custom', (container) => CloudDriver('custom-region'));
|
||||
var driver = manager.driver<TestDriver>('custom');
|
||||
expect(driver.getName(), equals('cloud:custom-region'));
|
||||
});
|
||||
|
||||
test('throws on unsupported driver', () {
|
||||
expect(
|
||||
() => manager.driver('unsupported'), throwsA(isA<ArgumentError>()));
|
||||
});
|
||||
|
||||
test('throws on null driver with no default', () {
|
||||
// Create new container and manager for this test
|
||||
var testContainer = Container(MirrorsReflector());
|
||||
testContainer.registerSingleton<Fluent>(Fluent());
|
||||
var testManager = TestManager(testContainer);
|
||||
expect(() => testManager.driver(), throwsA(isA<ArgumentError>()));
|
||||
});
|
||||
|
||||
test('forgets cached drivers', () {
|
||||
var driver1 = manager.driver<TestDriver>('local');
|
||||
manager.forgetDrivers();
|
||||
var driver2 = manager.driver<TestDriver>('local');
|
||||
expect(identical(driver1, driver2), isFalse);
|
||||
});
|
||||
|
||||
test('returns unmodifiable driver map', () {
|
||||
manager.driver<TestDriver>('local');
|
||||
var drivers = manager.getDrivers();
|
||||
expect(() => drivers['local'] = LocalDriver(),
|
||||
throwsA(isA<UnsupportedError>()));
|
||||
});
|
||||
|
||||
test('forwards method calls to default driver', () {
|
||||
expect(manager.getName(), equals('local'));
|
||||
});
|
||||
});
|
||||
}
|
Loading…
Reference in a new issue