# Container Migration Guide ## Overview This guide helps you migrate from the current Container implementation to the new Laravel-compatible version. It covers: 1. Breaking changes 2. New features 3. Migration strategies 4. Code examples 5. Best practices ## Breaking Changes ### 1. Binding Registration #### Old Way ```dart // Old implementation container.bind(instance); container.singleton(instance); ``` #### New Way ```dart // New implementation container.bind((c) => instance); container.singleton((c) => instance); // With contextual binding container.when(UserController) .needs() .give((c) => SpecialService()); ``` ### 2. Service Resolution #### Old Way ```dart // Old implementation var service = container.make(); var namedService = container.makeNamed('name'); ``` #### New Way ```dart // New implementation var service = container.make(); var contextualService = container.make(context: UserController); var taggedServices = container.taggedAs('tag'); ``` ### 3. Method Injection #### Old Way ```dart // Old implementation - manual parameter resolution class UserService { void process(User user) { var logger = container.make(); var validator = container.make(); // Process user... } } ``` #### New Way ```dart // New implementation - automatic method injection class UserService { void process( User user, Logger logger, // Automatically injected Validator validator // Automatically injected ) { // Process user... } } // Usage container.call(userService, 'process', {'user': user}); ``` ## New Features ### 1. Contextual Binding ```dart // Register different implementations based on context void setupBindings(Container container) { // Default storage container.bind((c) => LocalStorage()); // User uploads use cloud storage container.when(UserUploadController) .needs() .give((c) => CloudStorage()); // System files use local storage container.when(SystemFileController) .needs() .give((c) => LocalStorage()); } ``` ### 2. Tagged Bindings ```dart // Register and tag related services void setupReportServices(Container container) { // Register services container.bind((c) => PerformanceReport()); container.bind((c) => FinancialReport()); container.bind((c) => UserReport()); // Tag them for easy retrieval container.tag([ PerformanceReport, FinancialReport, UserReport ], 'reports'); // Additional categorization container.tag([PerformanceReport], 'metrics'); container.tag([FinancialReport], 'financial'); } // Usage var reports = container.taggedAs('reports'); var metricReports = container.taggedAs('metrics'); ``` ### 3. Method Injection ```dart class ReportGenerator { void generateReport( Report report, Logger logger, // Automatically injected Formatter formatter, // Automatically injected {required DateTime date} // Manually provided ) { logger.info('Generating report...'); var data = report.getData(); var formatted = formatter.format(data); // Generate report... } } // Usage container.call( generator, 'generateReport', {'report': report, 'date': DateTime.now()} ); ``` ## Migration Strategies ### 1. Gradual Migration ```dart // Step 1: Update bindings class ServiceRegistry { void register(Container container) { // Old way (still works) container.bind(OldService()); // New way container.bind((c) => NewService()); // Add contextual bindings container.when(NewController) .needs() .give((c) => NewService()); } } // Step 2: Update resolution class ServiceConsumer { void process() { // Old way (still works) var oldService = container.make(); // New way var newService = container.make(); var contextual = container.make( context: NewController ); } } // Step 3: Add method injection class ServiceProcessor { // Old way void processOld(Data data) { var service = container.make(); service.process(data); } // New way void processNew( Data data, Service service // Injected automatically ) { service.process(data); } } ``` ### 2. Feature-by-Feature Migration 1. **Update Bindings First** ```dart // Update all bindings to new style void registerBindings(Container container) { // Update simple bindings container.bind((c) => ServiceImpl()); // Add contextual bindings container.when(Controller) .needs() .give((c) => SpecialService()); } ``` 2. **Add Tagged Services** ```dart // Group related services void registerServices(Container container) { // Register services container.bind((c) => ServiceA()); container.bind((c) => ServiceB()); // Add tags container.tag([ServiceA, ServiceB], 'services'); } ``` 3. **Implement Method Injection** ```dart // Convert to method injection class UserController { // Before void oldProcess(User user) { var validator = container.make(); var logger = container.make(); // Process... } // After void newProcess( User user, Validator validator, Logger logger ) { // Process... } } ``` ## Testing During Migration ### 1. Verify Bindings ```dart void main() { group('Container Migration Tests', () { late Container container; setUp(() { container = Container(); registerBindings(container); }); test('should support old-style bindings', () { var oldService = container.make(); expect(oldService, isNotNull); }); test('should support new-style bindings', () { var newService = container.make(); expect(newService, isNotNull); }); test('should resolve contextual bindings', () { var service = container.make( context: Controller ); expect(service, isA()); }); }); } ``` ### 2. Verify Tagged Services ```dart void main() { group('Tagged Services Tests', () { late Container container; setUp(() { container = Container(); registerServices(container); }); test('should resolve tagged services', () { var services = container.taggedAs('services'); expect(services, hasLength(2)); expect(services, contains(isA())); expect(services, contains(isA())); }); }); } ``` ### 3. Verify Method Injection ```dart void main() { group('Method Injection Tests', () { late Container container; setUp(() { container = Container(); registerServices(container); }); test('should inject method dependencies', () { var controller = UserController(); // Call with only required parameters container.call( controller, 'newProcess', {'user': testUser} ); // Verify injection worked verify(() => mockValidator.validate(any)).called(1); verify(() => mockLogger.log(any)).called(1); }); }); } ``` ## Best Practices 1. **Update Bindings Consistently** ```dart // Good: Consistent new style container.bind((c) => ServiceImpl()); container.singleton((c) => FileLogger()); // Bad: Mixed styles container.bind(ServiceImpl()); // Old style container.singleton((c) => FileLogger()); // New style ``` 2. **Use Contextual Bindings Appropriately** ```dart // Good: Clear context and purpose container.when(UserController) .needs() .give((c) => UserStorage()); // Bad: Unclear or overly broad context container.when(Object) .needs() .give((c) => GenericStorage()); ``` 3. **Organize Tagged Services** ```dart // Good: Logical grouping container.tag([ PerformanceReport, SystemReport ], 'system-reports'); container.tag([ UserReport, ActivityReport ], 'user-reports'); // Bad: Mixed concerns container.tag([ PerformanceReport, UserReport, Logger, Storage ], 'services'); ``` ## Common Issues and Solutions 1. **Binding Resolution Errors** ```dart // Problem: Missing binding var service = container.make(); // Throws error // Solution: Register binding first container.bind((c) => ServiceImpl()); var service = container.make(); // Works ``` 2. **Contextual Binding Conflicts** ```dart // Problem: Multiple contexts container.when(Controller) .needs() .give((c) => ServiceA()); container.when(Controller) // Conflict! .needs() .give((c) => ServiceB()); // Solution: Use specific contexts container.when(UserController) .needs() .give((c) => ServiceA()); container.when(AdminController) .needs() .give((c) => ServiceB()); ``` 3. **Method Injection Failures** ```dart // Problem: Unresolvable parameter void process( CustomType param // Not registered with container ) { } // Solution: Register or provide parameter container.bind((c) => CustomType()); // or container.call(instance, 'process', { 'param': customInstance }); ``` ## Next Steps 1. Audit existing container usage 2. Plan migration phases 3. Update bindings 4. Add new features 5. Update tests 6. Document changes Would you like me to create detailed specifications for any of these next steps?