diff --git a/extension/Documentation/Manual.rst b/extension/Documentation/Manual.rst index 71f09e73371b9fc688aa2eb8b2a8f437e488f730..5efb0303ae7b7041fb68c8ffcf01956b8a35ef84 100644 --- a/extension/Documentation/Manual.rst +++ b/extension/Documentation/Manual.rst @@ -136,8 +136,8 @@ Setup a *report* to manage all *forms*: Create a Typo3 page and insert a content 10 { # List of Forms: Do not show this list of forms if there is a form given by SIP. # Table header. - sql = SELECT CONCAT('{{pageId:T}}&form=Form&') as Pagen, '#', 'Name', 'Title', 'Table' FROM (SELECT 1) AS fake WHERE '{{form:SE}}'='' - head = <table class="table table-hover"> + sql = SELECT CONCAT('{{pageId:T}}&form=Form&') as _Pagen, '#', 'Name', 'Title', 'Table', '' FROM (SELECT 1) AS fake WHERE '{{form:SE}}'='' + head = <table class="table table-hover qfq-table-50"> tail = </table> rbeg = <thead><tr> rend = </tr></thead> @@ -146,7 +146,7 @@ Setup a *report* to manage all *forms*: Create a Typo3 page and insert a content 10 { # All forms - sql = SELECT CONCAT('{{pageId:T}}&form=Form&r=', f.id) as Pagee, f.id, f.name, f.title, f.tableName, CONCAT('form=Form&r=', f.id) as Paged FROM Form AS f ORDER BY f.name + sql = SELECT CONCAT('{{pageId:T}}&form=Form&r=', f.id) as _Pagee, f.id, f.name, f.title, f.tableName, CONCAT('form=Form&r=', f.id) as _Paged FROM Form AS f ORDER BY f.name rbeg = <tr> rend = </tr> fbeg = <td> @@ -1593,6 +1593,7 @@ SQL * *typeAheadSql* = `SELECT ... AS 'key', ... AS 'value' WHERE name LIKE ? OR firstName LIKE ? LIMIT 100` * If there is only one column in the SELECT statement, that one will be used and there is no dict (key/value pair). + * If there is no column `key` or no column `value`, than the first column becomes `key` and the second column becomes `value`. * The query will be fired as a 'prepared statement'. * The value, typed by the user, will be replaced on all places where a `?` appears. * All `?` will be automatically surrounded by '%'. Therefore wildcard search is implemented: `... LIKE '%<?>%' ...` diff --git a/extension/qfq/qfq/Database.php b/extension/qfq/qfq/Database.php index bda86fc36bce03a4722331067999e3e24be0e922..f1f5354be9033000f590728816e547da9ec07feb 100644 --- a/extension/qfq/qfq/Database.php +++ b/extension/qfq/qfq/Database.php @@ -656,4 +656,77 @@ class Database { return $feSpecNative; } + /** + * Checks if there is the SQL keyword 'limit' at the end of the SQL statement. + * returns true for '... LIMIT', '.... LIMIT 1, ... LIMIT 1,2, ... LIMIT 1 , 2 + * + * @param $sql + * @return bool + */ + public function hasLimit($sql) { + + $sql = trim(strtolower($sql)); + $arr = explode(' ', $sql); + + $ii = 3; + array_pop($arr); // the last token can't be 'limit' + + while ($ii > 0) { + $item = array_pop($arr); + if ($item === null) { + return false; + } + if ($item != '') { + if ($item == 'limit') { + return true; + } else { + $ii--; + } + } + } + + return false; + } + + /** + * $arr will be converted to a two column array with keys $keyName1 and $keyName2. + * $arr might be one column or more columns. + * Only when $keyName1 and $keyName2 exist, those will be used. Else the first column becomes $keyName1 and the second becomes $keyName2. + * If there is only one column, that column will be doubled. + * + * @param array $arr + * @param string $keyName1 + * @param string $keyName2 + * @return array + */ + public function makeArrayDict(array $arr, $keyName1, $keyName2) { + $keyName = 0; + $valueName = 1; + $new = array(); + + if ($arr == array() || $arr === null) { + return array(); + } + + $row = $arr[0]; + $keys = array_keys($row); + if (count($row) < 2) { + $keyName = $keys[0]; + $valueName = $keys[0]; + } elseif (array_key_exists($keyName1, $row) && array_key_exists($keyName2, $row)) { + $keyName = $keyName1; + $valueName = $keyName2; + } else { + $keyName = $keys[0]; + $valueName = $keys[1]; + } + + $row = array_shift($arr); + while (null !== $row) { + $new[] = [$keyName1 => $row[$keyName], $keyName2 => $row[$valueName]]; + $row = array_shift($arr); + } + + return $new; + } } \ No newline at end of file diff --git a/extension/qfq/qfq/form/TypeAhead.php b/extension/qfq/qfq/form/TypeAhead.php index fbfc280bc7da6a93d0815dcd131b67c73389b7c4..a62511ab5c2b705e998cb52df84b02419404e41c 100644 --- a/extension/qfq/qfq/form/TypeAhead.php +++ b/extension/qfq/qfq/form/TypeAhead.php @@ -8,29 +8,13 @@ namespace qfq; -use TYPO3\CMS\Core\FormProtection\Exception; +//use TYPO3\CMS\Core\FormProtection\Exception; require_once(__DIR__ . '/../store/Sip.php'); -//require_once(__DIR__ . '/store/FillStoreForm.php'); require_once(__DIR__ . '/../store/Session.php'); require_once(__DIR__ . '/../Constants.php'); -//require_once(__DIR__ . '/Save.php'); -//require_once(__DIR__ . '/helper/KeyValueStringParser.php'); require_once(__DIR__ . '/../helper/Ldap.php'); -//require_once(__DIR__ . '/helper/HelperFormElement.php'); -//require_once(__DIR__ . '/exceptions/UserFormException.php'); -//require_once(__DIR__ . '/exceptions/CodeException.php'); -//require_once(__DIR__ . '/exceptions/DbException.php'); -//require_once(__DIR__ . '/exceptions/ErrorHandler.php'); require_once(__DIR__ . '/../Database.php'); -//require_once(__DIR__ . '/Evaluate.php'); -//require_once(__DIR__ . '/BuildFormPlain.php'); -//require_once(__DIR__ . '/BuildFormTable.php'); -//require_once(__DIR__ . '/BuildFormBootstrap.php'); -//require_once(__DIR__ . '/report/Report.php'); -//require_once(__DIR__ . '/BodytextParser.php'); -//require_once(__DIR__ . '/Delete.php'); -//require_once(__DIR__ . '/form/FormAction.php'); class TypeAhead { @@ -89,22 +73,44 @@ class TypeAhead { } /** + * Do a wildcard serach on the prepared statement $config[FE_TYPEAHEAD_SQL]. + * All '?' will be replaced by '%$value%'. + * If there is no 'LIMIT x' defined, append it. + * Returns an dict array [ API_TYPEAHEAD_KEY => key, API_TYPEAHEAD_VALUE => value ] + * * @param array $config - * @param $query - * @return array|int + * @param string $value + * @return array * @throws CodeException * @throws DbException + * @throws UserFormException */ - private function typeAheadSql(array $config, $query) { + private function typeAheadSql(array $config, $value) { $values = array(); - $query = '%' . $query . '%'; - $cnt = substr_count($config[FE_TYPEAHEAD_SQL], '?'); + $sql = $config[FE_TYPEAHEAD_SQL]; + $value = '%' . $value . '%'; + $cnt = substr_count($sql, '?'); + + if ($cnt == 0) { + throw new UserFormException("Missing at least one '?' in " . FE_TYPEAHEAD_SQL); + } + for ($ii = 0; $ii < $cnt; $ii++) { - $values[] = $query; + $values[] = $value; } - return $this->db->sql($config[FE_TYPEAHEAD_SQL], ROW_REGULAR, $values); + if (!$this->db->hasLimit($sql)) { + $sql .= ' LIMIT ' . $config[FE_TYPEAHEAD_LIMIT]; + } + + $arr = $this->db->sql($sql, ROW_REGULAR, $values); + if ($arr == false || count($arr) == 0) { + return array(); + } + + return $this->db->makeArrayDict($arr, API_TYPEAHEAD_KEY, API_TYPEAHEAD_VALUE); } + } \ No newline at end of file diff --git a/extension/qfq/tests/phpunit/DatabaseTest.php b/extension/qfq/tests/phpunit/DatabaseTest.php index 761d86b29e8606360d939ba385aa7cb1b0c2a644..9a98048f35cd5f9bc799cc4c0337cbb9cda7743d 100644 --- a/extension/qfq/tests/phpunit/DatabaseTest.php +++ b/extension/qfq/tests/phpunit/DatabaseTest.php @@ -373,7 +373,9 @@ class DatabaseTest extends AbstractDatabaseTest { $this->assertEquals($expected, $this->db->getTableDefinition('Person')); } - + /** + * + */ public function testSqlKeys() { $keys = array(); @@ -392,6 +394,71 @@ class DatabaseTest extends AbstractDatabaseTest { $this->assertEquals(['id', 'name', 'id'], $keys); } + /** + * + */ + public function testhasLimit() { + + $this->assertEquals(false, $this->db->hasLimit('')); + $this->assertEquals(false, $this->db->hasLimit('SELECT')); + $this->assertEquals(true, $this->db->hasLimit('SELECT ... LIMIT 1')); + $this->assertEquals(true, $this->db->hasLimit('SELECT ... LIMIT 1 ')); + $this->assertEquals(true, $this->db->hasLimit('SELECT ... LIMIT 1 ')); + $this->assertEquals(true, $this->db->hasLimit('SELECT ... LIMIT 1,1')); + $this->assertEquals(true, $this->db->hasLimit('SELECT ... LIMIT 1,1 ')); + $this->assertEquals(true, $this->db->hasLimit('SELECT ... LIMIT 1,1 ')); + $this->assertEquals(true, $this->db->hasLimit('SELECT ... LIMIT 1,1 ')); + $this->assertEquals(true, $this->db->hasLimit('SELECT ... LIMIT 1 ,1 ')); + $this->assertEquals(true, $this->db->hasLimit('SELECT ... LIMIT 1 , 1 ')); + $this->assertEquals(true, $this->db->hasLimit('SELECT ... LIMIT 1 , 1 ')); + $this->assertEquals(true, $this->db->hasLimit('SELECT ... LIMIT 1 , 1 ')); + $this->assertEquals(true, $this->db->hasLimit('SELECT ... LIMIT 1 , 1 ')); + $this->assertEquals(true, $this->db->hasLimit('SELECT ... LIMIT 1 , 1 ')); + $this->assertEquals(true, $this->db->hasLimit('SELECT ... LIMIT 1 , 1 ')); + } + + public function testMakeArrayDict() { + + $this->assertEquals(array(), $this->db->makeArrayDict(array(), 'key', 'value')); + + $arr[] = ['red', 'green']; + $expect[] = ['key' => 'red', 'value' => 'green']; + $this->assertEquals($expect, $this->db->makeArrayDict($arr, 'key', 'value')); + + $arr[] = ['blue', 'orange']; + $expect[] = ['key' => 'blue', 'value' => 'orange']; + $this->assertEquals($expect, $this->db->makeArrayDict($arr, 'key', 'value')); + + $arr = [['key1' => 'red', 'value1' => 'green'], ['key1' => 'blue', 'value1' => 'orange']]; + $this->assertEquals($expect, $this->db->makeArrayDict($arr, 'key', 'value')); + + $arr = [['key' => 'red', 'value1' => 'green'], ['key' => 'blue', 'value1' => 'orange']]; + $this->assertEquals($expect, $this->db->makeArrayDict($arr, 'key', 'value')); + + $arr = [['key1' => 'red', 'value' => 'green'], ['key1' => 'blue', 'value' => 'orange']]; + $this->assertEquals($expect, $this->db->makeArrayDict($arr, 'key', 'value')); + + $arr = [['key' => 'red', 'value' => 'green'], ['key' => 'blue', 'value' => 'orange']]; + $this->assertEquals($expect, $this->db->makeArrayDict($arr, 'key', 'value')); + + $arr = [['value' => 'green', 'key' => 'red'], ['value' => 'orange', 'key' => 'blue']]; + $this->assertEquals($expect, $this->db->makeArrayDict($arr, 'key', 'value')); + + $arr = [['green'], ['orange']]; + $expect = [['key' => 'green', 'value' => 'green'], ['key' => 'orange', 'value' => 'orange']]; + $this->assertEquals($expect, $this->db->makeArrayDict($arr, 'key', 'value')); + + $arr = [['value1' => 'green'], ['value1' => 'orange']]; + $this->assertEquals($expect, $this->db->makeArrayDict($arr, 'key', 'value')); + + $arr = [['key' => 'green'], ['key' => 'orange']]; + $this->assertEquals($expect, $this->db->makeArrayDict($arr, 'key', 'value')); + + $arr = [['value' => 'green'], ['value' => 'orange']]; + $this->assertEquals($expect, $this->db->makeArrayDict($arr, 'key', 'value')); + + } + /** * @throws Exception */