presentation.doxy
1 /*!
2 \page presentation Presentation
3 <div class="has-toc"></div>
4 
5 # Presentation # {#pres_main}
6 
7 Presentation refers to the part of the application that is visible to the user -
8 the _user interface_ - and the handling of user interaction.
9 
10 ## Services ## {#pres_services}
11 
12 The presentation layer usually depends on underlying services like persistency,
13 event handling, caching - just to name a few. These services typically exist as
14 one instance that is created on application startup and is used throughout the
15 whole application lifetime.
16 
17 The preferred way to get access to a service instance in client code is to set
18 the dependency explicitly or let it be injected, if the instance is not created
19 explicitly (see \ref conf_di). But there are also situations where this is not
20 possible (e.g. a global function that is used by third party code). Since most
21 of these services are registered with
22 \link wcmf::lib::core::ObjectFactory `ObjectFactory`\endlink, it's
23 \link wcmf::lib::core::ObjectFactory::getInstance `getInstance`\endlink method
24 may be used as a [service locator](https://en.wikipedia.org/wiki/Service_locator_pattern).
25 
26 The following example shows how to get the persistence service at any code location:
27 
28 ~~~~~~~~~~~~~{.php}
29 $persistenceFacade = ObjectFactory::getInstance('persistenceFacade');
30 ~~~~~~~~~~~~~
31 
32 ## Application ## {#pres_application}
33 
34 Web applications typically implement a _request-response pattern_, where a
35 client sends a
36 ([HTTP](http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol)-)request to the
37 application, which returns a response after processing it. wCMF encapsulates the
38 described procedure inside the
39 \link wcmf::lib::presentation::Application `Application`\endlink class. The
40 following code demonstrates the usage of this class in the main entry script of
41 the \ref app "default application".
42 
43 ~~~~~~~~~~~~~{.php}
44 $application = new Application();
45 try {
46  // initialize the application
47  $request = $application->initialize('', '', 'cms');
48 
49  // run the application
50  $response = $application->run($request);
51 }
52 catch (Exception $ex) {
53  try {
54  $application->handleException($ex, isset($request) ? $request : null);
55  }
56  catch (Exception $unhandledEx) {
57  echo("An unhandled exception occured. Please see log file for details.");
58  }
59 }
60 ~~~~~~~~~~~~~
61 
62 The example shows the three important methods of the
63 \link wcmf::lib::presentation::Application `Application`\endlink class:
64 
65 - The \link wcmf::lib::presentation::Application::initialize `initialize`\endlink
66  method is used to __setup__ the
67  \link wcmf::lib::presentation::Application `Application`\endlink. It returns a
68  \link wcmf::lib::presentation::Request `Request`\endlink instance, that may be
69  modified before execution.
70 - The \link wcmf::lib::presentation::Application::run `run`\endlink method is
71  called to __execute__ the given request. The method returns a
72  \link wcmf::lib::presentation::Response `Response`\endlink instance, that is not
73  used in this example.
74 - The \link wcmf::lib::presentation::Application::handleException `handleException`\endlink
75  method is called, if an __exception__ occurs. The method rolls back the database
76  transaction and calls the _failure_ action.
77 
78 The details of request execution are the topic of the next section.
79 
80 ## Request processing ## {#pres_request}
81 
82 The \link wcmf::lib::presentation::Request `Request`\endlink instance created
83 on initialization of the application provides all information about the incoming
84 HTTP request, that is necessary for execution. Upon execution, the following
85 actions are performed:
86 
87 1. The \link wcmf::lib::presentation::Request `Request`\endlink instance is passed
88  to \link wcmf::lib::presentation::ActionMapper `ActionMapper`\endlink for further
89  processing.
90 2. The \ref arch_actionkey is determined from the request parameters.
91 3. \link wcmf::lib::security::PermissionManager `PermissionManager`\endlink is
92  asked to authorize the action key for the current user (see \ref sec_perm_check).
93 4. If authorization is successful, the request data is transformed into the internal
94  application format (see \ref pres_format).
95 5. The \link wcmf::lib::presentation::Controller `Controller`\endlink instance
96  matching the request is determined (see \ref pres_routing) and executed.
97 6. The \link wcmf::lib::presentation::Response `Response`\endlink instance is
98  obtained after execution.
99 7. The response data is transformed into the requested response format (see
100  \ref pres_format).
101 8. Execution returns to step 3, if a valid action key is contained in the response
102  data and terminates, if no action key is found or the response is finalized
103  by calling the method
104  \link wcmf::lib::presentation::Response::setFinal `Response::setFinal`\endlink.
105 
106 ### Formats ### {#pres_format}
107 
108 wCMF is designed to be able to consume various request formats and produce
109 several response formats. While some clients communicate using
110 [JSON](http://en.wikipedia.org/wiki/JSON) format, others might prefer to encode
111 data in [XML](http://en.wikipedia.org/wiki/XML).
112 \link wcmf::lib::presentation::format::Formatter `Formatter`\endlink
113 is used to determine the required format and delegate the actual formatting to
114 the correct \link wcmf::lib::presentation::format::Format `Format`\endlink
115 implementation. wCMF currently provides the following __implementations__:
116 
117 - \link wcmf::lib::presentation::format::impl::HtmlFormat `HtmlFormat`\endlink
118  expects all data to be sent as key-value-pairs. Object data are transferred in
119  parameters named `value-`<em>name-oid</em> (e.g. `value-title-Book:3`).
120  Responses in this format are rendered as HTML views (see \ref pres_views).
121 - \link wcmf::lib::presentation::format::impl::JsonFormat `JsonFormat`\endlink
122  handles JSON encoded request data and encodes response data into the same format.
123 - \link wcmf::lib::presentation::format::impl::SoapFormat `SoapFormat`\endlink
124  is used together with the [NuSOAP](http://sourceforge.net/projects/nusoap/)
125  library to implement a SOAP interface.
126 - \link wcmf::lib::presentation::format::impl::NullFormat `NullFormat`\endlink
127  is used internally, if no formatting is required, e.g. if one controller calls
128  another controller.
129 
130 If not explicitely set, the request and response format is automatically
131 determined from the __HTTP headers__ sent with the request:
132 
133 - The `Content-Type` header defines the __request__ format
134 - The `Accept` header defines the __response__ format
135 
136 To find the correct format, the
137 [Media Type](https://www.iana.org/assignments/media-types/media-types.xhtml)
138 value set in those headers is matched against the mime type of all registered
139 formats (see
140 \link wcmf::lib::presentation::format::Format::getMimeType `Format::getMimeType`\endlink).
141 
142 Formats are defined in the `Formats` configuration section as shown in the following
143 example:
144 
145 ~~~~~~~~~~~~~{.ini}
146 [Formats]
147 html = $htmlFormat
148 null = $nullFormat
149 
150 [HtmlFormat]
151 __class = wcmf\lib\presentation\format\impl\HtmlFormat
152 
153 [NullFormat]
154 __class = wcmf\lib\presentation\format\impl\NullFormat
155 ~~~~~~~~~~~~~
156 
157 ### Routing ### {#pres_routing}
158 
159 Routing is the process of selecting the correct
160 \link wcmf::lib::presentation::Controller `Controller`\endlink for a given request.
161 wCMF distinguishes between _internal_ and _external_ routing.
162 
163 #### Internal routing #### {#pres_routingint}
164 
165 Internal routing takes place after the \link wcmf::lib::presentation::Request `Request`\endlink
166 instance is created and initialized. wCMF inspects the __action key__ formed from
167 it's _sender_, _context_ and _action_ parameters (see \ref arch_actionkey) to
168 determine the controller to be executed for the request. The mapping of action
169 keys to controllers is defined in the `ActionMapping` configuration section.
170 
171 If the executed controller together with the _context_ and _action_ parameters of
172 the response match another action key, the corresponding controller
173 will be executed afterwards. This allows to chain several actions together. If no
174 matching action key is found, the response is returned to the client.
175 
176 The following code is taken from the \ref app "default application" configuration
177 and shows the configuration of the indexing process (see \ref pres_longrequest):
178 
179 ~~~~~~~~~~~~~{.ini}
180 [ActionMapping]
181 ??indexAll = wcmf\application\controller\SearchIndexController
182 wcmf\application\controller\SearchIndexController??continue =
183  wcmf\application\controller\SearchIndexController
184 ~~~~~~~~~~~~~
185 
186 - The first line states that the action _indexAll_ called from _any_ controller and
187  in _any_ context will invoke
188  \link wcmf::application::controller::SearchIndexController `SearchIndexController`\endlink,
189  which will set a state dependent action name on the response (see
190  \link wcmf::application::controller::BatchController `BatchController`\endlink).
191 - The second line tells \link wcmf::lib::presentation::ActionMapper `ActionMapper`\endlink
192  to re-invoke
193  \link wcmf::application::controller::SearchIndexController `SearchIndexController`\endlink,
194  if it was the last controller and the action is _continue_. So this action key
195  only matches, if the last controller was
196  \link wcmf::application::controller::SearchIndexController `SearchIndexController`\endlink.
197 
198 ##### Controller methods #####
199 
200 The previous example maps the action keys to a controller class without specifying
201 a method to be called. In these cases, the framework calls the default method
202 `doExecute`, which must then be defined in the controller class (see \ref pres_controllers).
203 
204 Alternatively a specific __controller method__ to be called may be defined in the
205 action mapping, like illustrated in the following example:
206 
207 ~~~~~~~~~~~~~{.ini}
208 [ActionMapping]
209 ??indexAll = wcmf\application\controller\SearchIndexController::doBegin
210 wcmf\application\controller\SearchIndexController??continue =
211  wcmf\application\controller\SearchIndexController::doContinue
212 ~~~~~~~~~~~~~
213 
214 In this case \link wcmf::application::controller::SearchIndexController `SearchIndexController`\endlink
215 would have to define the methods `doBegin` and `doContinue` which are called
216 for the appropriate action keys.
217 
218 #### External routing #### {#pres_routingext}
219 
220 The mapping of the current __request uri__ to an __action key__ is called external
221 routing. The default mapping logic is implemented in the
222 \link wcmf::lib::presentation::impl::DefaultRequest::initialize `DefaultRequest::initialize`\endlink
223 method. The method matches the _path part_ of the request uri against the entries
224 of the `Routes` configuration section to find an appropriate action key.
225 Variables declared in path segments will be automatically passed as request parameters.
226 
227 The following example configuration taken from the \ref app "default application"
228 illustrates the concept:
229 
230 ~~~~~~~~~~~~~{.ini}
231 [Routes]
232 / = action=cms
233 /rest/{language}/{className} = action=restAction&collection=1
234 /rest/{language}/{className}/{id|[0-9]+} = action=restAction&collection=0
235 ~~~~~~~~~~~~~
236 
237 - The first entry is matched by the root path, which is then mapped to the _cms_
238  action - corresponding to the action key <em>??cms</em>.
239 - The second entry defines the _language_ and _className_ variables (surrounded
240  by curly braces) and would be matched by the request uris <em>/rest/de/Author</em>
241  or <em>/rest/en/Book</em>. The executed action would be _restAction_.
242 - The _id_ variable in the third entry must be an integer because of the regular
243  expression constraint `[0-9]+`.
244 
245 ##### HTTP methods #####
246 
247 To restrict a path to one or more __HTTP methods__, they may be added in front of
248 the route definition. In the following example the _cms_ action is only available
249 for the _GET_ method, while the other actions accept _GET_, _POST_, _PUT_ and
250 _DELETE_ requests:
251 
252 ~~~~~~~~~~~~~{.ini}
253 [Routes]
254 GET/ = action=cms
255 GET,POST,PUT,DELETE/rest/{language}/{className} = action=restAction&collection=1
256 GET,POST,PUT,DELETE/rest/{language}/{className}/{id|[0-9]+} = action=restAction&collection=0
257 ~~~~~~~~~~~~~
258 
259 If no method is added to a route, all methods are accepted.
260 
261 ## Controllers ## {#pres_controllers}
262 
263 Controllers take the user input from the request and modify the model according
264 to it. As a result a response is created which is presented to the user in a view
265 or any other format. Which controller is executed on a specific request is
266 determined in the routing process (see \ref pres_routing).
267 
268 wCMF provides \link wcmf::lib::presentation::Controller `Controller`\endlink as
269 abstract base class for controller implementations. There are three important
270 methods defined in this class, which are called by
271 \link wcmf::lib::presentation::ActionMapper `ActionMapper`\endlink in the following order:
272 
273 1. \link wcmf::lib::presentation::Controller::initialize `Controller::initialize`\endlink
274  is called directly after instantiation of the controller. The current
275  \link wcmf::lib::presentation::Request `Request`\endlink and
276  \link wcmf::lib::presentation::Response `Response`\endlink instances are passed
277  as parameters and subclasses may override this method to implement task specific
278  initializations.
279 2. \link wcmf::lib::presentation::Controller::validate `Controller::validate`\endlink
280  is called afterwards to check the validity of the request parameters. The default
281  implementation returns _true_ and subclasses are assumed to override this method
282  if necessary to do task specific validations.
283 3. \link wcmf::lib::presentation::Controller::execute `Controller::execute`\endlink
284  is called finally. This method accepts a parameter, that defines the actual
285  method to be called on the subclass. If the parameter is omitted it defaults
286  to `doExecute` which must then be defined in the subclass.
287 
288 ### Error handling ### {#pres_errors}
289 
290 Errors are typically divided into __fatal errors__ and __non-fatal errors__.
291 
292 By definition the application is not able to recover from a _fatal error_, meaning
293 that it's not functioning correctly. An example would be a programming error or
294 a missing vital resource. These errors normally need to be fixed by the application
295 maintainer. In case of _non-fatal errors_ a notice to the user is sufficient in most
296 cases. A typical example would be invalid user input, that can be fixed by the user
297 itself.
298 
299 In wCMF the following two strategies are recommended for handling these kind of
300 situations:
301 
302 - In case of a __fatal error__, an exception should be thrown. If it is not caught
303  inside the application code, it will bubble up to the main script (usually
304  _index.php_). In case the application is set up like in the \ref pres_application
305  section, the method
306  \link wcmf::lib::presentation::Application::handleException `Application::handleException`\endlink
307  will be called. This method rolls back the current transaction and calls the
308  _failure_ action, which is executed by
309  \link wcmf::application::controller::FailureController `FailureController`\endlink
310  by default.
311 
312 - If a __non-fatal error__ occurs, an instance of
313  \link wcmf::lib::presentation::ApplicationError `ApplicationError`\endlink
314  should be created and added to the response using the
315  \link wcmf::lib::presentation::Response::addError `Response::addError`\endlink
316  method. The error class provides the
317  \link wcmf::lib::presentation::ApplicationError::get `ApplicationError::get`\endlink
318  method to retrieve predefined errors. The following example shows how to signal
319  an invalid _type_ parameter while request validation:
320 
321 ~~~~~~~~~~~~~{.php}
322 $response->addError(ApplicationError::get('PARAMETER_INVALID',
323  array('invalidParameters' => array('type'))));
324 ~~~~~~~~~~~~~
325 
326 ### Long running requests ### {#pres_longrequest}
327 
328 There are situations where you want to split a long running process into parts,
329 because it's exceeding memory or time limits or simply to give the user feedback
330 about the progress. By subclassing
331 \link wcmf::application::controller::BatchController `BatchController`\endlink
332 the implementation of this behavior is as simple as defining the steps of
333 the process in the
334 \link wcmf::application::controller::BatchController::getWorkPackage `BatchController::getWorkPackage`\endlink
335 method.
336 
337 \link wcmf::application::controller::SearchIndexController `SearchIndexController`\endlink
338 is an example for a controller implementing a long running process. It is used
339 to create a Lucene search index over all searchable entity objects. The process
340 is split into collecting all object ids and then indexing them. In the final
341 step the index is optimized.
342 
343 ## Views ## {#pres_views}
344 
345 Views are used to present application information to the user. In a web application
346 they are typically HTML pages displayed in the browser.
347 
348 In wCMF the response will be turned into an HTML page, if the `Accept` HTTP header
349 is set to _text/html_ (see \ref pres_format). The appropriate
350 \link wcmf::lib::presentation::format::Format `Format`\endlink implementation is
351 \link wcmf::lib::presentation::format::impl::HtmlFormat `HtmlFormat`\endlink.
352 It renders the response into a template file using the configured
353 \link wcmf::lib::presentation::view::View `View`\endlink implementation. The format
354 of the template files depends on the chosen that implementation. Since different
355 actions may require different views to be displayed, a mapping of action keys to
356 view templates is defined in the `Views` configuration section.
357 
358 The following example shows the configuration of the
359 \link wcmf::lib::presentation::view::impl::SmartyView `SmartyView`\endlink class
360 and the mapping of action keys to views in the \ref app "default application":
361 
362 ~~~~~~~~~~~~~{.ini}
363 [View]
364 __class = wcmf\lib\presentation\view\impl\SmartyView
365 __shared = false
366 compileCheck = true
367 caching = false
368 cacheLifetime = 3600
369 cacheDir = app/cache/smarty/
370 
371 [Views]
372 app\src\controller\RootController?? = app/src/views/cms.tpl
373 ~~~~~~~~~~~~~
374 
375 Since the \ref app "default application" only uses an HTML page to bootstrap the
376 actual [Dojo](https://dojotoolkit.org/) application, there is only one view mapping
377 for `RootController`.
378 
379 ### Device dependent views ###
380 
381 \link wcmf::lib::presentation::format::impl::HtmlFormat `HtmlFormat`\endlink
382 allows to provide different versions of a view template. This is especially
383 useful, if you want to deliver device dependent content for the same action key.
384 
385 To select a specific template version, the value `html_tpl_format` has to be set
386 on the response instance. E.g. if the template file would be _home.tpl_, setting
387 the value to _mobile_ would select the template file _home-mobile.tpl_. If the
388 requested version does not exist, it is ignored and the default template is used
389 (_home.tpl_ in this example).
390 
391 ## Webservice APIs ##
392 
393 Besides the user interface driven \ref app "default application" wCMF provides
394 APIs for using the application as a [web service](https://en.wikipedia.org/wiki/Web_service).
395 These APIs provide create/read/update/delete
396 ([CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete))
397 operations on all entity types.
398 
399 ### RESTful API ###
400 
401 The [REST](https://en.wikipedia.org/wiki/Representational_state_transfer)ful
402 interface is implemented in
403 \link wcmf::application::controller::RESTController `RESTController`\endlink,
404 which basically acts as a facade in front of the application. That means the
405 controller checks the request data only and delegates the actual processing to
406 the action specific controller.
407 
408 The following example shows the configuration of the RESTful interface in the
409 \ref app "default application":
410 
411 ~~~~~~~~~~~~~{.ini}
412 [Routes]
413 /rest/{language}/{className} = action=restAction&collection=1
414 /rest/{language}/{className}/{id|[0-9]+} = action=restAction&collection=0
415 /rest/{language}/{className}/{sourceId|[0-9]+}/{relation} = action=restAction&collection=1
416 /rest/{language}/{className}/{sourceId|[0-9]+}/{relation}/{targetId|[0-9]+} = action=restAction&collection=0
417 
418 [ActionMapping]
419 ??restAction = wcmf\application\controller\RESTController
420 ~~~~~~~~~~~~~
421 
422 The `Routes` configuration section defines the urls for the interface. They all
423 call the action _restAction_ internally, which is handled by
424 \link wcmf::application::controller::RESTController `RESTController`\endlink as
425 defined in the `ActionMapping` section. For example the english version of
426 the `Author` instance with id _1_ may be retrieved by making a GET request to
427 the url <em>/rest/en/Author/1</em>.
428 
429 ### SOAP API ###
430 
431 wCMF uses the [NuSOAP](http://sourceforge.net/projects/nusoap/) library for
432 implementing the SOAP interface. It consists of the
433 \link wcmf::lib::service::SoapServer `SoapServer`\endlink and
434 \link wcmf::application::controller::SOAPController `SOAPController`\endlink classes.
435 The controller class handles all requests and delegates the processing to the
436 server class. The service description in the
437 [WSDL](https://en.wikipedia.org/wiki/Web_Services_Description_Language) format
438 is generated by the code generator into a file called _soap-interface.php_
439 (see \ref generator_artefacts_php).
440 
441 The following example shows the configuration of the SOAP interface in the
442 \ref app "default application":
443 
444 ~~~~~~~~~~~~~{.ini}
445 [Routes]
446 /soap = action=soapAction
447 
448 [ActionMapping]
449 ??soapAction = wcmf\application\controller\SOAPController
450 ~~~~~~~~~~~~~
451 
452 The `Routes` configuration section defines that the url <em>/soap</em> redirects
453 to the action _soapAction_ internally. The `ActionMapping` section defines that
454 this action is handled by
455 \link wcmf::application::controller::SOAPController `SOAPController`\endlink.
456 The interface description is available at the url <em>/soap?wsdl</em>.
457 
458 ## Caching ## {#pres_caching}
459 
460 Caching is an effective method to improve application performance. Caches in wCMF
461 are supposed to be divided into sections, which hold key-value pairs (see
462 \link wcmf::lib::io::Cache `Cache`\endlink interface). Cache instances may be
463 defined in the application configuration and retrieved by using
464 \link wcmf::lib::core::ObjectFactory `ObjectFactory`\endlink, which makes it easy
465 to exchange the underlying caching implementation.
466 
467 The following example shows the configuration of a
468 \link wcmf::lib::io::impl::FileCache `FileCache`\endlink instance in the
469 \ref app "default application":
470 
471 ~~~~~~~~~~~~~{.ini}
472 [Cache]
473 __class = wcmf\lib\io\impl\FileCache
474 cacheDir = app/cache/
475 ~~~~~~~~~~~~~
476 
477 The usage of this cache is illustrated in the code example:
478 
479 ~~~~~~~~~~~~~{.php}
480 $cache = ObjectFactory::getInstance('cache');
481 $cacheSection = 'calculations';
482 
483 $cacheKey = 'resultA';
484 if (!$cache->exists($cacheSection, $cacheKey)) {
485  // calculate the result and store it in the cache
486  $result = complexCalculationA();
487  $cache->put($cacheSection, $cacheKey, $value);
488 }
489 else {
490  // retrieve the result from the cache
491  $resultA = $cache->get($cacheSection, $cacheKey);
492 }
493 ~~~~~~~~~~~~~
494 
495 Supposed that `complexCalculationA` in this example takes long to finish, it
496 should only run once at the first time the result is needed. So we check if
497 _resultA_ is already cached and calculate it, if not. Since it is put it into the
498 cache after calculation, it can be retrieved _resultA_ directly from there the
499 next time it is needed.
500 
501 ## Events ## {#pres_events}
502 
503 Events are a way to decouple parts of a software by introducing an indirect
504 communication. They allow clients to react to certain application events without
505 the event source knowing them. wCMF uses the
506 [publish-subscribe](https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern)
507 messaging pattern, in which \link wcmf::lib::core::EventManager `EventManager`\endlink
508 acts as the message broker. Subscribers use this class to register for certain
509 \link wcmf::lib::core::Event `Event`\endlink types and publishers to send the
510 events.
511 
512 The following events are defined in wCMF:
513 
514 - \link wcmf::lib::persistence::PersistenceEvent `PersistenceEvent`\endlink
515  is sent whenever a \link wcmf::lib::persistence::PersistentObject `PersistentObject`\endlink
516  instance is created, updated or deleted.
517 - \link wcmf::lib::persistence::PropertyChangeEvent `PropertyChangeEvent`\endlink,
518  \link wcmf::lib::persistence::ValueChangeEvent `ValueChangeEvent`\endlink and
519  \link wcmf::lib::persistence::StateChangeEvent `StateChangeEvent`\endlink
520  signal changes in \link wcmf::lib::persistence::PersistentObject `PersistentObject`\endlink
521  instances.
522 - \link wcmf::lib::presentation::ApplicationEvent `ApplicationEvent`\endlink
523  allows to listen to the different steps of the request handling process.
524 
525 The event system may be extended by custom events by inheriting from the
526 \link wcmf::lib::core::Event `Event`\endlink class.
527 
528 The class below is a basic example for a listener that subscribes to persistence
529 events:
530 
531 ~~~~~~~~~~~~~{.php}
532 class PersistenceEventListener {
533  private $_eventListener = null;
534 
535  public function __construct(EventListener $eventListener) {
536  $this->_eventListener = $eventListener;
537  $this->_eventListener->addListener(PersistenceEvent::NAME,
538  array($this, 'persisted'));
539  }
540 
541  public function __destruct() {
542  $this->_eventListener->removeListener(PersistenceEvent::NAME,
543  array($this, 'persisted'));
544  }
545 
546  /**
547  * Listen to PersistenceEvent
548  * @param $event PersistenceEvent instance
549  */
550  public function persisted(PersistenceEvent $event) {
551  // do something on any create/update/delete
552  }
553 }
554 ~~~~~~~~~~~~~
555 
556 @note To prevent memory leaks the
557 \link wcmf::lib::core::EventManager::removeListener `EventManager::removeListener`\endlink
558 method __must__ be called, if the event listener is destroyed.
559 
560 To send a persistence event, the following code is used:
561 
562 ~~~~~~~~~~~~~{.php}
563 $eventListener = ObjectFactory::getInstance('eventManager');
564 $eventListener->dispatch(PersistenceEvent::NAME,
565  new PersistenceEvent($object, PersistenceAction::UPDATE));
566 ~~~~~~~~~~~~~
567 
568 ### Implicit listener installation ### {#pres_listeners}
569 
570 In some cases you may want to install event listeners without explicitely
571 instantiating them, because there is no appropriate place for that. For these
572 cases the \link wcmf::lib::presentation::Application `Application`\endlink class
573 reads the `listeners` value of the `Application` configuration section and
574 initializes all instances listed there.
575 
576 The \ref app "default application" defines two listeners as shown in the following
577 example:
578 
579 ~~~~~~~~~~~~~{.ini}
580 [Application]
581 listeners = {Search, EventListener}
582 ~~~~~~~~~~~~~
583 
584 Each entry in the `listeners` array is supposed to refer to an instance
585 configuration (see \ref conf_di).
586 
587 ## Logging ## {#pres_log}
588 
589 wCMF integrates the logging frameworks [log4php](http://logging.apache.org/log4php/)
590 and [Monolog](https://github.com/Seldaek/monolog). To abstract from these libraries
591 wCMF defines the \link wcmf::lib::core::Logger `Logger`\endlink interface and
592 implementations for each framework. The decision, which framework to use is made
593 by instantiating the appropriate \link wcmf::lib::core::Logger `Logger`\endlink
594 instance and passing it to the
595 \link wcmf::lib::core::LogManager::configure `LogManager::configure`\endlink
596 method as shown for _Monolog_ in the following example:
597 
598 ~~~~~~~~~~~~~{.php}
599 $logger = new MonologFileLogger('main', WCMF_BASE.'app/config/log.ini');
600 LogManager::configure($logger);
601 ~~~~~~~~~~~~~
602 
603 Afterwards \link wcmf::lib::core::Logger `Logger`\endlink instances can be retrieved
604 using the following code:
605 
606 ~~~~~~~~~~~~~{.php}
607 $logger = LogManager::getLogger(__CLASS__);
608 ~~~~~~~~~~~~~
609 
610 The parameter used in the
611 \link wcmf::lib::core::LogManager::getLogger `LogManager::getLogger`\endlink method
612 is the _logger name_. It's a good practice to use the `__CLASS__` constant as logger
613  name, since this allows to enable/disable loggers by class names in the configuration
614 (see \ref conf_logging).
615 
616 The following example shows how to log an error message with a stack trace
617 appended (see
618 \link wcmf::lib::core::ErrorHandler::getStackTrace `ErrorHandler::getStackTrace`\endlink):
619 
620 ~~~~~~~~~~~~~{.php}
621 $logger->error("An error occured.\n".ErrorHandler::getStackTrace());
622 ~~~~~~~~~~~~~
623 */