persistence.doxy
1 /*!
2 \page persistence Persistence
3 <div class="has-toc"></div>
4 
5 # Persistence # {#pers_main}
6 
7 Persistence refers to that part of the domain model, which we could call the data model.
8 
9 ## Data model ## {#pers_datamodel}
10 
11 The data model consists of domain classes whose instances are saved in the storage.
12 The following steps need to be accomplished to make domain class instances
13 persistent.
14 
15 - Definition and creation of the database tables, if using a database storage.
16 - Implementation of the \link wcmf::lib::persistence::PersistenceMapper `PersistenceMapper`\endlink
17  classes, which map the domain classes to these tables, or anything else that is used as storage.
18 - Implementation of the domain classes as subclasses of \link wcmf::lib::model::Node `Node`\endlink.
19 - Configuration of the persistence layer.
20 
21 @note If you are using the generator to create the application from a model
22 (see \ref model), all necessary code will be generated automatically.
23 
24 ### Database tables ### {#pers_tables}
25 
26 Still the most common storage for web applications is a _SQL_ database (e.g.
27 [MySQL](http://www.mysql.com/)). It is also wCMF's default storage. Although not
28 strictly necessary it is recommended to use one database table for each persistent
29 class, where each class property maps to one table column and each row stores one
30 instance. The object identity is stored in the primary key column, which is named
31 _id_ by default.
32 
33 @note wCMF uses a table called `DBSequence` for retrieving the next id value used for
34 insertion, since _autoincrement_ columns are not supported on all database servers.
35 
36 #### Primary keys #### {#pers_id}
37 
38 Primary keys are used to clearly identify an object in the database. They can consist
39 of one (_simple_) or more (_compound_) columns. The default name for a primary
40 key column is _id_. wCMF stores the primary key of an object together with it's type
41 name in an \link wcmf::lib::persistence::ObjectId `ObjectId`\endlink instance.
42 
43 #### Relations #### {#pers_relations}
44 
45 The following two relations types must be considered, when modeling the data
46 tables:
47 
48 - __One-To-Many__ relations are realized by adding a foreign key column to the
49 child table (_many_-side), which points to the parent table (_one_-side). This
50 column is named _fk_ _ + parent table name + _ _id_ by default (e.g. _fk_author_id_).
51 
52 - __Many-To-Many__ relations between two domain classes, are established by defining
53 a connection table. This table contains two primary keys, which point to the two
54 connected tables.
55 
56 ### Persistence Mappers ### {#pers_mappers}
57 
58 wCMF uses persistence mapper classes to communicate between the application and
59 the persistent storage (see \ref arch_main). These classes implement the
60 \link wcmf::lib::persistence::PersistenceMapper `PersistenceMapper`\endlink interface,
61 which defines methods for all persistence actions. By using this pattern wCMF
62 does not make any assumptions about the actual storage, which can be flat files,
63 a database or anything else a mapper is able to handle. This approach also makes
64 it easy to connect an existing storage to a newly created wCMF application.
65 
66 To simplify the implementation of mapper classes, wCMF already contains
67 a class hierarchy for a common mapping approach, which maps each concrete class
68 to one database table ([Concrete Table Inheritance]
69 (http://martinfowler.com/eaaCatalog/concreteTableInheritance.html)). In this
70 hierarchy \link wcmf::lib::model::mapper::RDBMapper `RDBMapper`\endlink handles
71 the communication with the relational database, while
72 \link wcmf::lib::model::mapper::NodeUnifiedRDBMapper `NodeUnifiedRDBMapper`\endlink
73 defines the actual mapping rules. Application developers simply need to implement
74 one subclass of \link wcmf::lib::model::mapper::NodeUnifiedRDBMapper `NodeUnifiedRDBMapper`\endlink
75 for each persistent domain class, which declares the mapping of the attributes and
76 relations of that class.
77 
78 @note All mapper classes, that are created by the generator are
79 \link wcmf::lib::model::mapper::NodeUnifiedRDBMapper `NodeUnifiedRDBMapper`\endlink
80 subclasses.
81 
82 ### Domain Classes ### {#pers_classes}
83 
84 Domain class instances hold the data that are used in the application and persisted
85 in the storage.
86 
87 Persistent domain classes either inherit from
88 - \link wcmf::lib::persistence::PersistentObject `PersistentObject`\endlink, which
89 is a container with value getter and setter methods, or from
90 - \link wcmf::lib::model::Node `Node`\endlink, which adds methods for managing
91 relations.
92 
93 These two classes are completely generic, the actual identity of the domain class -
94 that is the _properties_ and the _relations_ - are defined by the related
95 \link wcmf::lib::persistence::PersistenceMapper `PersistenceMapper`\endlink.
96 
97 So if no additional domain logic is required in the domain class, it would be
98 sufficient to use \link wcmf::lib::model::Node `Node`\endlink as domain class.
99 But in many cases you will want to execute custom code for \ref pers_hooks or
100 \ref pers_validation and therefor create a custom subclass of
101 \link wcmf::lib::model::Node `Node`\endlink.
102 
103 @note All domain classes, that are created by the generator are
104 \link wcmf::lib::model::Node `Node`\endlink subclasses.
105 
106 #### Persistence Hooks #### {#pers_hooks}
107 
108 Persistence hooks are methods that are called at certain points of the lifecycle of
109 an instance. The default implementation of these methods is empty - in fact their
110 sole purpose is to be overwritten in subclasses on order to implement special
111 functionality that should be executed at those points.
112 \link wcmf::lib::persistence::PersistentObject `PersistentObject`\endlink defines
113 the following persistence hooks:
114 
115 - \link wcmf::lib::persistence::PersistentObject::afterCreate `afterCreate`\endlink
116 - \link wcmf::lib::persistence::PersistentObject::beforeInsert `beforeInsert`\endlink
117 - \link wcmf::lib::persistence::PersistentObject::afterInsert `afterInsert`\endlink
118 - \link wcmf::lib::persistence::PersistentObject::afterLoad `afterLoad`\endlink
119 - \link wcmf::lib::persistence::PersistentObject::beforeUpdate `beforeUpdate`\endlink
120 - \link wcmf::lib::persistence::PersistentObject::afterUpdate `afterUpdate`\endlink
121 - \link wcmf::lib::persistence::PersistentObject::beforeDelete `beforeDelete`\endlink
122 - \link wcmf::lib::persistence::PersistentObject::afterDelete `afterDelete`\endlink
123 
124 #### Values, Properties and Tags #### {#pers_values}
125 
126 The following terms are important to know when working with wCMF's domain classes:
127 
128 - __Values__ are the persistent attributes of a domain class. You can think
129  of them as class members. Values are accessed using the methods
130  \link wcmf::lib::persistence::PersistentObject::getValue `getValue`\endlink
131  and \link wcmf::lib::persistence::PersistentObject::setValue `setValue`\endlink.
132 - __Properties__ apply to domain classes and domain class values. They describe
133  static features like the `display_value` of the class or the `input_type`
134  of a value. Properties are defined in the model as _tags_ (see \ref model_profile)
135  and are accessed using the methods
136  \link wcmf::lib::persistence::PersistentObject::getProperty `getProperty`\endlink/
137  \link wcmf::lib::persistence::PersistentObject::setProperty `setProperty`\endlink
138  and
139  \link wcmf::lib::persistence::PersistentObject::getValueProperty `getValueProperty`\endlink/
140  \link wcmf::lib::persistence::PersistentObject::setValueProperty `setValueProperty`\endlink
141 - __Tags__ are a special property used on values to group them by certain
142  aspects. For example the edit forms in the \ref app "default application" only
143  display domain class values that are tagged with `DATATYPE_ATTRIBUTE` and only those
144  attributes are editable in the translation form that are tagged with `TRANSLATABLE`.
145  Tags are defined in the model using the _tag_ `app_data_type` (see \ref model_chivalue).
146 
147 ### Configuration ### {#pers_config}
148 
149 Entry point of configuring the persistence layer is
150 \link wcmf::lib::persistence::PersistenceFacade `PersistenceFacade`\endlink
151 (see \ref pers_usage).
152 The configuration mainly tells the facade which mapper classes are responsible
153 for which domain classes. This assignment is defined in the `TypeMapping`
154 configuration section. The following example shows the appropriate entries
155 for the `Author` domain class:
156 
157 ~~~~~~~~~~~~~{.ini}
158 [PersistenceFacade]
159 __class = wcmf\lib\persistence\impl\DefaultPersistenceFacade
160 mappers = $typeMapping
161 logging = false
162 logStrategy = $auditingLogStragegy
163 
164 [AuditingLogStragegy]
165 __class = wcmf\lib\persistence\output\impl\AuditingOutputStrategy
166 
167 [TypeMapping]
168 app.src.model.Author = $app_src_model_AuthorRDBMapper
169 
170 [app_src_model_AuthorRDBMapper]
171 __class = app\src\model\AuthorRDBMapper
172 connectionParams = $database
173 
174 [Database]
175 dbType = sqlite
176 dbHostName = 127.0.0.1
177 dbName = app/test-db.sq3
178 dbUserName =
179 dbPassword =
180 dbCharSet = utf8
181 ~~~~~~~~~~~~~
182 
183 ## Usage ## {#pers_usage}
184 
185 \link wcmf::lib::persistence::PersistenceFacade `PersistenceFacade`\endlink is
186 the main entry point to the persistence layer. It is used to create and retrieve
187 \link wcmf::lib::persistence::PersistentObject `PersistentObject`\endlink instances.
188 The following sections show some basic examples for using the persistence layer.
189 
190 ### Loading objects ### {#pers_load}
191 
192 ~~~~~~~~~~~~~{.php}
193 $oid = new ObjectId('Author', 1);
194 
195 // load the Author instance with id 1
196 $author = ObjectFactory::getInstance('persistenceFacade')->load($oid);
197 
198 // PersistenceFacade will return null, if an instance does not exist
199 if($author == null) {
200  echo("An Author with object id ".$oid." does not exist.";
201 }
202 ~~~~~~~~~~~~~
203 
204 In the example the `Author` instance with id _1_ is loaded.
205 
206 #### Build depth #### {#pers_builddepth}
207 
208 When loading objects we generally distinguish between __eager__ and __lazy__ loading
209 (see [Lazy loading](http://en.wikipedia.org/wiki/Lazy_loading)).
210 By default \link wcmf::lib::persistence::PersistenceFacade `PersistenceFacade`\endlink
211 performs _lazy loading_ by using _virtual proxies_ (instances of
212 \link wcmf::lib::persistence::PersistentObjectProxy `PersistentObjectProxy`\endlink).
213 That means that related objects are retrieved from the store, only when they are
214 actually accessed. To perform _eager loading_, a
215 \link wcmf::lib::persistence::BuildDepth `BuildDepth`\endlink
216 value may be passed in the method calls:
217 
218 ~~~~~~~~~~~~~{.php}
219 $oid = new ObjectId('Author', 1);
220 
221 // load the Author instance with id 1 together with all related objects
222 $author = ObjectFactory::getInstance('persistenceFacade')->load($oid, BuildDepth::INFINITE);
223 ~~~~~~~~~~~~~
224 
225 In this example the `Author` instance with id _1_ is loaded together with all related
226 objects recursively.
227 
228 Instead of a \link wcmf::lib::persistence::BuildDepth `BuildDepth`\endlink
229 value, an integer number may be passed indicating the depth of relations to load.
230 The following image illustrates the _build depth_ parameter for a simple model.
231 
232 \image html builddepth.png "Build depth"
233 
234 If using a build depth value of _1_ the `Author` instance _Author A_ will be loaded together
235 with it's related `Articles` instances (_Article A_, _Article B_). A value of _2_ will also load
236 the `Chapter` instances (_Chapter A1_, _Chapter A2_). The default value is
237 \link wcmf::lib::persistence::BuildDepth::SINGLE `BuildDepth::SINGLE`\endlink,
238 which means that only the _Author A_ instance is loaded. In the above illustration
239 the value of _2_ is equal to passing
240 \link wcmf::lib::persistence::BuildDepth::INFINITE `BuildDepth::INFINITE`\endlink.
241 
242 #### Sorting #### {#pers_sorting}
243 
244 When loading a list of objects, the default order of the
245 \link wcmf::lib::persistence::PersistenceMapper `PersistenceMapper`\endlink
246 class is used for sorting. This default order is defined in the model (_orderby_ tag
247 of _ChiNode_, see \ref model_chinode). Besides this, all loading methods (e.g.
248 \link wcmf::lib::persistence::PersistenceFacade::loadObjects `PersistenceFacade::loadObjects`\endlink)
249 accept an `orderby` parameter for explicitly setting a different order.
250 
251 A list of already loaded \link wcmf::lib::model::Node `Node`\endlink
252 instances may be sorted by using \link wcmf::lib::model::NodeComparator `NodeComparator`\endlink
253 in the following way:
254 
255 ~~~~~~~~~~~~~{.php}
256 $nodeList = array(...);
257 
258 // set up a comparator for node type and created date
259 $sortCriteria = array(
260  NodeComparator::ATTRIB_TYPE => NodeComparator::SORTTYPE_ASC,
261  'created' => NodeComparator::SORTTYPE_DESC
262 );
263 $comparator = new NodeComparator($sortCriteria);
264 
265 // sort node list
266 usort($nodeList, array($comparator, 'compare'));
267 ~~~~~~~~~~~~~
268 
269 #### Pagination #### {#pers_pagination}
270 
271 To reduce the response time of your application when displaying large lists
272 of objects, [pagination](http://en.wikipedia.org/wiki/Pagination#Pagination_in_web_content)
273 may be used. This technique splits the list into smaller parts (_pages_) that are displayed
274 one by one. In wCMF the class \link wcmf::lib::persistence::PagingInfo `PagingInfo`\endlink
275 implements the concept.
276 
277 The following code shows how to load _25_ `Author` instances starting from
278 position _50_:
279 
280 ~~~~~~~~~~~~~{.php}
281 // setup paging
282 $pagingInfo = new PagingInfo(25);
283 $pagingInfo->setOffset(50);
284 
285 // load the Author instances
286 $authors = ObjectFactory::getInstance('persistenceFacade')->loadObjects('Author', BuildDepth::SINGLE, null, null, $pagingInfo);
287 ~~~~~~~~~~~~~
288 
289 ### Searching objects ### {#pers_search}
290 
291 To search objects in the store the
292 \link wcmf::lib::persistence::PersistenceFacade::loadObjects `PersistenceFacade::loadObjects`\endlink
293 method may be used. It allows to set the conditions that loaded objects should match.
294 
295 ~~~~~~~~~~~~~{.php}
296 $criteria = array(
297  new Criteria("Article", "title", "LIKE", "A%"),
298  new Criteria("Article", "year", ">=", "2014")))
299 )
300 
301 // load all Article instances with titles starting with A and release date 2014 or later
302 $articles = ObjectFactory::getInstance('persistenceFacade')->loadObjects("Article", BuildDepth::SINGLE, $criteria);
303 ~~~~~~~~~~~~~
304 
305 In this example all `Article` instances with titles starting with _A_ and release date
306 _2014 or later_ are loaded.
307 
308 More complex use cases are supported by the \link wcmf::lib::model::ObjectQuery `ObjectQuery`\endlink
309 class. For example it allows to set search constraints on connected objects as
310 shown in the following example:
311 
312 ~~~~~~~~~~~~~{.php}
313 // create a Author query
314 $query = new ObjectQuery('Author');
315 
316 // query part: Author.name LIKE 'A%' OR Author.name LIKE 'B%'
317 $authorTpl1 = $query->getObjectTemplate("Author");
318 $authorTpl1->setValue("name", Criteria::asValue("LIKE", "A%"));
319 $authorTpl2 = $query->getObjectTemplate("Author", null, Criteria::OPERATOR_OR);
320 $authorTpl2->setValue("name", Criteria::asValue("LIKE", "B%"));
321 
322 // query part: Article.created >= '2004-01-01' AND Article.created < '2005-01-01'
323 $articleTpl1 = $query->getObjectTemplate("Article");
324 $articleTpl1->setValue("created", Criteria::asValue(">=", "2004-01-01"));
325 $articleTpl2 = $query->getObjectTemplate("Article");
326 $articleTpl2->setValue("created", Criteria::asValue("<", "2005-01-01"));
327 
328 // connect query nodes
329 $authorTpl1->addNode($articleTpl1);
330 $authorTpl1->addNode($articleTpl2);
331 
332 // load result
333 $authorList = $query->execute(BuildDepth::SINGLE);
334 ~~~~~~~~~~~~~
335 
336 In this example all `Author` instances are loaded which have names starting with
337 _A_ or _B_ and which have `Article` instances connected that are created in the
338 year _2014_.
339 
340 Besides this, wCMF integrates the
341 [Lucene](http://framework.zend.com/manual/1.12/en/zend.search.lucene.overview.html)
342 search engine in the class \link wcmf::lib::search::impl::LuceneSearch `LuceneSearch`\endlink.
343 
344 ### Iterating objects ### {#pers_iter}
345 
346 wCMF provides several [iterator](http://php.net/manual/en/class.iterator.php)
347 classes for traversing objects and values.
348 
349 \link wcmf::lib::model::NodeIterator `NodeIterator`\endlink allows to traverse
350 object graphs starting from a root \link wcmf::lib::model::Node `Node`\endlink.
351 The algorithm used is [depth-first search](http://en.wikipedia.org/wiki/Depth-first_search).
352 
353 ~~~~~~~~~~~~~{.php}
354 // traverse $root and all descendents
355 $it = new NodeIterator($root);
356 foreach($it as $oid => $obj) {
357  echo "current object id: $oid";
358  echo "current object: $obj";
359 }
360 ~~~~~~~~~~~~~
361 
362 \link wcmf::lib::model::NodeValueIterator `NodeValueIterator`\endlink is used
363 to iterate over all persistent values of a \link wcmf::lib::model::Node `Node`\endlink.
364 
365 ~~~~~~~~~~~~~{.php}
366 // traverse all values of $object
367 $it = new NodeValueIterator($object);
368 for($it->rewind(); $it->valid(); $it->next()) {
369  echo "current object: ".$it->currentNode();
370  echo "current attribute name: ".$it->key();
371  echo "current attribute value: ".$it->current();
372 }
373 ~~~~~~~~~~~~~
374 
375 \link wcmf::lib::model::PersistentIterator `PersistentIterator`\endlink allows
376 to traverse object graphs as well, but it's state may be persisted to split the
377 iteration of large lists into smaller parts.
378 
379 ~~~~~~~~~~~~~{.php}
380 // traverse 10 nodes starting from $oid
381 $counter = 0;
382 $it = new PersistentIterator($oid);
383 while($it->valid() && $counter < 10) {
384  echo "current object: ".$it->currentNode();
385  $it->next();
386  $counter++;
387 }
388 
389 // save iterator state in the session
390 $iterId = $it->save();
391 
392 // load the iterator state later and traverse the remaining nodes
393 $it = PersistentIterator::load($iterId);
394 while($it->valid()) {
395  echo "current object: ".$it->currentNode();
396  $it->next();
397 }
398 ~~~~~~~~~~~~~
399 
400 ### Creating / Modifying objects ### {#pers_create_modify}
401 
402 Domain class instances are created by calling the
403 \link wcmf::lib::persistence::PersistenceFacade::create `PersistenceFacade::create`\endlink
404 method or simply the class constructor, where the first approach is preferred
405 over the second because it also sets the default values on attributes.
406 
407 Changes on instances are persisted automatically, when the current transaction
408 is committed (see \ref pers_tx). Objects are removed from the store by calling the
409 \link wcmf::lib::persistence::PersistentObject::delete `PersistentObject::delete`\endlink
410 method.
411 
412 ~~~~~~~~~~~~~{.php}
413 $persistenceFacade = ObjectFactory::getInstance('persistenceFacade');
414 $tx = $persistenceFacade->getTransaction();
415 
416 // create an Author instance
417 $author = $persistenceFacade->create('Author');
418 $author->setValue('name', 'Author A');
419 
420 // create an Article instance and attach it to the author
421 $article = $persistenceFacade->create('Article');
422 $article->setValue('title', 'Article A');
423 $author->addNode($article);
424 
425 // save everything
426 $tx->commit();
427 
428 // get the author's object id
429 $oid = $author->getOID()
430 
431 // delete the author instance
432 $author = $persistenceFacade->load($oid);
433 $author->delete();
434 
435 // save everything
436 $tx->commit();
437 ~~~~~~~~~~~~~
438 
439 ## Validation ## {#pers_validation}
440 
441 Before persisting objects, their content has to be validated according to the
442 application requirements. Validation is handled in
443 \link wcmf::lib::persistence::PersistentObject::validateValue `PersistentObject::validateValue`\endlink
444 (for a single attribute) or
445 \link wcmf::lib::persistence::PersistentObject::validateValues `PersistentObject::validateValues`\endlink
446 (for the complete instance). These methods are called when values are changed via
447 \link wcmf::lib::persistence::PersistentObject::setValue `PersistentObject::setValue`\endlink
448 or right before persisting the object in
449 \link wcmf::lib::persistence::impl::AbstractMapper::save `AbstractMapper::save`\endlink.
450 Both validation methods throw a
451 \link wcmf::lib::persistence::ValidationException `ValidationException`\endlink, if
452 validation fails.
453 
454 ### Validation types ### {#pers_validation_types}
455 
456 The actual validation is delegated to the
457 \link wcmf::lib::persistence::validator::Validator `Validator`\endlink
458 class, which uses
459 \link wcmf::lib::persistence::validator::ValidateType `ValidateType`\endlink
460 implementations for validating different types of attributes. Each validation type
461 accepts configuration options, that are passed in as a string value. The format
462 of this value is completely up to the validator type implementation. To define
463 which validation should be applied to a domain class attribute, the
464 _tag_ `restrictions_match` is used in the model (see \ref model_chivalue).
465 
466 Currently three validation types are supported:
467 
468 \link wcmf::lib::persistence::validator::impl::Filter `Filter`\endlink
469 validates against a PHP filter (see [filter_var](http://php.net/manual/en/function.filter-var.php)),
470 e.g.
471 ~~~~~~~~~~~~~{.php}
472 // FILTER_VALIDATE_INT with min_range option and FILTER_FLAG_ALLOW_HEX flag
473 filter:int|{"options":{"min_range":0},"flags":2}
474 ~~~~~~~~~~~~~
475 
476 \link wcmf::lib::persistence::validator::impl::Image `Image`\endlink
477 checks _width_ and _height_ of the referred image file
478 e.g.
479 ~~~~~~~~~~~~~{.php}
480 // image width exactly 200px, height less than 100px
481 image:{"width":[200,1],"height":[100,0]}
482 ~~~~~~~~~~~~~
483 
484 \link wcmf::lib::persistence::validator::impl::RegExp `RegExp`\endlink
485 validates against a regular expression (see [preg_match](http://php.net/manual/en/function.preg-match.php))
486 e.g.
487 ~~~~~~~~~~~~~{.php}
488 // integer or empty
489 regexp:^[0-9]*$
490 ~~~~~~~~~~~~~
491 
492 \note The validation type is derived from the part of the configuration string,
493 that precedes the first colon.
494 
495 Custom validation types may be added in the configuration. For example
496 after adding `myValidator` (implemented in `MyValidator` class):
497 
498 ~~~~~~~~~~~~~{.ini}
499 [Validators]
500 regexp = $regexpValidator
501 filter = $filterValidator
502 image = $imageValidator
503 myValidator = $myValidator
504 
505 [MyValidator]
506 __class = path\to\MyValidator
507 ~~~~~~~~~~~~~
508 
509 it may be used in the following way:
510 
511 ~~~~~~~~~~~~~{.php}
512 myValidator:custom_configuration_string_passed_by_MyValidator
513 ~~~~~~~~~~~~~
514 
515 ### Complex validation ### {#pers_validation_custom}
516 
517 The described validation types only operate on one attribute. If more complex
518 validation is required, e.g. if dependencies between several attributes exist, the method
519 \link wcmf::lib::persistence::PersistentObject::validateValue `PersistentObject::validateValue`\endlink
520 may be overriden in the appropriate domain class.
521 
522 ## Concurrency ## {#pers_concurrency}
523 
524 When two or more users try to access the same object at the same time problems
525 like _lost updates_ might occur. These issues are avoided by _concurrency control_
526 mechanisms, typically _object locking_.
527 
528 ### Locking ### {#pers_locking}
529 
530 wCMF provides two locking strategies:
531 
532 - __Pessimistic locking__: An explicit lock is obtained by one user, that blocks
533  write access to the object for other users until the lock is released.
534 - __Optimistic locking__: A copy of the initial object data is stored for each user
535  and checked against later, when the user tries to store the object. The operation
536  fails, if another user has updated the object data in the meantime.
537 
538 For more detailed information see
539 [database locks](http://en.wikipedia.org/wiki/Lock_%28computer_science%29#Database_locks).
540 
541 \link wcmf::lib::persistence::concurrency::Lock `Lock`\endlink instances are
542 obtained by calling
543 \link wcmf::lib::persistence::concurrency::ConcurrencyManager::aquireLock `ConcurrencyManager::aquireLock`\endlink
544 and released using
545 \link wcmf::lib::persistence::concurrency::ConcurrencyManager::releaseLock `ConcurrencyManager::releaseLock`\endlink
546 like shown in the following example:
547 
548 ~~~~~~~~~~~~~{.php}
549 // object id of the object to lock
550 $oid = new ObjectId('Author', 1);
551 
552 // aquire an optimistic lock for the object
553 $lockType = Lock::TYPE_OPTIMISTIC;
554 $concurrencyManager = ObjectFactory::getInstance('concurrencyManager');
555 try {
556  $concurrencyManager->aquireLock($oid, $lockType);
557 }
558 catch(PessimisticLockException $ex) {
559  // another user already holds a lock on this object
560  echo $ex->getMessage();
561 }
562 
563 // release lock later
564 $concurrencyManager->releaseLock($oid, $lockType);
565 ~~~~~~~~~~~~~
566 
567 The actual storage and retrieval of
568 \link wcmf::lib::persistence::concurrency::Lock `Lock`\endlink instances is
569 delegated to
570 \link wcmf::lib::persistence::concurrency::LockHandler `LockHandler`\endlink.
571 The following lines show the concurrency configuration in the \ref app "default application":
572 
573 ~~~~~~~~~~~~~{.ini}
574 [ConcurrencyManager]
575 __class = wcmf\lib\persistence\concurrency\impl\DefaultConcurrencyManager
576 lockHandler = $lockHandler
577 
578 [LockHandler]
579 __class = wcmf\lib\persistence\concurrency\impl\DefaultLockHandler
580 lockType = app.src.model.wcmf.Lock
581 ~~~~~~~~~~~~~
582 
583 As you can see the
584 \link wcmf::lib::persistence::concurrency::LockHandler `LockHandler`\endlink
585 implementation is exchangeable.
586 
587 ## Transactions ## {#pers_tx}
588 
589 wCMF supports [database transactions](http://en.wikipedia.org/wiki/Database_transaction).
590 There is only __one transaction at the same time__ and it may be obtained using the
591 \link wcmf::lib::persistence::PersistenceFacade::getTransaction `PersistenceFacade::getTransaction`\endlink
592 method. The transaction has an _active_ state, which is set in the
593 \link wcmf::lib::persistence::Transaction::begin `Transaction::begin`\endlink
594 method and reset on commit or rollback.
595 
596 The following example shows, how to use transactions:
597 
598 ~~~~~~~~~~~~~{.php}
599 $persistenceFacade = ObjectFactory::getInstance('persistenceFacade');
600 
601 // get the current transaction and start it
602 $transaction = $persistenceFacade->getTransaction();
603 $transaction->begin();
604 try {
605  // load the the Author instance with id 1 and make changes to it
606  $author = $persistenceFacade->load(new ObjectId('Author', 1));
607  $author->setValue("name", "Author B");
608 
609  // save the changes
610  $transaction->commit();
611 }
612 catch(Exception $ex) {
613  // rollback the transaction if the commit fails
614  echo $ex->getMessage();
615  $transaction->rollback();
616 }
617 ~~~~~~~~~~~~~
618 
619 \note Even if not obtained explicitely, there is always a transaction existing
620 in the background, to which objects loaded from the store are attached. But to
621 persist changes when doing a commit, the transaction has to be set _active_
622 _before_ loading or creating the object.
623 
624 There are situations where you want to let the current transaction __ignore changes__
625 made to newly created objects or objects loaded from the store. In these cases you
626 can use the method
627 \link wcmf::lib::persistence::Transaction::detach `Transaction::detach`\endlink
628 to disconnect the object from the transaction.
629 */