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