* implemented recursive deletion of objects (deletes the object its 1:n related...
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Persistence / Mapper / TX_EXTMVC_Persistence_Mapper_TcaMapper.php
1 <?php
2 declare(ENCODING = 'utf-8');
3
4 /* *
5 * This script belongs to the FLOW3 framework. *
6 * *
7 * It is free software; you can redistribute it and/or modify it under *
8 * the terms of the GNU Lesser General Public License as published by the *
9 * Free Software Foundation, either version 3 of the License, or (at your *
10 * option) any later version. *
11 * *
12 * This script is distributed in the hope that it will be useful, but *
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- *
14 * TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser *
15 * General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU Lesser General Public *
18 * License along with the script. *
19 * If not, see http://www.gnu.org/licenses/lgpl.html *
20 * *
21 * The TYPO3 project - inspiring people to share! *
22 * */
23
24 require_once(PATH_t3lib . 'interfaces/interface.t3lib_singleton.php');
25 require_once(t3lib_extMgm::extPath('extmvc') . 'Classes/Utility/TX_EXTMVC_Utility_Strings.php');
26
27 /**
28 * A mapper to map database tables configured in $TCA onto domain objects.
29 *
30 * @version $Id:$
31 * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License, version 3 or later
32 */
33 class TX_EXTMVC_Persistence_Mapper_TcaMapper implements t3lib_singleton {
34
35 /**
36 * The content object
37 *
38 * @var tslib_cObj
39 **/
40 protected $cObj;
41
42 /**
43 * The persistence session
44 *
45 * @var
46 **/
47 protected $session;
48
49 /**
50 * Constructs a new mapper
51 *
52 * @author Jochen Rau <jochen.rau@typoplanet.de>
53 */
54 public function __construct() {
55 $this->cObj = t3lib_div::makeInstance('tslib_cObj');
56 $this->session = t3lib_div::makeInstance('TX_EXTMVC_Persistence_Session');
57 $GLOBALS['TSFE']->includeTCA();
58 }
59
60 /**
61 * Finds objects matching property="xyz"
62 *
63 * @param string $propertyName The name of the property (will be chekced by a white list)
64 * @param string $arguments The WHERE statement
65 * @return void
66 * @author Jochen Rau <jochen.rau@typoplanet.de>
67 */
68 public function findWhere($className, $where = '1=1') {
69 return $this->reconstituteObjects($className, $this->fetch($className, $where));
70 }
71
72 /**
73 * Fetches a rows from the database by given SQL statement snippets
74 *
75 * @param string $from FROM statement
76 * @param string $where WHERE statement
77 * @param string $groupBy GROUP BY statement
78 * @param string $orderBy ORDER BY statement
79 * @param string $limit LIMIT statement
80 * @return void
81 * @author Jochen Rau <jochen.rau@typoplanet.de>
82 */
83 public function fetch($className, $where = '1=1', $groupBy = NULL, $orderBy = NULL, $limit = NULL) {
84 $tableName = $this->getTableName($className);
85 $rows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
86 '*', // TODO limit fetched fields
87 $tableName,
88 $where . $this->cObj->enableFields($tableName) . $this->cObj->enableFields($tableName),
89 $groupBy,
90 $orderBy,
91 $limit
92 );
93 // TODO language overlay; workspace overlay
94 return $rows ? $rows : array();
95 }
96
97 /**
98 * Fetches a rows from the database by given SQL statement snippets
99 *
100 * @author Jochen Rau <jochen.rau@typoplanet.de>
101 */
102 public function fetchOneToMany($parentObject, $parentField, $tableName, $where = '', $groupBy = NULL, $orderBy = NULL, $limit = NULL) {
103 $where .= ' ' . $parentField . '=' . intval($parentObject->getUid());
104 return $this->fetch($tableName, $where, $groupBy, $orderBy, $limit);
105 }
106
107 /**
108 * Fetches a rows from the database by given SQL statement snippets
109 *
110 * @author Jochen Rau <jochen.rau@typoplanet.de>
111 */
112 public function fetchManyToMany($parentObject, $foreignTableName, $relationTableName, $where = '1=1', $groupBy = NULL, $orderBy = NULL, $limit = NULL) {
113 $rows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
114 $foreignTableName . '.*, ' . $relationTableName . '.*',
115 $foreignTableName . ' LEFT JOIN ' . $relationTableName . ' ON (' . $foreignTableName . '.uid=' . $relationTableName . '.uid_foreign)',
116 $where . ' AND ' . $relationTableName . '.uid_local=' . intval($parentObject->getUid()) . $this->cObj->enableFields($foreignTableName) . $this->cObj->enableFields($foreignTableName),
117 $groupBy,
118 $orderBy,
119 $limit
120 );
121 // TODO language overlay; workspace overlay
122 return $rows ? $rows : array();
123 }
124
125 /**
126 * Dispatches the reconstitution of a domain object to an appropriate method
127 *
128 * @param array $rows The rows array fetched from the database
129 * @throws TX_EXTMVC_Persistence_Exception_RecursionTooDeep
130 * @return array An array of reconstituted domain objects
131 * @author Jochen Rau <jochen.rau@typoplanet.de>
132 */
133 protected function reconstituteObjects($className, array $rows) {
134 // TODO if ($depth > 10) throw new TX_EXTMVC_Persistence_Exception_RecursionTooDeep('The maximum depth of ' . $depth . ' recursions was reached.', 1233352348);
135 foreach ($rows as $row) {
136 $propertiesToReconstitute = array();
137 foreach ($row as $fieldName => $fieldValue) {
138 $propertyName = TX_EXTMVC_Utility_Strings::underscoredToLowerCamelCase($fieldName);
139 $propertiesToReconstitute[$propertyName] = $this->convertFieldValueToPropertyValue($className, $propertyName, $fieldValue);
140 }
141 $object = $this->reconstituteObject($className, $propertiesToReconstitute);
142 $properties = $object->_getProperties();
143 foreach ($properties as $propertyName => $propertyValue) {
144 if ($this->isOneToManyRelation($className, $propertyName)) {
145 $relatedRows = $this->fetchOneToMany($object, $this->getForeignUidField($className, $propertyName), $this->getForeignTableName($className, $propertyName));
146 $relatedObjects = $this->reconstituteObjects($this->getForeignClass($className, $propertyName), $relatedRows, $depth);
147 $object->_reconstituteProperty($propertyName, $relatedObjects);
148 } elseif ($this->isManyToManyRelation($className, $propertyName)) {
149 $relatedRows = $this->fetchManyToMany($object, $this->getForeignTableName($className, $propertyName), $this->getRelationTableName($className, $propertyName));
150 $relatedObjects = $this->reconstituteObjects($this->getForeignClass($className, $propertyName), $relatedRows, $depth);
151 $object->_reconstituteProperty($propertyName, $relatedObjects);
152 }
153 }
154 $this->session->registerReconstitutedObject($object);
155 $objects[] = $object;
156 }
157 return $objects;
158 }
159
160 /**
161 * Reconstitutes the specified object and fills it with the given properties.
162 *
163 * @param string $objectName Name of the object to reconstitute
164 * @param array $properties The names of properties and their values which should be set during the reconstitution
165 * @return object The reconstituted object
166 * @author Robert Lemke <robert@typo3.org>
167 */
168 protected function reconstituteObject($className, array $properties = array()) {
169 // those objects will be fetched from within the __wakeup() method of the object...
170 $GLOBALS['EXTMVC']['reconstituteObject']['properties'] = $properties;
171 $object = unserialize('O:' . strlen($className) . ':"' . $className . '":0:{};');
172 unset($GLOBALS['EXTMVC']['reconstituteObject']);
173 return $object;
174 }
175
176 /**
177 * Persists all objects of a persistence session
178 *
179 * @param string $session The persistence session
180 * @return void
181 * @author Jochen Rau <jochen.rau@typoplanet.de>
182 */
183 public function persistAll($session) {
184 $this->session = $session;
185
186 // first, persit all aggregate root objects
187 $aggregateRootClassNames = $this->session->getAggregateRootClassNames();
188 foreach ($aggregateRootClassNames as $className) {
189 $this->persistObjects($className);
190 }
191
192 // persist all remaining objects
193 $this->persistObjects();
194 }
195
196 /**
197 * Persists all objects of a persitance session that are of a given class. If there
198 * is no class specified, it persits all objects of a session.
199 *
200 * @param string $className Name of the class of the objects to be persisted
201 * @author Jochen Rau <jochen.rau@typoplanet.de>
202 */
203 protected function persistObjects($className = NULL) {
204 foreach ($this->session->getAddedObjects($className) as $object) {
205 $this->insertObject($object);
206 $this->session->unregisterAddedObject($object);
207 }
208 foreach ($this->session->getDirtyObjects($className) as $object) {
209 $this->updateObject($object);
210 $this->session->unregisterObject($object); // TODO is this necessary?
211 $this->session->registerReconstitutedObject($object);
212 }
213 foreach ($this->session->getRemovedObjects($className) as $object) {
214 $this->deleteObject($object);
215 $this->session->unregisterRemovedObject($object);
216 }
217 }
218
219 /**
220 * Inserts an object to the database.
221 *
222 * @return void
223 * @author Karsten Dambekalns <karsten@typo3.org>
224 * @author Jochen Rau <jochen.rau@typoplanet.de>
225 */
226 public function insertObject(TX_EXTMVC_DomainObject_AbstractDomainObject $object, $parentObject = NULL, $parentPropertyName = NULL) {
227 $queuedRelations = array();
228 $rowToInsert = array();
229 $properties = $object->_getProperties();
230 foreach ($properties as $propertyName => $propertyValue) {
231 if ($this->isOneToManyRelation(get_class($object), $propertyName)) {
232 $queuedRelations = t3lib_div::array_merge_recursive_overrule($queuedRelations, array($propertyName => $propertyValue));
233 $rowToInsert[TX_EXTMVC_Utility_Strings::camelCaseToLowerCaseUnderscored($propertyName)] = count($properties[$propertyName]);
234 } elseif ($this->isManyToManyRelation(get_class($object), $propertyName)) {
235 $queuedRelations = t3lib_div::array_merge_recursive_overrule($queuedRelations, array($propertyName => $propertyValue));
236 $rowToInsert[TX_EXTMVC_Utility_Strings::camelCaseToLowerCaseUnderscored($propertyName)] = count($properties[$propertyName]);
237 } else {
238 $rowToInsert[TX_EXTMVC_Utility_Strings::camelCaseToLowerCaseUnderscored($propertyName)] = $this->convertPropertyValueToFieldValue($propertyValue);
239 }
240 }
241
242 $rowToInsert['pid'] = 0; // FIXME
243 $rowToInsert['tstamp'] = time();
244 if ($parentObject !== NULL && $parentPropertyName !== NULL) {
245 $foreignUidfield = $this->getForeignUidField(get_class($parentObject), $parentPropertyName);
246 if ($foreignUidfield !== NULL) {
247 $rowToInsert[$foreignUidfield] = $parentObject->getUid();
248 }
249 $foreignTablefield = $this->getForeignTableField(get_class($parentObject), $parentPropertyName);
250 if ($foreignTablefield !== NULL) {
251 $rowToInsert[$foreignTablefield] = $this->getTableName(get_class($parentObject));
252 }
253 }
254 $tableName = $this->getTableName(get_class($object));
255 $res = $GLOBALS['TYPO3_DB']->exec_INSERTquery(
256 $tableName,
257 $rowToInsert
258 );
259
260 $object->_reconstituteProperty('uid', $GLOBALS['TYPO3_DB']->sql_insert_id());
261 // var_dump($object);
262
263 foreach ($queuedRelations as $propertyName => $relatedObjects) {
264 foreach ($relatedObjects as $relatedObject) {
265 if (!$this->session->isReconstitutedObject($relatedObject)) {
266 $this->insertObject($relatedObject, $object, $propertyName);
267 if ($this->isManyToManyRelation(get_class($object), $propertyName)) {
268 $this->insertRelation($object, $propertyName, $relatedObject);
269 }
270 }
271 }
272 }
273
274 }
275
276 /**
277 * Updates a modified object in the database
278 *
279 * @return void
280 * @author Karsten Dambekalns <karsten@typo3.org>
281 * @author Jochen Rau <jochen.rau@typoplanet.de>
282 */
283 public function updateObject(TX_EXTMVC_DomainObject_AbstractDomainObject $object, $parentObject = NULL, $parentPropertyName = NULL) {
284 $queuedRelations = array();
285 $fieldsToUpdate = array();
286 $properties = $object->_getDirtyProperties();
287 foreach ($properties as $propertyName => $propertyValue) {
288 if ($this->isOneToManyRelation(get_class($object), $propertyName)) {
289 $queuedRelations = t3lib_div::array_merge_recursive_overrule($queuedRelations, array($propertyName => $propertyValue));
290 $fieldsToUpdate[TX_EXTMVC_Utility_Strings::camelCaseToLowerCaseUnderscored($propertyName)] = count($properties[$propertyName]);
291 } elseif ($this->isManyToManyRelation(get_class($object), $propertyName)) {
292 $queuedRelations = t3lib_div::array_merge_recursive_overrule($queuedRelations, array($propertyName => $propertyValue));
293 $fieldsToUpdate[TX_EXTMVC_Utility_Strings::camelCaseToLowerCaseUnderscored($propertyName)] = count($properties[$propertyName]);
294 } else {
295 $fieldsToUpdate[TX_EXTMVC_Utility_Strings::camelCaseToLowerCaseUnderscored($propertyName)] = $this->convertPropertyValueToFieldValue($propertyValue);
296 }
297 }
298
299 $fieldsToUpdate['crdate'] = time();
300 if (!empty($GLOBALS['TSFE']->fe_user->user['uid'])) {
301 $fieldsToUpdate['cuser_id'] = $GLOBALS['TSFE']->fe_user->user['uid'];
302 }
303 if ($parentObject !== NULL && $parentPropertyName !== NULL) {
304 $foreignUidfield = $this->getForeignUidField(get_class($parentObject), $parentPropertyName);
305 if ($foreignUidfield !== NULL) {
306 $fieldsToUpdate[$foreignUidfield] = $parentObject->getUid();
307 }
308 $foreignTablefield = $this->getForeignTableField(get_class($parentObject), $parentPropertyName);
309 if ($foreignTablefield !== NULL) {
310 $fieldsToUpdate[$foreignTablefield] = $this->getTableName(get_class($parentObject));
311 }
312 }
313 $tableName = $this->getTableName(get_class($object));
314 $res = $GLOBALS['TYPO3_DB']->exec_UPDATEquery(
315 $tableName,
316 'uid=' . $object->getUid(),
317 $fieldsToUpdate
318 );
319
320 // var_dump($object);
321
322 foreach ($queuedRelations as $propertyName => $relatedObjects) {
323 foreach ($relatedObjects as $relatedObject) {
324 if (!$this->session->isReconstitutedObject($relatedObject)) {
325 $this->insertObject($relatedObject, $object, $propertyName);
326 if ($this->isManyToManyRelation(get_class($object), $propertyName)) {
327 $this->insertRelation($object, $propertyName, $relatedObject);
328 }
329 }
330 }
331 }
332
333 }
334
335 /**
336 * Deletes an object, it's 1:n related objects, and the m:n relations in relation tables (but not the m:n related objects!)
337 *
338 * @return void
339 * @author Jochen Rau <jochen.rau@typoplanet.de>
340 */
341 public function deleteObject(TX_EXTMVC_DomainObject_AbstractDomainObject $object, $parentObject = NULL, $parentPropertyName = NULL) {
342 $queuedRelations = array();
343 $properties = $object->_getProperties();
344 foreach ($properties as $propertyName => $propertyValue) {
345 if ($this->isOneToManyRelation(get_class($object), $propertyName)) {
346 $queuedRelations = t3lib_div::array_merge_recursive_overrule($queuedRelations, array($propertyName => $propertyValue));
347 } elseif ($this->isManyToManyRelation(get_class($object), $propertyName)) {
348 $queuedRelations = t3lib_div::array_merge_recursive_overrule($queuedRelations, array($propertyName => $propertyValue));
349 }
350 }
351
352 $tableName = $this->getTableName(get_class($object));
353 $res = $GLOBALS['TYPO3_DB']->exec_DELETEquery(
354 $tableName,
355 'uid=' . $object->getUid()
356 );
357
358 foreach ($queuedRelations as $propertyName => $relatedObjects) {
359 foreach ($relatedObjects as $relatedObject) {
360 if ($this->session->isReconstitutedObject($relatedObject)) {
361 if ($this->isOneToManyRelation(get_class($object), $propertyName)) {
362 $this->deleteObject($relatedObject, $object, $propertyName);
363 } elseif ($this->isManyToManyRelation(get_class($object), $propertyName)) {
364 $this->deleteRelations($object, $propertyName, $relatedObject);
365 }
366
367 }
368 }
369 }
370
371 }
372
373 /**
374 * Inserts relation to a relation table
375 *
376 * @param TX_EXTMVC_DomainObject_AbstractDomainObject $parentObject The parent object
377 * @param string $parentPropertyName The name of the parent object's property where the related objects are stored in
378 * @param TX_EXTMVC_DomainObject_AbstractDomainObject $relatedObject The related object
379 * @return void
380 * @author Jochen Rau <jochen.rau@typoplanet.de>
381 */
382 protected function insertRelation(TX_EXTMVC_DomainObject_AbstractDomainObject $parentObject, $parentPropertyName, TX_EXTMVC_DomainObject_AbstractDomainObject $relatedObject) {
383 $rowToInsert = array(
384 'uid_local' => $parentObject->getUid(),
385 'uid_foreign' => $relatedObject->getUid(),
386 'tablenames' => $this->getTableName(get_class($parentObject)),
387 'sorting' => 9999 // TODO sorting of mm table items
388 );
389 $tableName = $this->getRelationTableName(get_class($parentObject), $parentPropertyName);
390 $res = $GLOBALS['TYPO3_DB']->exec_INSERTquery(
391 $tableName,
392 $rowToInsert
393 );
394 }
395
396 /**
397 * Inserts relation to a relation table
398 *
399 * @param TX_EXTMVC_DomainObject_AbstractDomainObject $parentObject The parent object
400 * @param string $parentPropertyName The name of the parent object's property where the related objects are stored in
401 * @param TX_EXTMVC_DomainObject_AbstractDomainObject $relatedObject The related object
402 * @return void
403 * @author Jochen Rau <jochen.rau@typoplanet.de>
404 */
405 protected function deleteRelations(TX_EXTMVC_DomainObject_AbstractDomainObject $parentObject, $parentPropertyName, TX_EXTMVC_DomainObject_AbstractDomainObject $relatedObject) {
406 $tableName = $this->getRelationTableName(get_class($parentObject), $parentPropertyName);
407 $res = $GLOBALS['TYPO3_DB']->exec_DELETEquery(
408 $tableName,
409 'uid_local=' . $parentObject->getUid()
410 );
411 }
412
413 /**
414 * Returns all columns configured in $TCA for a given class
415 *
416 * @param string $className The class name
417 * @return array The column configurations from $TCA
418 * @author Jochen Rau <jochen.rau@typoplanet.de>
419 */
420 protected function getColumns($className) {
421 $tableName = $this->getTableName($className);
422 t3lib_div::loadTCA($tableName);
423 return $GLOBALS['TCA'][$tableName]['columns'];
424 }
425
426 /**
427 * Returns a table name for a given class
428 *
429 * @param string $className The class name
430 * @return string The table name
431 * @author Jochen Rau <jochen.rau@typoplanet.de>
432 */
433 protected function getTableName($className) {
434 // TODO implement table name aliases
435 return strtolower($className);
436 }
437
438 /**
439 * Returns the name of a column indicating the 'deleted' state of the row
440 *
441 * @param string $className The class name
442 * @return string The class name
443 * @author Jochen Rau <jochen.rau@typoplanet.de>
444 */
445 protected function getDeletedColumnName($className) {
446 $this->getTableName($className);
447 return $GLOBALS['TCA'][$tableName]['ctrl']['delete'];
448 }
449
450 /**
451 * Returns the name of a column indicating the 'hidden' state of the row
452 *
453 * @param string $className The class name
454 * @author Jochen Rau <jochen.rau@typoplanet.de>
455 */
456 protected function getHiddenColumnName($className) {;
457 $this->getTableName($className);
458 return $GLOBALS['TCA'][$tableName]['ctrl']['enablecolumns']['disabled'];
459 }
460
461 /**
462 * Returns TRUE if the given property corresponds to one to many relation in the database
463 *
464 * @param string $className The class name
465 * @param string $propertyName The property name
466 * @return boolean TRUE if the given property corresponds to one to many relation in the database
467 * @author Jochen Rau <jochen.rau@typoplanet.de>
468 */
469 protected function isOneToManyRelation($className, $propertyName) {
470 $columns = $this->getColumns($this->getTableName($className));
471 $columnConfiguration = $columns[TX_EXTMVC_Utility_Strings::camelCaseToLowerCaseUnderscored($propertyName)]['config'];
472 if (array_key_exists('foreign_table', $columnConfiguration) && !array_key_exists('MM', $columnConfiguration)) return TRUE;
473 return FALSE;
474 }
475
476 /**
477 * Returns TRUE if the given property corresponds to many to many relation in the database
478 *
479 * @param string $className The class name
480 * @param string $propertyName The property name
481 * @return boolean TRUE if the given property corresponds to many to many relation in the database
482 * @author Jochen Rau <jochen.rau@typoplanet.de>
483 */
484 protected function isManyToManyRelation($className, $propertyName) {
485 $columns = $this->getColumns($this->getTableName($className));
486 $columnConfiguration = $columns[TX_EXTMVC_Utility_Strings::camelCaseToLowerCaseUnderscored($propertyName)]['config'];
487 if (array_key_exists('foreign_table', $columnConfiguration) && array_key_exists('MM', $columnConfiguration)) return TRUE;
488 return FALSE;
489 }
490
491 /**
492 * Returns the foreign class name for a given parent class and property
493 *
494 * @param string $className The class name
495 * @param string $propertyName The property name
496 * @return string The foreign class name
497 * @author Jochen Rau <jochen.rau@typoplanet.de>
498 */
499 protected function getForeignClass($className, $propertyName) {
500 $columns = $this->getColumns($this->getTableName($className));
501 return $columns[TX_EXTMVC_Utility_Strings::camelCaseToLowerCaseUnderscored($propertyName)]['config']['foreign_class'];
502 }
503
504 /**
505 * Returns the foreign table name for a given parent class and property
506 *
507 * @param string $className The class name
508 * @param string $propertyName The property name
509 * @return string The foreign table name
510 * @author Jochen Rau <jochen.rau@typoplanet.de>
511 */
512 protected function getForeignTableName($className, $propertyName) {
513 $columns = $this->getColumns($this->getTableName($className));
514 return $columns[TX_EXTMVC_Utility_Strings::camelCaseToLowerCaseUnderscored($propertyName)]['config']['foreign_table'];
515 }
516
517 /**
518 * Returns the foreign uid field name for a given parent class and property
519 *
520 * @param string $className The class name
521 * @param string $propertyName The property name
522 * @return string The foreign uid field name
523 * @author Jochen Rau <jochen.rau@typoplanet.de>
524 */
525 protected function getForeignUidField($className, $propertyName) {
526 $columns = $this->getColumns($this->getTableName($className));
527 return $columns[TX_EXTMVC_Utility_Strings::camelCaseToLowerCaseUnderscored($propertyName)]['config']['foreign_field'];
528 }
529
530 /**
531 * Returns the foreign table field name for a given parent class and property
532 *
533 * @param string $className The class name
534 * @param string $propertyName The property name
535 * @return string The foreign table field name
536 * @author Jochen Rau <jochen.rau@typoplanet.de>
537 */
538 protected function getForeignTableField($className, $propertyName) {
539 $columns = $this->getColumns($this->getTableName($className));
540 return $columns[TX_EXTMVC_Utility_Strings::camelCaseToLowerCaseUnderscored($propertyName)]['config']['foreign_table_field'];
541 }
542
543 /**
544 * Returns the relation table name for a given parent class and property
545 *
546 * @param string $className The class name
547 * @param string $propertyName The property name
548 * @return string The relation table name
549 * @author Jochen Rau <jochen.rau@typoplanet.de>
550 */
551 protected function getRelationTableName($className, $propertyName) {
552 $columns = $this->getColumns($this->getTableName($className));
553 return $columns[TX_EXTMVC_Utility_Strings::camelCaseToLowerCaseUnderscored($propertyName)]['config']['MM'];
554 }
555
556 /**
557 * Returns TRUE if the property of a given class is of type date (as configured in $TCA)
558 *
559 * @param string $className The class name
560 * @param string $propertyName The property name
561 * @return boolean TRUE if the property of a given class is of type date (as configured in $TCA)
562 * @author Jochen Rau <jochen.rau@typoplanet.de>
563 */
564 protected function isOfTypeDate($className, $propertyName) {
565 $columns = $this->getColumns($this->getTableName($className));
566 return strpos($columns[TX_EXTMVC_Utility_Strings::camelCaseToLowerCaseUnderscored($propertyName)]['config']['eval'], 'date') !== FALSE
567 || strpos($columns[TX_EXTMVC_Utility_Strings::camelCaseToLowerCaseUnderscored($propertyName)]['config']['eval'], 'datetime') !== FALSE;
568 }
569
570 /**
571 * Returns TRUE if the property of a given class is of type boolean (as configured in $TCA)
572 *
573 * @param string $className The class name
574 * @param string $propertyName The property name
575 * @return boolean TRUE if the property of a given class is of type boolean (as configured in $TCA)
576 * @author Jochen Rau <jochen.rau@typoplanet.de>
577 */
578 protected function isOfTypeBoolean($className, $propertyName) {
579 $columns = $this->getColumns($this->getTableName($className));
580 return $columns[TX_EXTMVC_Utility_Strings::camelCaseToLowerCaseUnderscored($propertyName)]['config']['type'] === 'check'
581 && empty($columns[TX_EXTMVC_Utility_Strings::camelCaseToLowerCaseUnderscored($propertyName)]['config']['items']);
582 }
583
584 /**
585 * Returns TRUE if the property is persistable (configured in $TCA)
586 *
587 * @param string $className The class name
588 * @param string $propertyName The property name
589 * @return boolean TRUE if the property is persistable (configured in $TCA)
590 * @author Jochen Rau <jochen.rau@typoplanet.de>
591 */
592 public function isPersistableProperty($className, $propertyName) {
593 $columns = $this->getColumns($this->getTableName($className));
594 if (array_key_exists(TX_EXTMVC_Utility_Strings::camelCaseToLowerCaseUnderscored($propertyName), $columns)) return TRUE;
595 return FALSE;
596 }
597
598 /**
599 * Converts a value from a database field type to a property type
600 *
601 * @param string $className The class name
602 * @param string $propertyName The property name
603 * @param mixed $fieldValue The field value
604 * @return mixed The converted value
605 * @author Jochen Rau <jochen.rau@typoplanet.de>
606 */
607 protected function convertFieldValueToPropertyValue($className, $propertyName, $fieldValue) {
608 if ($this->isOfTypeDate($className, $propertyName)) {
609 $convertedValue = new DateTime(strftime('%Y-%m-%d %H:%M', $fieldValue), new DateTimeZone('UTC'));
610 } elseif ($this->isOfTypeBoolean($className, $propertyName)) {
611 if ($fieldValue === '0') {
612 $convertedValue = FALSE;
613 } else {
614 $convertedValue = TRUE;
615 }
616 } else {
617 $convertedValue = $fieldValue;
618 }
619 return $convertedValue;
620 }
621
622 /**
623 * Converts a value from a property type to a database field type
624 *
625 * @param mixed $propertyValue The property value
626 * @return mixed The converted value
627 * @author Jochen Rau <jochen.rau@typoplanet.de>
628 */
629 protected function convertPropertyValueToFieldValue($propertyValue) {
630 if ($propertyValue instanceof DateTime) {
631 $convertedValue = $propertyValue->format('U');
632 } elseif (is_bool($propertyValue)) {
633 $convertedValue = $propertyValue ? 1 : 0;
634 } else {
635 $convertedValue = $propertyValue;
636 }
637 return $convertedValue;
638 }
639
640 }
641 ?>