add: adding support manager

This commit is contained in:
Patrick Stewart 2024-12-30 02:26:25 -07:00
parent 9dc7b8940a
commit 85a4517440
2 changed files with 258 additions and 0 deletions

View 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;
}
}

View 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'));
});
});
}