1 /**
2  * Модуль предоставляет объекты и методы для работы с именованным внедрением зависимостей (DI)
3  *
4  * Copyright: (c) 2015-2017, Milofon Project.
5  * License: Subject to the terms of the BSD license, as written in the included LICENSE.txt file.
6  * Authors: Maksim Galanin
7  */
8 module dango.system.container.named;
9 
10 private
11 {
12    import poodinis;
13 }
14 
15 /**
16  * Контейнер для управления именованных зависимостей
17  *
18  * При помощи данного контейнера можно зарегистрировать именованную зависимось определенного типа.
19  * Имена уникальны в рамках одного типа
20  */
21 class NamedContainer
22 {
23     private Registration[string][TypeInfo] registrations;
24 
25     /**
26      * Регистрация зависимости
27      *
28      * Params:
29      *
30      * reg   = Объект регистрации типа
31      * name  = Имя (метка) типа
32      */
33     void register(Registration reg, string name)
34     {
35         registrations[reg.registeredType][name] = reg;
36     }
37 
38     /**
39      * Получение объекта из именованного контейнера по имени
40      *
41      * Метод не учитывает опции, которые есть в оригинальном методе DependencyContainer
42      *
43      * Params:
44      *
45      * name = Имя требуемой зависимости
46      *
47      * See_Also: poodinis.container: DependencyContainer
48      */
49     RegistrationType resolve(RegistrationType)(string name)
50     {
51         TypeInfo resolveType = typeid(RegistrationType);
52 
53         auto candidates = resolveType in registrations;
54         if (!candidates)
55             throw new ResolveException("Type not registered.", resolveType);
56 
57         if (auto r = name in *candidates)
58         {
59             auto autowireContext = new AutowireInstantiationContext();
60             autowireContext.autowireInstance = true;
61             return cast(RegistrationType)(*r).getInstance(autowireContext);
62         }
63 
64         return null;
65     }
66 }
67 
68 
69 /**
70  * Метод расширяет поведение DependencyContainer при помощи NamedContainer и добавляет возможность регистрировать именованные зависимости
71  *
72  * Params:
73  *
74  * container = Контейнер управляющий зависимостями
75  * name      = Имя(метка) типа
76  * options   = Опции для регистрации зависимости
77  *
78  * Returns: Объект регистрации
79  */
80 Registration registerByName(SuperType, ConcreteType: SuperType)(shared(DependencyContainer) container, string name, RegistrationOption options = RegistrationOption.none)
81 {
82     NamedContainer nc = container.resolve!NamedContainer(ResolveOption.registerBeforeResolving);
83     Registration reg = container.register!(SuperType, ConcreteType)(options);
84     nc.register(reg, name);
85     return reg;
86 }
87 
88 
89 /**
90  * Метод расширяет поведение DependencyContainer при помощи NamedContainer и добавляет возможность создать объект указав тип помеченный именем
91  *
92  * Params:
93  *
94  * container = Контейнер зависимостей
95  * name      = Имя(метка) типа
96  *
97  * Returns: Объект зарегистрированного типа
98  */
99 RegistrationType resolveByName(RegistrationType)(shared(DependencyContainer) container, string name)
100 {
101     NamedContainer nc = container.resolve!NamedContainer(ResolveOption.registerBeforeResolving);
102     return nc.resolve!RegistrationType(name);
103 }
104 
105 
106 /**
107  * Метод расширяет поведение DependencyContainer при помощи NamedContainer и добавляет возможность создать объект указав тип помеченный именем
108  *
109  * Params:
110  *
111  * container = Контейнер зависимостей
112  * name      = Имя(метка) типа
113  *
114  * Returns: Объект требуемого типа
115  */
116 QualifierType resolveByName(RegistrationType, QualifierType : RegistrationType)(shared(DependencyContainer) container, string name)
117 {
118     return cast(QualifierType) resolveByName!RegistrationType(container, name);
119 }
120