configuration.doxy
1 /*!
2 \page configuration Configuration
3 <div class="has-toc"></div>
4 
5 # Configuration # {#conf_main}
6 
7 Application configuration is handled by implementations of
8 \link wcmf::lib::config::Configuration `Configuration`\endlink. To use the configuration
9 throughout the application, an instance of the appropriate implementation is
10 passed to \link wcmf::lib::core::ObjectFactory `ObjectFactory`\endlink.
11 
12 The following code demonstrates how to set up and use the
13 \link wcmf::lib::config::impl::InifileConfiguration `InifileConfiguration`\endlink
14 configuration in code:
15 
16 ~~~~~~~~~~~~~{.php}
17 $configPath = WCMF_BASE.'app/config/';
18 
19 // setup configuration
20 $configuration = new InifileConfiguration($configPath);
21 $configuration->addConfiguration('config.ini');
22 
23 // register with object factory
24 ObjectFactory::registerInstance('configuration', $configuration);
25 
26 // get a configuration value
27 $configuration = ObjectFactory::getInstance('configuration');
28 $tz = $configuration->getValue('timezone', 'application');
29 ~~~~~~~~~~~~~
30 
31 ## Configuration Format ## {#conf_format}
32 
33 Currently wCMF provides an implementation for using the
34 [INI file](http://en.wikipedia.org/wiki/INI_file) format.
35 \link wcmf::lib::config::impl::InifileConfiguration `InifileConfiguration`\endlink
36 handles ini files that consist of __key-value pairs__ that are grouped in __sections__:
37 
38 ~~~~~~~~~~~~~{.ini}
39 [SectionA]
40 key1 = value1
41 key2 = value2
42 
43 [SectionB]
44 key3 = value3
45 ~~~~~~~~~~~~~
46 
47 Additionally it defines __array values__ (enclosed in curly braces) and __inclusion__
48 of additional files. Included files are defined in the `include` key of the `Config`
49 section. Keys in the current file override keys from included files.
50 
51 The following example shows how to include an array of additional configuration
52 files to separate concerns:
53 
54 ~~~~~~~~~~~~~{.ini}
55 [Config]
56 include = {server.ini, persistence.ini, presentation.ini, security.ini}
57 ~~~~~~~~~~~~~
58 
59 @note While path values in the configuration are normally resolved relative to the
60 value of the `WCMF_BASE` constant, the included files are expected to be located
61 in the directory that is passed to the constructor of
62 \link wcmf::lib::config::impl::InifileConfiguration `InifileConfiguration`\endlink.
63 
64 The possibility to include configuration files into others is useful, if you want
65 to __separate varying parts__ from static ones to simplify the deployment process.
66 In the \ref app "default application" for example all server specific configuration
67 (e.g. database connection) are separated into a file called _server.ini_.
68 
69 @note Configuration section and key names are treated case-insensitive.
70 
71 ## Dependency injection ## {#conf_di}
72 
73 wCMF supports [Dependency injection](http://en.wikipedia.org/wiki/Dependency_injection)
74 through \link wcmf::lib::core::Factory `ObjectFactory`\endlink and it's
75 \link wcmf::lib::core::impl::DefaultFactory `DefaultFactory`\endlink implementation.
76 This class implements _constructor_ and _setter injection_, which means that dependencies
77 are either set through the _constructor_ or a _setter method_ of the client class
78 or a _public member variable_.
79 
80 Assembly details for client instances are defined in the application configuration
81 in special sections containing a `__class` key. The value of the key denotes the
82 class to be used to create the client instance. All other keys are tried to be
83 mapped to constructor parameters or setters/members of that class. Complex
84 dependencies of an instance may be set by using the `$` notation, which refers
85 to another configuration section. If a section does not contain a `__class` key
86 it is instantiated as an associative array.
87 
88 The following example demonstrates the pattern by means of the
89 \link wcmf::lib::persistence::PersistenceFacade `PersistenceFacade`\endlink instance:
90 
91 ~~~~~~~~~~~~~{.ini}
92 [PersistenceFacade]
93 __class = wcmf\lib\persistence\impl\DefaultPersistenceFacade
94 mappers = $typeMapping
95 logStrategy = $auditingLogStragegy
96 
97 [AuditingLogStragegy]
98 __class = wcmf\lib\persistence\output\impl\AuditingOutputStrategy
99 
100 [TypeMapping]
101 app.src.model.wcmf.DBSequence = $app_src_model_wcmf_DBSequenceRDBMapper
102 app.src.model.wcmf.Lock = $app_src_model_wcmf_LockRDBMapper
103 
104 [app_src_model_wcmf_DBSequenceRDBMapper]
105 __class = app\src\model\wcmf\DBSequenceRDBMapper
106 connectionParams = $database
107 
108 [app_src_model_wcmf_LockRDBMapper]
109 __class = app\src\model\wcmf\LockRDBMapper
110 connectionParams = $database
111 
112 [Database]
113 dbType = sqlite
114 dbHostName = 127.0.0.1
115 dbName = app/test-db.sq3
116 dbUserName =
117 dbPassword =
118 dbCharSet = utf8
119 
120 [EventManager]
121 __class = wcmf\lib\core\impl\DefaultEventManager
122 ~~~~~~~~~~~~~
123 
124 The first section defines that the instance named _PersistenceFacade_ is an object of
125 the class \link wcmf::lib::persistence::impl::DefaultPersistenceFacade `DefaultPersistenceFacade`\endlink.
126 
127 So let's have a look at the relevant code in
128 \link wcmf::lib::persistence::impl::DefaultPersistenceFacade `DefaultPersistenceFacade`\endlink:
129 
130 ~~~~~~~~~~~~~{.php}
131 class DefaultPersistenceFacade implements PersistenceFacade {
132 
133  public function __construct(EventManager $eventManager,
134  OutputStrategy $logStrategy) {
135  ...
136  }
137 
138  public function setMappers($mappers) {
139  ...
140  }
141 }
142 ~~~~~~~~~~~~~
143 
144 When requested the first time, the _PersistenceFacade_ instance is created in
145 the following steps:
146 
147 1. _Constructor parameters_:
148  - <em>$eventManager</em> is not explicitly defined in the instance configuration,
149  so the factory looks it up in the configuration. Since there is a `EventManager`
150  section, it uses it to create an instance of
151  \link wcmf::lib::core::impl::DefaultEventManager `DefaultEventManager`\endlink
152  and injects it into the constructor. If there would be no section with
153  this name, the factory would use the _type hint_ and search for a class
154  called `EventManager`.
155  - <em>$logStrategy</em> is explicitly defined as an instance of
156  \link wcmf::lib::persistence::output::impl::AuditingOutputStrategy `AuditingOutputStrategy`\endlink.
157  This is an example of a complex dependency that is defined in another
158  configuration section.
159 2. _Setter injection of the remaining parameters_:
160  - The _mappers_ configuration parameter is not used in the constructor.
161  The factory searches for a _setter method_ (_setMappers_) or a public member
162  variable (<em>$mappers</em>). Since the class defines a setter method, it is used
163  to inject the dependency. The `TypeMapping` section does not contain a
164  `__class` key, which means that the _mappers_ property will be an associative
165  array. In this example it maps class names (e.g. _app.src.model.wcmf.DBSequence_)
166  to mapper instances (e.g. `DBSequenceRDBMapper`). Further sections show that
167  the _connectionParams_ property of the `DBSequenceRDBMapper` instance is set
168  to an associative array describing the database connection (section `Database`).
169 
170 The \link wcmf::lib::persistence::PersistenceFacade `PersistenceFacade`\endlink
171 instance can be retrieved by using the following code:
172 
173 ~~~~~~~~~~~~~{.php}
174 $persistenceFacade = ObjectFactory::getInstance('persistenceFacade');
175 ~~~~~~~~~~~~~
176 
177 ### Shared and Non-Shared instances ### {#conf_shareddi}
178 
179 By default all instances created by \link wcmf::lib::core::ObjectFactory `ObjectFactory`\endlink
180 are _shared_ instances, which means, that they will be created on the first call
181 and only returned by succeeding calls. If you want to create a _non-shared_ instance,
182 you must use the `__shared` key in the configuration and set it to _false_.
183 
184 The following example shows the configuration of a non-shared
185 \link wcmf::lib::presentation::view::View `View`\endlink instance:
186 
187 ~~~~~~~~~~~~~{.ini}
188 [View]
189 __class = wcmf\lib\presentation\view\impl\SmartyView
190 __shared = false
191 compileCheck = true
192 caching = false
193 cacheLifetime = 3600
194 cacheDir = app/cache/smarty/
195 ~~~~~~~~~~~~~
196 
197 ### Circular dependencies ### {#conf_circulardi}
198 
199 Since \link wcmf::lib::core::impl::DefaultFactory `DefaultFactory`\endlink tries
200 to resolve all dependencies when constructing an instance, it might happen that
201 a dependency depends on the instance being currently constructed. This is called
202 a _circular dependency_ and would cause infinite recursion. To solve this problem
203 the dependency in question _must not_ be injected in the constructor, but in a
204 setter method or member variable. This allows the factory to construct the initial
205 instance first without requiring the child dependency. It is then available
206 when constructing the child dependency.
207 
208 ## Configuration for individual users ## {#conf_peruser}
209 
210 wCMF's user base class \link wcmf::lib::security::principal::impl::AbstractUser `AbstractUser`\endlink
211 has a persistent property `config` which may be used to set a individual configuration
212 for a user. This will be loaded after the standard configuration and extends its settings.
213 If two keys have the same name the one from the user configuration overwrites the standard one.
214 Using the `RoleConfig` configuration section, you can easily assign configuration files
215 to groups:
216 
217 ~~~~~~~~~~~~~{.ini}
218 [RoleConfig]
219 administrators = admin.ini
220 ~~~~~~~~~~~~~
221 
222 If a user is added to a listed role, the given configuration file will be automatically
223 assigned to it, if no individual configuration is set yet.
224 
225 ## Default application configuration ## {#conf_default_app}
226 
227 The \ref app "default application" uses some special configuration sections:
228 
229 ~~~~~~~~~~~~~{.ini}
230 [Application]
231 title = WCMF TEST MODEL
232 color = #428BCA
233 rootTypes = {Author, Book, Publisher}
234 timezone = Europe/Berlin
235 listeners = {Search, EventListener}
236 
237 [Media]
238 uploadDir = app/public/media/
239 ~~~~~~~~~~~~~
240 
241 - `Application`
242  - `title` Application title
243  - `color` Color to be used in the header of the login screen
244  - `rootTypes` List of entity types to create tabs for
245  - `timezone` Application timezone
246  - `listeners` List of listeners to install (see \ref pres_listeners)
247 
248 - `Media`
249  - `uploadDir` Directory, to which media files should be uploaded
250 
251 ## Logging configuration ## {#conf_logging}
252 
253 Since logging is potentially required right from application startup, it is
254 usually the first service to set up - even before setting up the application
255 configuration. This implies that logging should not depend on other services,
256 especially not on the application configuration.
257 
258 wCMF provides integrations for [log4php](http://logging.apache.org/log4php/)
259 and [Monolog](https://github.com/Seldaek/monolog) through implementations
260 of the \link wcmf::lib::core::Logger `Logger`\endlink interface. The concrete
261 classes are configured using a configuration file, that is passed to the constructor.
262 An instance of the concrete class is then passed to the
263 \link wcmf::lib::core::LogManager::configure `LogManager::configure`\endlink
264 method.
265 
266 ### Monolog ### {#conf_monolog}
267 
268 To use the _log4php_ library, instantiate
269 \link wcmf::lib::core::impl::MonologFileLogger `MonologFileLogger`\endlink in the
270 following way:
271 
272 ~~~~~~~~~~~~~{.php}
273 $logger = new MonologFileLogger('main', WCMF_BASE.'app/config/log.ini');
274 LogManager::configure($logger);
275 ~~~~~~~~~~~~~
276 
277 \link wcmf::lib::core::impl::MonologFileLogger `MonologFileLogger`\endlink is
278 a simple wrapper class that allows logging to files or streams. The configuration is defined
279 in the [INI file](http://en.wikipedia.org/wiki/INI_file) format using the following
280 sections and keys:
281 
282 - `Root` section defines properties valid for all loggers unless otherwise stated
283  - `level` The default log level
284  - `target` The logging target. This could be either a
285  - _directory_ (e.g. _app/log/_) for daily rotating log files or a
286  - _stream_ (e.g. _php://output_) for logging to a stream
287 - `Logger` section defines log levels for individual loggers
288  - _logger name_ (e.g. <em>wcmf\\lib\\presentation\\Application</em>) is used as
289  key and the log level (e.g. `DEBUG`) as value
290 
291 Since in wCMF each class uses it's own logger named after the class name, setting
292 up the log level for individual classes is straightforward.
293 
294 The following configuration sets the default log level to `ERROR` and the
295 log level for the
296 \link wcmf::lib::presentation::Controller `Controller`\endlink class to `DEBUG`:
297 
298 ~~~~~~~~~~~~~{.ini}
299 [Root]
300 level = ERROR
301 target = app/log/
302 
303 [Logger]
304 wcmf\lib\presentation\Controller = DEBUG
305 ~~~~~~~~~~~~~
306 
307 ### log4php ### {#conf_log4php}
308 
309 To use the _log4php_ library, instantiate
310 \link wcmf::lib::core::impl::Log4phpLogger `Log4phpLogger`\endlink in the following
311 way:
312 
313 ~~~~~~~~~~~~~{.php}
314 $logger = new Log4phpLogger('main', WCMF_BASE.'app/config/log4php.php');
315 LogManager::configure($logger);
316 ~~~~~~~~~~~~~
317 
318 The configuration file _log4php.php_ uses log4php's
319 [PHP configuration format](https://logging.apache.org/log4php/docs/configuration.html#PHP).
320 
321 The following configuration sets the default log level to `ERROR` and the
322 log level for the
323 \link wcmf::lib::presentation::Controller `Controller`\endlink class to `DEBUG`:
324 
325 ~~~~~~~~~~~~~{.php}
326 return array(
327  'rootLogger' => array(
328  'level' => 'ERROR',
329  'appenders' => array('dailyFile', 'echo'),
330  ),
331 
332  'loggers' => array(
333  'wcmf.lib.presentation.Controller' => array('level' => 'DEBUG', 'appenders' => array('dailyFile')),
334  ),
335 
336  ...
337 );
338 ~~~~~~~~~~~~~
339 */