elif_http/controller/
factory.rs

1//! Controller factory implementation for IoC container integration
2//!
3//! Provides automatic controller instantiation with dependency injection
4//! using the new IoC container from elif-core.
5
6use async_trait::async_trait;
7use std::collections::HashMap;
8use std::sync::Arc;
9
10use crate::controller::base::ElifController;
11use crate::errors::HttpError;
12use crate::request::ElifRequest;
13use elif_core::container::{IocContainer, ScopeId};
14
15/// Trait for creating controller instances from the IoC container
16#[async_trait]
17pub trait ControllerFactory: Send + Sync {
18    /// Create a controller instance with dependencies resolved from the container
19    async fn create_controller(
20        &self,
21        container: &IocContainer,
22        scope: Option<&ScopeId>,
23    ) -> Result<Arc<dyn ElifController>, HttpError>;
24}
25
26/// Generic controller factory that uses the from_ioc_container method
27pub struct IocControllerFactory<T> {
28    _phantom: std::marker::PhantomData<T>,
29}
30
31impl<T> IocControllerFactory<T> {
32    pub fn new() -> Self {
33        Self {
34            _phantom: std::marker::PhantomData,
35        }
36    }
37}
38
39impl<T> Default for IocControllerFactory<T> {
40    fn default() -> Self {
41        Self::new()
42    }
43}
44
45#[async_trait]
46impl<T> ControllerFactory for IocControllerFactory<T>
47where
48    T: ElifController + IocControllable + 'static,
49{
50    async fn create_controller(
51        &self,
52        container: &IocContainer,
53        scope: Option<&ScopeId>,
54    ) -> Result<Arc<dyn ElifController>, HttpError> {
55        let controller =
56            T::from_ioc_container(container, scope).map_err(|e| HttpError::InternalError {
57                message: format!("Failed to create controller: {}", e),
58            })?;
59
60        Ok(Arc::new(controller))
61    }
62}
63
64/// Trait for controllers that can be created from IoC container
65pub trait IocControllable {
66    /// Create controller instance with dependencies resolved from IoC container
67    fn from_ioc_container(
68        container: &IocContainer,
69        scope: Option<&ScopeId>,
70    ) -> Result<Self, String>
71    where
72        Self: Sized;
73}
74
75/// Controller registry for managing controller factories
76pub struct ControllerRegistry {
77    factories: HashMap<String, Box<dyn ControllerFactory>>,
78    container: Arc<IocContainer>,
79}
80
81impl ControllerRegistry {
82    /// Create a new controller registry with IoC container
83    pub fn new(container: Arc<IocContainer>) -> Self {
84        Self {
85            factories: HashMap::new(),
86            container,
87        }
88    }
89
90    /// Register a controller type with automatic factory creation
91    pub fn register<T>(&mut self, name: &str) -> Result<(), HttpError>
92    where
93        T: ElifController + IocControllable + 'static,
94    {
95        let factory = Box::new(IocControllerFactory::<T>::new());
96        self.factories.insert(name.to_string(), factory);
97        Ok(())
98    }
99
100    /// Register a custom factory for a controller
101    pub fn register_factory(&mut self, name: &str, factory: Box<dyn ControllerFactory>) {
102        self.factories.insert(name.to_string(), factory);
103    }
104
105    /// Create a controller instance by name
106    pub async fn create_controller(
107        &self,
108        name: &str,
109        scope: Option<&ScopeId>,
110    ) -> Result<Arc<dyn ElifController>, HttpError> {
111        let factory = self
112            .factories
113            .get(name)
114            .ok_or_else(|| HttpError::InternalError {
115                message: format!("Controller '{}' not registered", name),
116            })?;
117
118        factory.create_controller(&self.container, scope).await
119    }
120
121    /// Create a scoped controller registry for request-specific controllers
122    pub async fn create_scoped_registry(
123        &self,
124        request: &ElifRequest,
125    ) -> Result<ScopedControllerRegistry<'_>, HttpError> {
126        let scope_id = self
127            .container
128            .create_scope()
129            .map_err(|e| HttpError::InternalError {
130                message: format!("Failed to create request scope: {}", e),
131            })?;
132
133        Ok(ScopedControllerRegistry {
134            registry: self,
135            scope_id,
136            request_context: RequestContext::from_request(request),
137        })
138    }
139
140    /// Get list of registered controller names
141    pub fn registered_controllers(&self) -> Vec<String> {
142        self.factories.keys().cloned().collect()
143    }
144}
145
146/// Scoped controller registry for request-specific dependency injection
147pub struct ScopedControllerRegistry<'a> {
148    registry: &'a ControllerRegistry,
149    scope_id: ScopeId,
150    #[allow(dead_code)]
151    request_context: RequestContext,
152}
153
154impl<'a> ScopedControllerRegistry<'a> {
155    /// Create a controller instance within this scope
156    pub async fn create_controller(
157        &self,
158        name: &str,
159    ) -> Result<Arc<dyn ElifController>, HttpError> {
160        // Register request context in scope for injection
161        // TODO: Add request context to scope once request-scoped services are implemented
162
163        self.registry
164            .create_controller(name, Some(&self.scope_id))
165            .await
166    }
167
168    /// Get the scope ID for this registry
169    pub fn scope_id(&self) -> &ScopeId {
170        &self.scope_id
171    }
172
173    /// Dispose the scope when done
174    pub async fn dispose(self) -> Result<(), HttpError> {
175        self.registry
176            .container
177            .dispose_scope(&self.scope_id)
178            .await
179            .map_err(|e| HttpError::InternalError {
180                message: format!("Failed to dispose scope: {}", e),
181            })
182    }
183}
184
185/// Request context for dependency injection
186#[derive(Clone, Debug)]
187pub struct RequestContext {
188    pub method: String,
189    pub path: String,
190    pub query_params: HashMap<String, String>,
191    pub headers: HashMap<String, String>,
192}
193
194impl RequestContext {
195    /// Create request context from ElifRequest
196    pub fn from_request(request: &ElifRequest) -> Self {
197        Self {
198            method: request.method.to_string(),
199            path: request.path().to_string(),
200            query_params: HashMap::new(), // Simplified for now
201            headers: HashMap::new(),      // Simplified for now
202        }
203    }
204}
205
206/// Builder for controller registry
207pub struct ControllerRegistryBuilder {
208    container: Option<Arc<IocContainer>>,
209    controllers: Vec<(String, Box<dyn ControllerFactory>)>,
210}
211
212impl ControllerRegistryBuilder {
213    /// Create a new builder
214    pub fn new() -> Self {
215        Self {
216            container: None,
217            controllers: Vec::new(),
218        }
219    }
220
221    /// Set the IoC container
222    pub fn container(mut self, container: Arc<IocContainer>) -> Self {
223        self.container = Some(container);
224        self
225    }
226
227    /// Register a controller type
228    pub fn register<T>(mut self, name: &str) -> Self
229    where
230        T: ElifController + IocControllable + 'static,
231    {
232        let factory = Box::new(IocControllerFactory::<T>::new());
233        self.controllers.push((name.to_string(), factory));
234        self
235    }
236
237    /// Register a custom factory
238    pub fn register_factory(mut self, name: &str, factory: Box<dyn ControllerFactory>) -> Self {
239        self.controllers.push((name.to_string(), factory));
240        self
241    }
242
243    /// Build the controller registry
244    pub fn build(self) -> Result<ControllerRegistry, HttpError> {
245        let container = self.container.ok_or_else(|| HttpError::InternalError {
246            message: "IoC container is required for controller registry".to_string(),
247        })?;
248
249        let mut registry = ControllerRegistry::new(container);
250
251        for (name, factory) in self.controllers {
252            registry.register_factory(&name, factory);
253        }
254
255        Ok(registry)
256    }
257}
258
259impl Default for ControllerRegistryBuilder {
260    fn default() -> Self {
261        Self::new()
262    }
263}
264
265/// Auto-discovery helper for controllers
266pub struct ControllerScanner;
267
268impl ControllerScanner {
269    /// Scan for controllers in a module and register them automatically
270    /// This would typically be implemented as a proc macro in a full implementation
271    pub async fn scan_and_register(
272        _registry: &mut ControllerRegistry,
273        _module_path: &str,
274    ) -> Result<usize, HttpError> {
275        // Placeholder implementation - in a real system this would use
276        // reflection or proc macros to discover controller types
277        Ok(0)
278    }
279}
280
281#[cfg(test)]
282mod tests {
283    use super::*;
284    use crate::controller::base::{ControllerRoute, ElifController};
285    use async_trait::async_trait;
286    use elif_core::ServiceBinder;
287
288    // Test controller for factory tests
289    pub struct TestController {
290        #[allow(dead_code)]
291        pub service: Arc<TestService>,
292    }
293
294    #[async_trait]
295    impl ElifController for TestController {
296        fn name(&self) -> &str {
297            "TestController"
298        }
299
300        fn base_path(&self) -> &str {
301            "/test"
302        }
303
304        fn routes(&self) -> Vec<ControllerRoute> {
305            vec![]
306        }
307
308        async fn handle_request(
309            self: Arc<Self>,
310            _method_name: String,
311            _request: ElifRequest,
312        ) -> crate::errors::HttpResult<crate::response::ElifResponse> {
313            Ok(crate::response::ElifResponse::ok().text("test"))
314        }
315    }
316
317    impl IocControllable for TestController {
318        fn from_ioc_container(
319            container: &IocContainer,
320            _scope: Option<&ScopeId>,
321        ) -> Result<Self, String> {
322            let service = container
323                .resolve::<TestService>()
324                .map_err(|e| format!("Failed to resolve TestService: {}", e))?;
325
326            Ok(Self { service })
327        }
328    }
329
330    // Test service
331    #[derive(Default)]
332    pub struct TestService {
333        #[allow(dead_code)]
334        pub name: String,
335    }
336
337    unsafe impl Send for TestService {}
338    unsafe impl Sync for TestService {}
339
340    #[tokio::test]
341    async fn test_controller_factory_creation() {
342        let mut container = IocContainer::new();
343        container.bind::<TestService, TestService>();
344        container.build().expect("Container build failed");
345
346        let container_arc = Arc::new(container);
347        let mut registry = ControllerRegistry::new(container_arc);
348
349        registry
350            .register::<TestController>("test")
351            .expect("Failed to register controller");
352
353        let controller = registry
354            .create_controller("test", None)
355            .await
356            .expect("Failed to create controller");
357
358        assert_eq!(controller.name(), "TestController");
359    }
360}