Refactored the ObjectRelationalMapper, fixed testcases
authorChristopher Hlubek <hlubek@networkteam.com>
Fri, 27 Mar 2009 13:03:40 +0000 (13:03 +0000)
committerChristopher Hlubek <hlubek@networkteam.com>
Fri, 27 Mar 2009 13:03:40 +0000 (13:03 +0000)
typo3/sysext/extbase/Classes/Persistence/Mapper/ObjectRelationalMapper.php
typo3/sysext/extbase/Classes/Persistence/Repository.php
typo3/sysext/extbase/Tests/ObjectRelationalMapper_testcase.php
typo3/sysext/extbase/Tests/Repository_testcase.php

index a57df82..185f562 100644 (file)
@@ -60,131 +60,159 @@ class Tx_ExtBase_Persistence_Mapper_ObjectRelationalMapper implements t3lib_Sing
         *
         */
        public function __construct() {
-               $this->persistenceSession = t3lib_div::makeInstance('Tx_ExtBase_Persistence_Session'); // singleton
+               $this->persistenceSession = t3lib_div::makeInstance('Tx_ExtBase_Persistence_Session');
                $GLOBALS['TSFE']->includeTCA();
                $this->database = $GLOBALS['TYPO3_DB'];
        }
        
        /**
-        * Fetches objects from the database by given SQL statement snippets.
+        * The build query method is invoked by the Persistence Repository.
+        * Build a query for objects by multiple conditions. Either as SQL parts or query by example.
+        * 
+        * The following condition array would find entities with description like the given keyword and
+        * name equal to "foo".
         *
-        * @param string $className the className
-        * @param string $where WHERE statement
-        * @param string $groupBy GROUP BY statement
-        * @param string $orderBy ORDER BY statement
-        * @param string $limit LIMIT statement
-        * @return array The matched rows
+        * <pre>
+        * array(
+        *   array('blog_description LIKE ?', $keyword),
+        *      'blogName' => 'Foo'
+        *      )
+        * </pre>
+        * 
+        * Note: The SQL part uses the database columns names, the query by example syntax uses
+        * the object property name (camel-cased, without underscore).
+        *
+        * @param array|string $conditions The conditions as an array or SQL string
+        * @return string The query where part for the class and given conditions
         */
