Provider Plugin Pattern
When to Use
✅ No existing plugin ecosystem for your service category ✅ Need service abstraction across diverse external providers ✅ Want cross-cutting infrastructure (proxy, events, caching) ✅ Provider-agnostic consumers that work with any implementation ✅ External API integrations with similar but different interfaces ✅ User choice between multiple service providers
Decision
| Situation | Choose | Why |
|---|---|---|
| No existing plugin ecosystem for service category | Provider Plugin | Create standardized abstraction from scratch |
| Need service abstraction across providers | Provider Plugin | Consistent interfaces for diverse implementations |
| Want cross-cutting infrastructure | Provider Plugin | Proxy, events, caching, monitoring in main module |
| Provider-agnostic consumers | Provider Plugin | Consumers work with any implementation |
| External API integrations | Provider Plugin | Standardize different external service interfaces |
| User choice between providers | Provider Plugin | Configuration-driven provider selection |
| REST API-first external integration | Service Collector | Built-in REST endpoints, minimal overhead |
Architecture Overview
Main Module creates provider abstraction: - Single plugin manager for provider plugins - Standardized interfaces across all providers - Cross-cutting infrastructure (proxy, events, caching) - Consumer services that work with any provider
Provider Modules implement specific services: - Focus on service-specific optimization - Implement standard provider interface - No infrastructure concerns (handled by main module) - Can be contributed separately by different maintainers
Pattern
Pattern Reference: /web/modules/contrib/ai/ (main module)
Provider Reference: /web/modules/contrib/ai_provider_openai/ (a provider implementation). Providers are not submodules of ai; each ships as its own contrib project — ai_provider_openai, ai_provider_amazeeio and the rest — so ai/modules/ holds consumers such as ai_assistant_api and ai_automators, never providers.
Key Interfaces:
- /web/modules/contrib/ai/src/AiProviderInterface.php
- /web/modules/contrib/ai/src/OperationType/ (operation-specific interfaces)
Plugin Manager:
- /web/modules/contrib/ai/src/AiProviderPluginManager.php
Service Proxy Pattern: - Reference: AI module's provider proxy implementation - Features: Event dispatching, error handling, retry logic
Data Transfer Objects:
// Pattern reference from AI module structure
// Input/Output objects for standardized data exchange
Service Registration:
# Provider pattern service definition
services:
my_module.service_provider:
class: Drupal\my_module\ServiceProviderPluginManager
parent: default_plugin_manager
arguments: ['@service_container']
Critical Pattern Elements
- Standardized Provider Interface - All providers implement same contract
- Service Proxy - Wraps provider execution with events, logging, retry
- DTOs for Data Exchange - Input/Output objects abstract data structures
- Capability-Based Discovery -
getProvidersByCapability()method - Default Provider Configuration - Per-operation-type defaults
Common Mistakes
- Wrong: Creating provider plugin when Foundation+Extension exists → Right: Extend mature ecosystem (e.g., Commerce Payment)
- Wrong: No service proxy layer → Right: Implement proxy for events, error handling, retry logic
- Wrong: Direct provider implementation in consumers → Right: Consumers use provider-agnostic service interface
- Wrong: Provider-specific DTOs → Right: Standardized Input/Output objects across all providers
See Also
- Foundation + Extension Pattern
- Service Collector Pattern
- Service Integration Patterns
- Reference:
/web/modules/contrib/ai/(main module) - Reference:
/web/modules/contrib/ai/src/AiProviderInterface.php - Reference:
/web/modules/contrib/ai/src/OperationType/(operation-specific interfaces) - Reference:
/web/modules/contrib/ai/src/AiProviderPluginManager.php - Reference: Drupal Plugin API
- Reference: Services and Dependency Injection