[FEATURE] Expand db function searchQuery to handle AND and OR constraints
authorNicole Cordes <nicole@cordes.co>
Thu, 22 Nov 2012 16:34:59 +0000 (17:34 +0100)
committerJigal van Hemert <jigal@xs4all.nl>
Sun, 2 Dec 2012 13:40:52 +0000 (14:40 +0100)
The database function searchQuery can build queries for multiple search
words. But those words are expected to be all in the field. Sometimes it
is useful to use an OR constraint. So this function should be extended to
have another parameter to do so.

Change-Id: Ie2d83d5875ce5de6680a4a45b43995be4b48debc
Resolves: #43234
Releases: 6.1
Reviewed-on: http://review.typo3.org/16686
Reviewed-by: Jigal van Hemert
Tested-by: Jigal van Hemert
typo3/sysext/core/Classes/Database/DatabaseConnection.php
typo3/sysext/core/Tests/Unit/Database/DatabaseConnectionTest.php

index 19c011d..4f0a1b1 100644 (file)
@@ -55,6 +55,20 @@ namespace TYPO3\CMS\Core\Database;
  */
 class DatabaseConnection {
 
+       /**
+        * The AND constraint in where clause
+        *
+        * @var string
+        */
+       const AND_Constraint = 'AND';
+
+       /**
+        * The OR constraint in where clause
+        *
+        * @var string
+        */
+       const OR_Constraint = 'OR';
+
        // Set "TRUE" or "1" if you want database errors outputted. Set to "2" if you also want successful database actions outputted.
        /**
         * @todo Define visibility
@@ -587,21 +601,32 @@ class DatabaseConnection {
        }
 
        /**
-        * Returns a WHERE clause which will make an AND search for the words in the $searchWords array in any of the fields in array $fields.
+        * Returns a WHERE clause which will make an AND or OR search for the words in the $searchWords array in any of the fields in array $fields.
         *
         * @param array $searchWords Array of search words
         * @param array $fields Array of fields
         * @param string $table Table in which we are searching (for DBAL detection of quoteStr() method)
+        * @param string $constraint How multiple search words have to match ('AND' or 'OR')
+        *
         * @return string WHERE clause for search
-        * @todo Define visibility
         */
-       public function searchQuery($searchWords, $fields, $table) {
+       public function searchQuery($searchWords, $fields, $table, $constraint = self::AND_Constraint) {
+               switch ($constraint) {
+                       case self::OR_Constraint:
+                               $constraint = 'OR';
+                               break;
+                       default:
+                               $constraint = 'AND';
+                               break;
+               }
+
                $queryParts = array();
                foreach ($searchWords as $sw) {
                        $like = ' LIKE \'%' . $this->quoteStr($sw, $table) . '%\'';
                        $queryParts[] = $table . '.' . implode(($like . ' OR ' . $table . '.'), $fields) . $like;
                }
-               $query = '(' . implode(') AND (', $queryParts) . ')';
+               $query = '(' . implode(') ' . $constraint . ' (', $queryParts) . ')';
+
                return $query;
        }
 
index 717c88a..91b603e 100644 (file)
@@ -94,6 +94,79 @@ class DatabaseConnectionTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
                $this->assertEquals($this->fixture->listQuery('dummy', 44, 'table'), $this->fixture->listQuery('dummy', '44', 'table'));
        }
 
+       ////////////////////////////////
+       // Tests concerning searchQuery
+       ////////////////////////////////
+
+       /**
+        * Data provider for searchQueryCreatesQuery
+        *
+        * @return array
+        */
+       public function searchQueryDataProvider() {
+               return array(
+                       'One search word in one field' => array(
+                               '(pages.title LIKE \'%TYPO3%\')',
+                               array('TYPO3'),
+                               array('title'),
+                               'pages',
+                               'AND'
+                       ),
+
+                       'One search word in multiple fields' => array(
+                               '(pages.title LIKE \'%TYPO3%\' OR pages.keyword LIKE \'%TYPO3%\' OR pages.description LIKE \'%TYPO3%\')',
+                               array('TYPO3'),
+                               array('title', 'keyword', 'description'),
+                               'pages',
+                               'AND'
+                       ),
+
+                       'Multiple search words in one field with AND constraint' => array(
+                               '(pages.title LIKE \'%TYPO3%\') AND (pages.title LIKE \'%is%\') AND (pages.title LIKE \'%great%\')',
+                               array('TYPO3', 'is', 'great'),
+                               array('title'),
+                               'pages',
+                               'AND'
+                       ),
+
+                       'Multiple search words in one field with OR constraint' => array(
+                               '(pages.title LIKE \'%TYPO3%\') OR (pages.title LIKE \'%is%\') OR (pages.title LIKE \'%great%\')',
+                               array('TYPO3', 'is', 'great'),
+                               array('title'),
+                               'pages',
+                               'OR'
+                       ),
+
+                       'Multiple search words in multiple fields with AND constraint' => array(
+                               '(pages.title LIKE \'%TYPO3%\' OR pages.keywords LIKE \'%TYPO3%\' OR pages.description LIKE \'%TYPO3%\') AND ' .
+                                       '(pages.title LIKE \'%is%\' OR pages.keywords LIKE \'%is%\' OR pages.description LIKE \'%is%\') AND ' .
+                                       '(pages.title LIKE \'%great%\' OR pages.keywords LIKE \'%great%\' OR pages.description LIKE \'%great%\')',
+                               array('TYPO3', 'is', 'great'),
+                               array('title', 'keywords', 'description'),
+                               'pages',
+                               'AND'
+                       ),
+
+                       'Multiple search words in multiple fields with OR constraint' => array(
+                               '(pages.title LIKE \'%TYPO3%\' OR pages.keywords LIKE \'%TYPO3%\' OR pages.description LIKE \'%TYPO3%\') OR ' .
+                                       '(pages.title LIKE \'%is%\' OR pages.keywords LIKE \'%is%\' OR pages.description LIKE \'%is%\') OR ' .
+                                       '(pages.title LIKE \'%great%\' OR pages.keywords LIKE \'%great%\' OR pages.description LIKE \'%great%\')',
+                               array('TYPO3', 'is', 'great'),
+                               array('title', 'keywords', 'description'),
+                               'pages',
+                               'OR'
+                       ),
+               );
+       }
+
+       /**
+        * @test
+        * @dataProvider searchQueryDataProvider
+        */
+       public function searchQueryCreatesQuery($expectedResult, $searchWords, $fields, $table, $constraint) {
+               $this->assertSame($expectedResult, $this->fixture->searchQuery($searchWords, $fields, $table, $constraint));
+       }
+
        /////////////////////////////////////////////////
        // Tests concerning escapeStringForLikeComparison
        /////////////////////////////////////////////////