-       public function fetch($className, $where = '', $groupBy = '', $orderBy = '', $limit = '', $useEnableFields = TRUE) {
-               if (!is_string($where) || strlen($where) === 0) {
-                       $where = '1=1';
-               }
+       public function buildQuery($className, $conditions) {
                $dataMap = $this->getDataMap($className);
-               if ($useEnableFields === TRUE) {
-                       $enableFields = $GLOBALS['TSFE']->sys_page->enableFields($dataMap->getTableName());
-               } else {
-                       $enableFields = '';
-               }
-
-               $rows = $this->database->exec_SELECTgetRows(
-                       '*',
-                       $dataMap->getTableName(),
-                       $where . $enableFields,
-                       $groupBy,
-                       $orderBy,
-                       $limit
-                       );
-                       // TODO language overlay; workspace overlay
-
-               $objects = array();
-               if (is_array($rows) && (count($rows) > 0)) {
-                       $objects = $this->reconstituteObjects($className, $rows);
+               if (is_array($conditions)) {
+                       $where = $this->buildQueryByConditions($dataMap, $conditions);
+               } if (is_string($conditions)) {
+                       $where = $conditions;
                }
-               return $objects;
+               return $where;
        }
        
        /**
-        * Fetches a rows from the database by given SQL statement snippets taking a relation table into account
+        * Get a where part for conditions by a specific data map. This will
+        * either replace placeholders (index based array) or use the condition
+        * as an example relative to the data map.
         *
-        * @param string Optional WHERE clauses put in the end of the query, defaults to '1=1. NOTICE: You must escape values in this argument with $this->fullQuoteStr() yourself!
-        * @param string Optional GROUP BY field(s), defaults to blank string.
-        * @param string Optional ORDER BY field(s), defaults to blank string.
-        * @param string Optional LIMIT value ([begin,]max), defaults to blank string.
+        * @param Tx_ExtBase_Persistence_Mapper_DataMap $dataMap The data map
+        * @param array $conditions The conditions
+        * 
+        * @return string The where part
         */
-       public function fetchWithRelationTable($parentObject, $columnMap, $where = '1=1', $groupBy = '', $orderBy = '', $limit = '', $useEnableFields = TRUE) {
-               if ($useEnableFields === TRUE) {
-                       $enableFields = $GLOBALS['TSFE']->sys_page->enableFields($columnMap->getChildTableName());
+       protected function buildQueryByConditions(&$dataMap, $conditions) {
+               $whereParts = array();
+               foreach ($conditions as $key => $condition) {
+                       if (is_array($condition) && isset($condition[0])) {
+                               $sql = $this->replacePlaceholders($dataMap, $condition[0], array_slice($condition, 1));
+                               $whereParts[] = '(' . $sql . ')';
+                       } elseif (is_string($key)) {
+                               $sql = $this->buildQueryByExample($dataMap, $key, $condition);
+                               if (strlen($sql) > 0) {
+                                       $whereParts[] = '(' . $sql . ')';
+                               }
+                       }
+               }
+               return implode(' AND ', $whereParts);           
+       }
+
+       /**
+        * Get a where part for an example condition (associative array). This also works
+        * for nested conditions.
+        *
+        * @param Tx_ExtBase_Persistence_Mapper_DataMap $dataMap The data map
+        * @param array $propertyName The property name
+        * @param array $example The example condition
+        * 
+        * @return string The where part
+        */
+       protected function buildQueryByExample(&$dataMap, $propertyName, $example) {
+               $sql = '';
+               $columnMap = $dataMap->getColumnMap($propertyName);
+               if (!$columnMap) {
+                       echo "No columnMap for $propertyName";
+               }
+               if (!is_array($example)) {
+                       $column = $dataMap->getTableName() . '.' . $columnMap->getColumnName();
+                       $sql = $column . ' = ' . $dataMap->convertPropertyValueToFieldValue($example);
                } else {
-                       $enableFields = '';
+                       $childDataMap = $this->getDataMap($columnMap->getChildClassName());
+                       $sql = $this->buildQueryByConditions($childDataMap, $example);
                }
-               $rows = $this->database->exec_SELECTgetRows(
-                       $columnMap->getChildTableName() . '.*, ' . $columnMap->getRelationTableName() . '.*',
-                       $columnMap->getChildTableName() . ' LEFT JOIN ' . $columnMap->getRelationTableName() . ' ON (' . $columnMap->getChildTableName() . '.uid=' . $columnMap->getRelationTableName() . '.uid_foreign)',
-                       $where . ' AND ' . $columnMap->getRelationTableName() . '.uid_local=' . t3lib_div::intval_positive($parentObject->getUid()) . $enableFields,
-                       $groupBy,
-                       $orderBy,
-                       $limit
-                       );
-               // TODO language overlay; workspace overlay; sorting
-               $objects = array();
-               if (is_array($rows)) {
-                       if (count($rows) > 0) {
-                               $objects = $this->reconstituteObjects($columnMap->getChildClassName(), $rows);
+               return $sql;
+       }
+       
+       /**
+        * Replace query placeholders in a query part by the given
+        * parameters.
+        *
+        * @param Tx_ExtBase_Persistence_Mapper_DataMap $dataMap The data map for conversion
+        * @param string $queryPart The query part with placeholders
+        * @param array $parameters The parameters
+        *
+        * @return string The query part with replaced placeholders
+        */
+       protected function replacePlaceholders(&$dataMap, $queryPart, $parameters) {
+               $sql = $queryPart;
+               foreach ($parameters as $parameter) {
+                       $markPosition = strpos($sql, '?');
+                       if ($markPosition !== FALSE) {
+                               $sql = substr($sql, 0, $markPosition) . $dataMap->convertPropertyValueToFieldValue($parameter) . substr($sql, $markPosition + 1);
                        }
                }
-               return $objects;
+               return $sql;
        }
-       
+
        /**
         * Fetches objects from the database by given SQL statement snippets. The where
         * statement is raw SQL and will not be escaped. It is much safer to use the
         * generic find method to supply where conditions.
         *
         * @param string $className the className
-        * @param array $conditions The conditions
+        * @param string $where WHERE statement
+        * @param string $from FROM statement will default to the tablename of the given class
         * @param string $groupBy GROUP BY statement
         * @param string $orderBy ORDER BY statement
         * @param string $limit LIMIT statement
         * @return array The matched rows
         */
-       public function fetchByConditions($className, $conditions = array(), $groupBy = '', $orderBy = '', $limit = '', $useEnableFields = TRUE) {
-               $where = $this->queryByConditions($dataMap, $conditions);
-               if (strlen($where) === 0) {
+       public function fetch($className, $where = '', $from = '', $groupBy = '', $orderBy = '', $limit = '', $useEnableFields = TRUE) {
+               if (!strlen($where)) {
                        $where = '1=1';
                }
                $dataMap = $this->getDataMap($className);
+               $joinClause = $this->getJoinClause($className);
+               if (!strlen($from)) {
+                       $from = $dataMap->getTableName() . ' ' . $joinClause;
+               }
                if ($useEnableFields === TRUE) {
                        $enableFields = $GLOBALS['TSFE']->sys_page->enableFields($dataMap->getTableName());
+                       // TODO CH: add enable fields for joined tables
                } else {
                        $enableFields = '';
                }
                
-               $joinTables = $this->getJoinClause($className);
                $res = $this->database->exec_SELECTquery(
                        '*', // TODO limit fetched fields (CH: should we do that? JR: Not needed; only existing properties will be mapped)
-                       $dataMap->getTableName() . ' ' . $joinTables,
+                       $from,
                        $where . $enableFields,
                        $groupBy,
                        $orderBy,
                        $limit
                        );
-                       // TODO language overlay; workspace overlay
                        
-               $fieldMap = array();
-               $i = 0;
-               // FIXME mysql_fetch_field should be available in t3lib_db (patch core)
-               $rows = array();
-               if ($res !== FALSE) {
-                       while ($field = mysql_fetch_field($res)) {
-                               $fieldMap[$field->table][$field->name] = $i;
-                               $i++;
-                       }
-                       while($rows[] = $this->database->sql_fetch_row($res));
-                       array_pop($rows);
-               }
-
+               $fieldMap = $this->getFieldMapFromResult($res);
+               $rows = $this->getRowsFromResult($res);
+               
+               $this->database->sql_free_result($res);
                
                // SK: Do we want to make it possible to ignore "enableFields"?
+               // TODO language overlay; workspace overlay
                $objects = array();
                if (is_array($rows)) {
                        if (count($rows) > 0) {
@@ -194,6 +222,28 @@ class Tx_ExtBase_Persistence_Mapper_ObjectRelationalMapper implements t3lib_Sing
                return $objects;
        }
        
+       protected function getFieldMapFromResult($res) {
+               $fieldMap = array();
+               if ($res !== FALSE) {
+                       $fieldPosition = 0;
+                       // FIXME mysql_fetch_field should be available in t3lib_db (patch core)
+                       while ($field = mysql_fetch_field($res)) {
+                               $fieldMap[$field->table][$field->name] = $fieldPosition;
+                               $fieldPosition++;
+                       }
+               }
+               return $fieldMap;
+       }
+       
+       protected function getRowsFromResult($res) {
+               $rows = array();
+               if ($res !== FALSE) {
+                       while($rows[] = $this->database->sql_fetch_row($res));
+                       array_pop($rows);
+               }
+               return $rows;
+       }
+       
        /**
         * Get the join clause for the fetch method for a specific class. This will
         * eagerly load all has-one relations.
@@ -212,118 +262,23 @@ class Tx_ExtBase_Persistence_Mapper_ObjectRelationalMapper implements t3lib_Sing
                }
                return $join;
        }
-       
-       /**
-        * Get a where part for conditions by a specific data map. This will
-        * either replace placeholders (index based array) or use the condition
-        * as an example relative to the data map.
-        *
-        * @param Tx_ExtBase_Persistence_Mapper_DataMap $dataMap The data map
-        * @param array $conditions The conditions
-        * 
-        * @return string The where part
-        */
-       protected function queryByConditions(&$dataMap, $conditions) {
-               $whereParts = array();
-               foreach ($conditions as $key => $condition) {
-                       if (is_array($condition) && isset($condition[0])) {
-                               $sql = $this->replacePlaceholders($dataMap, $condition[0], array_slice($condition, 1));
-                               $whereParts[] = '(' . $sql . ')';
-                       } elseif (is_string($key)) {
-                               $sql = $this->queryByExample($dataMap, $key, $condition);
-                               if (strlen($sql) > 0) {
-                                       $whereParts[] = '(' . $sql . ')';
-                               }
-                       }
-               }
-               return implode(' AND ', $whereParts);           
-       }
-       
-       /**
-        * Get a where part for an example condition (associative array). This also works
-        * for nested conditions.
-        *
-        * @param Tx_ExtBase_Persistence_Mapper_DataMap $dataMap The data map
-        * @param array $propertyName The property name
-        * @param array $example The example condition
-        * 
-        * @return string The where part
-        */
-       protected function queryByExample(&$dataMap, $propertyName, $example) {
-               $sql = '';
-               if (!is_array($example)) {
-                       $column = $dataMap->getTableName() . '.' . $dataMap->getColumnMap($propertyName)->getColumnName();
-                       $sql = $column . ' = ' . $dataMap->convertPropertyValueToFieldValue($example);
-               } else {
-                       $columnMap = $dataMap->getColumnMap($propertyName);
-                       $childDataMap = $this->getDataMap($columnMap->getChildClassName());
-                       $sql = $this->queryByConditions($childDataMap, $example);
-               }
-               return $sql;
-       }
-       
-       /**
-        * Replace query placeholders in a query part by the given
-        * parameters.
-        *
-        * @param Tx_ExtBase_Persistence_Mapper_DataMap $dataMap The data map for conversion
-        * @param string $queryPart The query part with placeholders
-        * @param array $parameters The parameters
-        *
-        * @return string The query part with replaced placeholders
-        */
-       protected function replacePlaceholders(&$dataMap, $queryPart, $parameters) {
-               $sql = $queryPart;
-               foreach ($parameters as $parameter) {
-                       $markPos = strpos($sql, '?');
-                       if ($markPos !== FALSE) {
-                               $sql = substr($sql, 0, $markPos) . $dataMap->convertPropertyValueToFieldValue($parameter) . substr($sql, $markPos + 1);
-                       }
-               }
-               // TODO Throw exception on unsubstituted question marks
-               return $sql;
-       }
-       
+
        /**
-        * reconstitutes domain objects from $rows (array)
+        * Fetches a rows from the database by given SQL statement snippets taking a relation table into account
         *
-        * @param Tx_ExtBase_Persistence_Mapper_DataMap $dataMap The data map corresponding to the domain object
-        * @param array $fieldMap An array indexed by the table name and field name to the row index
-        * @param array $rows The rows array fetched from the database (not associative)
-        * @return array An array of reconstituted domain objects
+        * @param string Optional WHERE clauses put in the end of the query, defaults to '1=1. NOTICE: You must escape values in this argument with $this->fullQuoteStr() yourself!
+        * @param string Optional GROUP BY field(s), defaults to blank string.
+        * @param string Optional ORDER BY field(s), defaults to blank string.
+        * @param string Optional LIMIT value ([begin,]max), defaults to blank string.
         */
-       // SK: I Need to check this method more thoroughly.
-       // SK: Are loops detected during reconstitution?
-       protected function reconstituteObjects($className, array $rows) {
-               $dataMap = $this->getDataMap($className);
-               $objects = array();
-               foreach ($rows as $row) {
-                       $properties = array();
-                       foreach ($dataMap->getColumnMaps() as $columnMap) {
-                               $fieldValue = $row[$columnMap->getColumnName()];
-                               $properties[$columnMap->getPropertyName()] = $dataMap->convertFieldValueToPropertyValue($columnMap->getPropertyName(), $fieldValue);
-                       }
-                       $object = $this->reconstituteObject($dataMap->getClassName(), $properties);
-                       foreach ($dataMap->getColumnMaps() as $columnMap) {
-                               if ($columnMap->getTypeOfRelation() === Tx_ExtBase_Persistence_Mapper_ColumnMap::RELATION_HAS_ONE) {
-                                       list($relatedObject) = $this->reconstituteObjects($columnMap->getChildClassName(), $row);
-                                       $object->_reconstituteProperty($columnMap->getPropertyName(), $relatedObject);
-                               } elseif ($columnMap->getTypeOfRelation() === Tx_ExtBase_Persistence_Mapper_ColumnMap::RELATION_HAS_MANY) {
-                                       $where = $columnMap->getParentKeyFieldName() . '=' . intval($object->getUid());
-                                       $relatedDataMap = $this->getDataMap($columnMap->getChildClassName());
-                                       $relatedObjects = $this->fetch($columnMap->getChildClassName(), $where);
-                                       $object->_reconstituteProperty($columnMap->getPropertyName(), $relatedObjects);
-                               } elseif ($columnMap->getTypeOfRelation() === Tx_ExtBase_Persistence_Mapper_ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY) {
-                                       $relatedDataMap = $this->getDataMap($columnMap->getChildClassName());
-                                       // FIXME fetchWithRelationTable()
-                                       $relatedObjects = $this->fetchWithRelationTable($object, $columnMap);
-                                       $object->_reconstituteProperty($columnMap->getPropertyName(), $relatedObjects);
-                               }
-                       }
-                       $this->persistenceSession->registerReconstitutedObject($object);
-                       $objects[] = $object;
+       public function fetchWithRelationTable($parentObject, $columnMap, $where = '', $groupBy = '', $orderBy = '', $limit = '', $useEnableFields = TRUE) {
+               if (!strlen($where)) {
+                       $where = '1=1';
                }
-               return $objects;
+               $from = $columnMap->getChildTableName() . ' LEFT JOIN ' . $columnMap->getRelationTableName() . ' ON (' . $columnMap->getChildTableName() . '.uid=' . $columnMap->getRelationTableName() . '.uid_foreign)';
+               $where .= ' AND ' . $columnMap->getRelationTableName() . '.uid_local=' . t3lib_div::intval_positive($parentObject->getUid());
+
+               return $this->fetch($columnMap->getChildClassName(), $where, $from, $groupBy, $orderBy, $limit, $useEnableFields);
        }
 
        /**
@@ -336,7 +291,7 @@ class Tx_ExtBase_Persistence_Mapper_ObjectRelationalMapper implements t3lib_Sing
         */
        // SK: I Need to check this method more thoroughly.
        // SK: Are loops detected during reconstitution?
-       protected function reconstituteObjectsWithFieldMap($dataMap, &$fieldMap, array $rows) {
+       protected function reconstituteObjects($dataMap, &$fieldMap, array $rows) {
                $objects = array();
                foreach ($rows as $row) {
                        $properties = array();
@@ -356,7 +311,6 @@ class Tx_ExtBase_Persistence_Mapper_ObjectRelationalMapper implements t3lib_Sing
                                        $object->_reconstituteProperty($columnMap->getPropertyName(), $relatedObjects);
                                } elseif ($columnMap->getTypeOfRelation() === Tx_ExtBase_Persistence_Mapper_ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY) {
                                        $relatedDataMap = $this->getDataMap($columnMap->getChildClassName());
-                                       // FIXME fetchWithRelationTable()
                                        $relatedObjects = $this->fetchWithRelationTable($object, $columnMap);
                                        $object->_reconstituteProperty($columnMap->getPropertyName(), $relatedObjects);
                                }
@@ -665,7 +619,7 @@ class Tx_ExtBase_Persistence_Mapper_ObjectRelationalMapper implements t3lib_Sing
                        'uid_local=' . $parentObject->getUid()
                        );
                $existingRelations = array();
-               while($row = mysql_fetch_assoc($res)) {
+               while($row = $this->database->sql_fetch_assoc($res)) {
                        $existingRelations[current($row)] = current($row);
                }
                $relationsToDelete = $existingRelations;
@@ -695,7 +649,10 @@ class Tx_ExtBase_Persistence_Mapper_ObjectRelationalMapper implements t3lib_Sing
         * @return boolean TRUE if the property is persistable (configured in $TCA)
         */
        public function isPersistableProperty($className, $propertyName) {
-               return $this->getDataMap($className)->isPersistableProperty($propertyName);
+               $dataMap = new Tx_ExtBase_Persistence_Mapper_DataMap($className);
+               $dataMap->initialize();
+               return $dataMap->isPersistableProperty($propertyName);
+               return $dataMap->isPersistableProperty($propertyName);
        }
 
        /**
index 61e9867..1e5ec1b 100644 (file)
@@ -114,10 +114,10 @@ abstract class Tx_ExtBase_Persistence_Repository implements Tx_ExtBase_Persisten
        public function __call($methodName, $arguments) {
                if (substr($methodName, 0, 6) === 'findBy' && strlen($methodName) > 7) {
                        $propertyName = Tx_ExtBase_Utility_Strings::lowercaseFirst(substr($methodName,6));
-                       return $this->findWhere(array($propertyName => $arguments[0]));
+                       return $this->findByConditions(array($propertyName => $arguments[0]));
                } elseif (substr($methodName, 0, 9) === 'findOneBy' && strlen($methodName) > 10) {
                        $propertyName = Tx_ExtBase_Utility_Strings::lowercaseFirst(substr($methodName,9));
-                       $result = $this->findWhere(array($propertyName => $arguments[0]), '', '', 1);
+                       $result = $this->findByConditions(array($propertyName => $arguments[0]), '', '', 1);
                        if (count($result) > 0) {
                                return $result[0];
                        } else {
@@ -126,11 +126,9 @@ abstract class Tx_ExtBase_Persistence_Repository implements Tx_ExtBase_Persisten
                }
                throw new Tx_ExtBase_Persistence_Exception_UnsupportedMethod('The method "' . $methodName . '" is not supported by the repository.', 1233180480);
        }
-       
-       
+
        /**
-        * Find objects by multiple conditions. Either as SQL parts or query by example. The fin process is delegated
-        * to the data mapper.
+        * Find objects by a raw where clause.
         *
         * @param string $where The conditions as an array or SQL string
         * @param string $groupBy Group by SQL part
@@ -144,8 +142,7 @@ abstract class Tx_ExtBase_Persistence_Repository implements Tx_ExtBase_Persisten
        }
 
        /**
-        * Find objects by multiple conditions. Either as SQL parts or query by example. The fin process is delegated
-        * to the data mapper.
+        * Find objects by multiple conditions. Either as SQL parts or query by example.
         * 
         * The following condition array would find entities with description like the given keyword and
         * name equal to "foo".
@@ -167,8 +164,9 @@ abstract class Tx_ExtBase_Persistence_Repository implements Tx_ExtBase_Persisten
         * @param bool $useEnableFields Wether to automatically restrict the query by enable fields
         * @return array An array of objects, an empty array if no objects found
         */
-       public function findByConditions($conditions = array(), $groupBy = '', $orderBy = '', $limit = '', $useEnableFields = TRUE) {
-               return $this->dataMapper->fetchByConditions($this->aggregateRootClassName, $conditions, $groupBy, $orderBy, $limit, $useEnableFields);
+       public function findByConditions($conditions = '', $groupBy = '', $orderBy = '', $limit = '', $useEnableFields = TRUE) {
+               $where = $this->dataMapper->buildQuery($this->aggregateRootClassName, $conditions);
+               return $this->dataMapper->fetch($this->aggregateRootClassName, $where, '', $groupBy, $orderBy, $limit, $useEnableFields);
        }
 
        /**
index 5c3c56c..c5a8cdb 100644 (file)
@@ -38,12 +38,8 @@ class Tx_ExtBase_Persistence_Mapper_ObjectRelationalMapper_testcase extends Tx_E
                $GLOBALS['TYPO3_DB'] = $this->typo3Db;
        }
 
-       public function test_FindByConditionWithPlaceholders() {
-               $this->markTestIncomplete('This test has not been fully implemented yet.');
-               $mapper = $this->getMock('Tx_ExtBase_Persistence_Mapper_ObjectRelationalMapper', array('fetchByConditions'));
-               $mapper->expects($this->once())
-                       ->method('fetch')
-                       ->with($this->equalTo('Tx_BlogExample_Domain_Model_Blog'), $this->equalTo('(name LIKE "foo" OR name LIKE "bar") AND (hidden = 0)'));
+       public function test_BuildQueryWithPlaceholders() {
+               $mapper = new Tx_ExtBase_Persistence_Mapper_ObjectRelationalMapper();
                
                $GLOBALS['TYPO3_DB']->expects($this->at(0))
                        ->method('fullQuoteStr')
@@ -55,20 +51,18 @@ class Tx_ExtBase_Persistence_Mapper_ObjectRelationalMapper_testcase extends Tx_E
                        ->with($this->equalTo('bar'))
                        ->will($this->returnValue('"bar"'));
                
-               $mapper->fetchByConditions('Tx_BlogExample_Domain_Model_Blog',
+               $query = $mapper->buildQuery('Tx_BlogExample_Domain_Blog',
                        array(
                                array('name LIKE ? OR name LIKE ?', 'foo', 'bar'),
                                array('hidden = ?', FALSE)
                        ));
+               
+               $this->assertEquals('(name LIKE "foo" OR name LIKE "bar") AND (hidden = 0)', $query);
        }
 
-       public function test_FindByConditionWithExample() {
-               $this->markTestIncomplete('This test has not been fully implemented yet.');
-               $mapper = $this->getMock('Tx_ExtBase_Persistence_Mapper_ObjectRelationalMapper', array('fetchByConditions', 'getDataMap'));
-               $mapper->expects($this->once())
-                       ->method('fetch')
-                       ->with($this->equalTo('Tx_BlogExample_Domain_Model_Blog'), $this->equalTo('(tx_blogexample_domain_model_blog.blog_name = "foo") AND (tx_blogexample_domain_model_blog.hidden = 0)'));
-
+       public function test_BuildQueryWithExample() {
+               $mapper = $this->getMock('Tx_ExtBase_Persistence_Mapper_ObjectRelationalMapper', array('getDataMap'));
+       
                $columnMap1 = $this->getMock('Tx_ExtBase_Persistence_Mapper_ColumnMap', array('getColumnName'), array(), '', FALSE);
                $columnMap1->expects($this->once())
                        ->method('getColumnName')
@@ -82,22 +76,22 @@ class Tx_ExtBase_Persistence_Mapper_ObjectRelationalMapper_testcase extends Tx_E
                $dataMap = $this->getMock('Tx_ExtBase_Persistence_Mapper_DataMap', array('getColumnMap', 'getTableName'), array(), '', FALSE);
 
                $dataMap->expects($this->at(0))
-                       ->method('getTableName')
-                       ->will($this->returnValue('tx_blogexample_domain_model_blog'));
-
-               $dataMap->expects($this->at(1))
                        ->method('getColumnMap')
                        ->with($this->equalTo('blogName'))
                        ->will($this->returnValue($columnMap1));
 
-               $dataMap->expects($this->at(2))
+               $dataMap->expects($this->at(1))
                        ->method('getTableName')
                        ->will($this->returnValue('tx_blogexample_domain_model_blog'));
 
-               $dataMap->expects($this->at(3))
+               $dataMap->expects($this->at(2))
                        ->method('getColumnMap')
                        ->with($this->equalTo('hidden'))
                        ->will($this->returnValue($columnMap2));
+
+               $dataMap->expects($this->at(3))
+                       ->method('getTableName')
+                       ->will($this->returnValue('tx_blogexample_domain_model_blog'));
                
                $mapper->expects($this->any())
                        ->method('getDataMap')
@@ -109,19 +103,17 @@ class Tx_ExtBase_Persistence_Mapper_ObjectRelationalMapper_testcase extends Tx_E
                        ->with($this->equalTo('foo'))
                        ->will($this->returnValue('"foo"'));
                
-               $mapper->fetchByConditions('Tx_BlogExample_Domain_Model_Blog',
+               $query = $mapper->buildQuery('Tx_BlogExample_Domain_Model_Blog',
                        array(
                                'blogName' => 'foo',
                                'hidden' => FALSE
                        ));
+               
+               $this->assertEquals('(tx_blogexample_domain_model_blog.blog_name = "foo") AND (tx_blogexample_domain_model_blog.hidden = 0)', $query);
        }
        
-       public function test_FindByConditionWithNestedExample() {
-               $this->markTestIncomplete('This test has not been fully implemented yet.');
-               $mapper = $this->getMock('Tx_ExtBase_Persistence_Mapper_ObjectRelationalMapper', array('fetchByConditions', 'getDataMap'));
-               $mapper->expects($this->once())
-                       ->method('fetch')
-                       ->with($this->equalTo('Tx_BlogExample_Domain_Model_Blog'), $this->equalTo('(tx_blogexample_domain_model_blog.hidden = 0) AND ((tx_blogexample_domain_model_author.name = "Christopher"))'));
+       public function test_BuildQueryWithNestedExample() {
+               $mapper = $this->getMock('Tx_ExtBase_Persistence_Mapper_ObjectRelationalMapper', array('getDataMap'));
 
                $columnMap1 = $this->getMock('Tx_ExtBase_Persistence_Mapper_ColumnMap', array('getColumnName'), array(), '', FALSE);
                $columnMap1->expects($this->once())
@@ -135,12 +127,12 @@ class Tx_ExtBase_Persistence_Mapper_ObjectRelationalMapper_testcase extends Tx_E
 
                $dataMap1 = $this->getMock('Tx_ExtBase_Persistence_Mapper_DataMap', array('getColumnMap', 'getTableName'), array(), '', FALSE);
                $dataMap1->expects($this->at(0))
-                       ->method('getTableName')
-                       ->will($this->returnValue('tx_blogexample_domain_model_blog'));
-               $dataMap1->expects($this->at(1))
                        ->method('getColumnMap')
                        ->with($this->equalTo('hidden'))
                        ->will($this->returnValue($columnMap1));
+               $dataMap1->expects($this->at(1))
+                       ->method('getTableName')
+                       ->will($this->returnValue('tx_blogexample_domain_model_blog'));
                $dataMap1->expects($this->at(2))
                        ->method('getColumnMap')
                        ->with($this->equalTo('author'))
@@ -153,12 +145,12 @@ class Tx_ExtBase_Persistence_Mapper_ObjectRelationalMapper_testcase extends Tx_E
 
                $dataMap2 = $this->getMock('Tx_ExtBase_Persistence_Mapper_DataMap', array('getColumnMap', 'getTableName'), array(), '', FALSE);
                $dataMap2->expects($this->at(0))
-                       ->method('getTableName')
-                       ->will($this->returnValue('tx_blogexample_domain_model_author'));
-               $dataMap2->expects($this->at(1))
                        ->method('getColumnMap')
                        ->with($this->equalTo('name'))
                        ->will($this->returnValue($columnMap2));
+               $dataMap2->expects($this->at(1))
+                       ->method('getTableName')
+                       ->will($this->returnValue('tx_blogexample_domain_model_author'));
                
                $mapper->expects($this->at(0))
                        ->method('getDataMap')
@@ -175,13 +167,15 @@ class Tx_ExtBase_Persistence_Mapper_ObjectRelationalMapper_testcase extends Tx_E
                        ->with($this->equalTo('Christopher'))
                        ->will($this->returnValue('"Christopher"'));
                
-               $mapper->fetchByConditions('Tx_BlogExample_Domain_Model_Blog',
+               $query = $mapper->buildQuery('Tx_BlogExample_Domain_Model_Blog',
                        array(
                                'hidden' => FALSE,
                                'author' => array(
                                        'name' => 'Christopher'
                                )
                        ));
+               
+               $this->assertEquals('(tx_blogexample_domain_model_blog.hidden = 0) AND ((tx_blogexample_domain_model_author.name = "Christopher"))', $query);
        }
        
 }
index caed137..31b3d2a 100644 (file)
@@ -27,24 +27,26 @@ class Tx_ExtBase_Persistence_Repository_testcase extends Tx_ExtBase_Base_testcas
                require_once(t3lib_extMgm::extPath('blogexample', 'Classes/Domain/Model/BlogRepository.php'));
        }
 
-       public function test_FindDelegatesToDataMapperFind() {
-        $this->markTestIncomplete('This test has not been fully implemented yet.');            
+       public function test_FindDelegatesToObjectRelationalMapperBuildQueryAndFetch() {
                $repository = new Tx_BlogExample_Domain_Model_BlogRepository();
-               $repository->dataMapper = $this->getMock('Tx_ExtBase_Persistence_Mapper_DataMap', array('findWhere'), array(), '', FALSE);
+               $repository->dataMapper = $this->getMock('Tx_ExtBase_Persistence_Mapper_ObjectRelationalMapper', array('buildQuery', 'fetch'), array(), '', FALSE);
                $repository->dataMapper->expects($this->once())
-                       ->method('findWhere')
+                       ->method('buildQuery')
                        ->with($this->equalTo('Tx_BlogExample_Domain_Model_Blog'), $this->equalTo('foo'))
+                       ->will($this->returnValue('query'));
+               $repository->dataMapper->expects($this->once())
+                       ->method('fetch')
+                       ->with($this->equalTo('Tx_BlogExample_Domain_Model_Blog'), $this->equalTo('query'))
                        ->will($this->returnValue(array()));
                
-               $result = $repository->findWhere('foo');
+               $result = $repository->findByConditions('foo');
                $this->assertEquals(array(), $result);
        }
 
        public function test_MagicFindByPropertyUsesGenericFind() {
-               $this->markTestIncomplete('This test has not been fully implemented yet.');             
-               $repository = $this->getMock('Tx_BlogExample_Domain_Model_BlogRepository', array('find'), array('Tx_BlogExample_Domain_Model_Blog'));
+               $repository = $this->getMock('Tx_BlogExample_Domain_Model_BlogRepository', array('findByConditions'), array('Tx_BlogExample_Domain_Model_Blog'));
                $repository->expects($this->once())
-                       ->method('find')
+                       ->method('findByConditions')
                        ->with($this->equalTo(array('name' => 'foo')))
                        ->will($this->returnValue(array()));
                
@@ -52,10 +54,9 @@ class Tx_ExtBase_Persistence_Repository_testcase extends Tx_ExtBase_Base_testcas
        }
 
        public function test_MagicFindOneByPropertyUsesGenericFind() {
-               $this->markTestIncomplete('This test has not been fully implemented yet.');             
-               $repository = $this->getMock('TX_Blogexample_Domain_BlogRepository', array('find'), array('TX_Blogexample_Domain_Blog'));
+               $repository = $this->getMock('TX_Blogexample_Domain_Model_BlogRepository', array('findByConditions'), array('Tx_BlogExample_Domain_Model_Blog'));
                $repository->expects($this->once())
-                       ->method('find')
+                       ->method('findByConditions')
                        ->with($this->equalTo(array('name' => 'foo')), $this->equalTo(''), $this->equalTo(''), $this->equalTo(1))
                        ->will($this->returnValue(array()));