Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
typo3
qfq
Commits
1cf6fd11
Commit
1cf6fd11
authored
Dec 22, 2019
by
Carsten Rose
Browse files
Merge branch 'develop' into 'master'
Develop See merge request
!233
parents
55163328
48dda007
Pipeline
#3105
passed with stages
in 1 minute and 54 seconds
Changes
11
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Documentation-develop/RECORD_LOCK.md
0 → 100644
View file @
1cf6fd11
<!-- -*- markdown -*- -->
# Record locking
## Concept: Late locking
*
A lock is required on first modification.
*
Multiple forms might open the same record, all seems to have write access. The first one who modifies the record
get the lock, all following will switch to form=readonly on their first try to modify the record.
## Lock mode: Exclusive
*
A lock can't be overwritten.
## Lock mode: Advisory
*
A lock can be ignored.
*
Last save win's.
## Lock mode: None
*
No locking at all.
# Workarounds
*
At least one Browser (FF 71, maybe other in the future too), do not allow to wrap the 'leave page' dialog anymore.
This might result in stale lock files (modified record, click on browser tab close or any link), cause the lock
logic does not know that the user leaves the page.
*
Workaround: before 'do you want to leave the page' appears, the lock is released, independent if the user answers 'no'.
As soon as the users modifies the record again, a new lock is acquired. This is better than a stale record lock.
*
Reload a page (F5) on a modified record, opens the form in readonly mode (record lock found).
*
Reason: the lock release is fired by the browser AFTER form load - than the lock-logic reports 'record is already locked'.
*
Workaround: with the above workaround, this does not happen anymore. Nevertheless, a 'tabUniqId' has been implemented.
That one is saved as record lock and a page reload origin can be identified as the same tab as where the lock has been
acquired.
= State Diagram =
See
`Documentation-develop/diagram`
for a state diagram.
Documentation/Manual.rst
View file @
1cf6fd11
...
...
@@ -2255,7 +2255,7 @@ If a timeout expires, the lock becomes invalid. During the next change in a form
A lock is assigned to a record of a table. Multiple forms, with the same primary table, uses the same lock for a given record.
If a `Form` acts on further records (e.g. via FE action), those records are not protected by this basic record locking.
If a `Form` acts on further records (e.g. via FE action), those
further
records are not protected by this basic record locking.
If a user tries to delete a record and another user already owns a lock on that record, the delete action is denied.
...
...
extension/Classes/Core/Constants.php
View file @
1cf6fd11
...
...
@@ -1372,6 +1372,7 @@ const QUERY_TYPE_SELECT = 'type: select,show,describe,explain';
const
QUERY_TYPE_INSERT
=
'type: insert'
;
const
QUERY_TYPE_UPDATE
=
'type: update,replace,delete'
;
const
QUERY_TYPE_CONTROL
=
'type: set'
;
const
QUERY_TYPE_FAILED
=
'type: query failed'
;
//Regexp
//const REGEXP_DATE_INT = '^\d{4}-\d{2}-\d{2}$';
...
...
@@ -1816,7 +1817,7 @@ const DIRTY_API_ACTION_EXTEND = 'extend';
const
LOCK_NOT_FOUND
=
0
;
const
LOCK_FOUND_OWNER
=
1
;
const
LOCK_FOUND_CONFLICT
=
2
;
const
TAB_UNIQ_ID
=
'tabUniqId'
;
//
Currently only only a u
niq identifier: no values stored behind the identifier - might change.
const
TAB_UNIQ_ID
=
'tabUniqId'
;
//
U
niq identifier
per tab
: no values stored behind the identifier - might change.
// AutoCron
const
AUTOCRON_MAX_AGE_MINUTES
=
10
;
...
...
extension/Classes/Core/Database/Database.php
View file @
1cf6fd11
...
...
@@ -181,6 +181,7 @@ class Database {
* @param string $specificMessage
* @param array $keys
* @param array $stat DB_NUM_ROWS | DB_INSERT_ID | DB_AFFECTED_ROWS
* @param array $skipErrno
*
* @return array|int
* SELECT | SHOW | DESCRIBE | EXPLAIN: see $mode
...
...
@@ -190,7 +191,7 @@ class Database {
* @throws \DbException
* @throws \UserFormException
*/
public
function
sql
(
$sql
,
$mode
=
ROW_REGULAR
,
array
$parameterArray
=
array
(),
$specificMessage
=
''
,
array
&
$keys
=
array
(),
array
&
$stat
=
array
())
{
public
function
sql
(
$sql
,
$mode
=
ROW_REGULAR
,
array
$parameterArray
=
array
(),
$specificMessage
=
''
,
array
&
$keys
=
array
(),
array
&
$stat
=
array
(),
array
$skipErrno
=
array
())
{
$queryType
=
''
;
$result
=
array
();
$this
->
closeMysqliStmt
();
...
...
@@ -205,7 +206,7 @@ class Database {
$specificMessage
.
=
" "
;
}
$count
=
$this
->
prepareExecute
(
$sql
,
$parameterArray
,
$queryType
,
$stat
,
$specificMessage
);
$count
=
$this
->
prepareExecute
(
$sql
,
$parameterArray
,
$queryType
,
$stat
,
$specificMessage
,
$skipErrno
);
if
(
$count
===
false
)
{
throw
new
\
DbException
(
$specificMessage
.
"No idea why this error happens - please take some time and check the problem."
,
ERROR_DB_GENERIC_CHECK
);
...
...
@@ -339,23 +340,29 @@ class Database {
* Returns the number of selected rows (SELECT, SHOW, ..) or the affected rows (UPDATE, INSERT). $stat contains
* appropriate num_rows, insert_id or rows_affected.
*
* In case of an error, throw an exception.
* mysqli error code listed in $skipErrno[] do not throw an error.
*
* @param string $sql SQL statement with prepared statement variable.
* @param array $parameterArray parameter array for prepared statement execution.
* @param string $queryType returns QUERY_TYPE_SELECT | QUERY_TYPE_UPDATE | QUERY_TYPE_INSERT, depending on
* the query.
* @param array $stat DB_NUM_ROWS | DB_INSERT_ID | DB_AFFECTED_ROWS
*
* @param string $specificMessage
* @param array $skipErrno
*
* @return int|mixed
* @throws \CodeException
* @throws \DbException
* @throws \UserFormException
*/
private
function
prepareExecute
(
$sql
,
array
$parameterArray
,
&
$queryType
,
array
&
$stat
,
$specificMessage
=
''
)
{
private
function
prepareExecute
(
$sql
,
array
$parameterArray
,
&
$queryType
,
array
&
$stat
,
$specificMessage
=
''
,
array
$skipErrno
=
array
()
)
{
// Only log a modify type statement here if sqlLogMode is (at least) modifyAll
// If sqlLogMode is modify, log the statement after it has been executed and we know if there are affected rows.
$sqlLogMode
=
$this
->
isSqlModify
(
$sql
)
?
SQL_LOG_MODE_MODIFY_ALL
:
SQL_LOG_MODE_ALL
;
$errno
=
0
;
$result
=
0
;
$stat
=
array
();
$errorMsg
[
ERROR_MESSAGE_TO_USER
]
=
empty
(
$specificMessage
)
?
'SQL error'
:
$specificMessage
;
...
...
@@ -372,34 +379,52 @@ class Database {
$this
->
dbLog
(
$sqlLogMode
,
$sql
,
$parameterArray
);
if
(
false
===
(
$this
->
mysqli_stmt
=
$this
->
mysqli
->
prepare
(
$sql
)))
{
$this
->
dbLog
(
SQL_LOG_MODE_ERROR
,
$sql
,
$parameterArray
);
$errorMsg
[
ERROR_MESSAGE_TO_DEVELOPER
]
=
$this
->
getSqlHint
(
$sql
,
$this
->
mysqli
->
error
);
$errorMsg
[
ERROR_MESSAGE_OS
]
=
'[ mysqli: '
.
$this
->
mysqli
->
errno
.
' ] '
.
$this
->
mysqli
->
error
;
throw
new
\
DbException
(
json_encode
(
$errorMsg
),
ERROR_DB_PREPARE
);
if
(
$skipErrno
===
array
()
&&
false
===
array_search
(
$this
->
mysqli
->
errno
,
$skipErrno
))
{
$this
->
dbLog
(
SQL_LOG_MODE_ERROR
,
$sql
,
$parameterArray
);
$errorMsg
[
ERROR_MESSAGE_TO_DEVELOPER
]
=
$this
->
getSqlHint
(
$sql
,
$this
->
mysqli
->
error
);
$errorMsg
[
ERROR_MESSAGE_OS
]
=
'[ mysqli: '
.
$this
->
mysqli
->
errno
.
' ] '
.
$this
->
mysqli
->
error
;
throw
new
\
DbException
(
json_encode
(
$errorMsg
),
ERROR_DB_PREPARE
);
}
else
{
$errno
=
$this
->
mysqli
->
errno
;
}
}
if
(
count
(
$parameterArray
)
>
0
)
{
if
(
false
===
$this
->
prepareBindParam
(
$parameterArray
))
{
$this
->
dbLog
(
SQL_LOG_MODE_ERROR
,
$sql
,
$parameterArray
);
$errorMsg
[
ERROR_MESSAGE_TO_DEVELOPER
]
=
$this
->
getSqlHint
(
$sql
,
$this
->
mysqli
->
error
);
$errorMsg
[
ERROR_MESSAGE_OS
]
=
'[ mysqli: '
.
$this
->
mysqli_stmt
->
errno
.
' ] '
.
$this
->
mysqli_stmt
->
error
;
if
(
$skipErrno
!==
array
()
&&
false
===
array_search
(
$this
->
mysqli
->
errno
,
$skipErrno
))
{
$this
->
dbLog
(
SQL_LOG_MODE_ERROR
,
$sql
,
$parameterArray
);
$errorMsg
[
ERROR_MESSAGE_TO_DEVELOPER
]
=
$this
->
getSqlHint
(
$sql
,
$this
->
mysqli
->
error
);
$errorMsg
[
ERROR_MESSAGE_OS
]
=
'[ mysqli: '
.
$this
->
mysqli_stmt
->
errno
.
' ] '
.
$this
->
mysqli_stmt
->
error
;
throw
new
\
DbException
(
json_encode
(
$errorMsg
),
ERROR_DB_BIND
);
throw
new
\
DbException
(
json_encode
(
$errorMsg
),
ERROR_DB_BIND
);
}
else
{
$errno
=
$this
->
mysqli
->
errno
;
}
}
}
if
(
false
===
$this
->
mysqli_stmt
->
execute
())
{
$this
->
dbLog
(
SQL_LOG_MODE_ERROR
,
$sql
,
$parameterArray
);
$errorMsg
[
ERROR_MESSAGE_TO_DEVELOPER
]
=
$this
->
getSqlHint
(
$sql
,
$this
->
mysqli
->
error
);
$errorMsg
[
ERROR_MESSAGE_OS
]
=
'[ mysqli: '
.
$this
->
mysqli_stmt
->
errno
.
' ] '
.
$this
->
mysqli_stmt
->
error
;
if
(
$skipErrno
!==
array
()
&&
false
===
array_search
(
$this
->
mysqli
->
errno
,
$skipErrno
))
{
$this
->
dbLog
(
SQL_LOG_MODE_ERROR
,
$sql
,
$parameterArray
);
$errorMsg
[
ERROR_MESSAGE_TO_DEVELOPER
]
=
$this
->
getSqlHint
(
$sql
,
$this
->
mysqli
->
error
);
$errorMsg
[
ERROR_MESSAGE_OS
]
=
'[ mysqli: '
.
$this
->
mysqli_stmt
->
errno
.
' ] '
.
$this
->
mysqli_stmt
->
error
;
throw
new
\
DbException
(
json_encode
(
$errorMsg
),
ERROR_DB_EXECUTE
);
throw
new
\
DbException
(
json_encode
(
$errorMsg
),
ERROR_DB_EXECUTE
);
}
else
{
$errno
=
$this
->
mysqli
->
errno
;
}
}
$msg
=
''
;
$count
=
0
;
$command
=
strtoupper
(
explode
(
' '
,
$sql
,
2
)[
0
]);
if
(
$errno
===
0
)
{
$command
=
strtoupper
(
explode
(
' '
,
$sql
,
2
)[
0
]);
}
else
{
$command
=
'FAILED'
;
}
switch
(
$command
)
{
case
'SELECT'
:
case
'SHOW'
:
...
...
@@ -444,6 +469,12 @@ class Database {
$count
=
$stat
[
DB_AFFECTED_ROWS
];
$msg
=
''
;
break
;
case
'FAILED'
:
$queryType
=
QUERY_TYPE_FAILED
;
$stat
[
DB_AFFECTED_ROWS
]
=
0
;
$count
=
-
1
;
$msg
=
'[ mysqli: '
.
$this
->
mysqli_stmt
->
errno
.
' ] '
.
$this
->
mysqli_stmt
->
error
;
break
;
default
:
// Unknown command: treat it as a control command
...
...
extension/Classes/Core/Database/DatabaseUpdate.php
View file @
1cf6fd11
...
...
@@ -373,6 +373,9 @@ class DatabaseUpdate {
* @throws \UserFormException
*/
private
function
dbUpdateStatements
(
$old
,
$new
)
{
$dummy
=
array
();
if
(
$new
==
''
||
$old
===
false
||
$old
===
null
)
{
return
;
}
...
...
@@ -391,7 +394,9 @@ class DatabaseUpdate {
if
(
$apply
)
{
// Play Statements
foreach
(
$sqlStatements
as
$sql
)
{
$this
->
db
->
sql
(
$sql
,
ROW_REGULAR
,
array
(),
"Apply updates to QFQ database. Installed version:
$old
. New QFQ version:
$new
"
);
$this
->
db
->
sql
(
$sql
,
ROW_REGULAR
,
array
(),
"Apply updates to QFQ database. Installed version:
$old
. New QFQ version:
$new
"
,
$dummy
,
$dummy
,
[
1060
]
/* duplicate column name */
);
}
// Remember already applied updates - in case something breaks and the update has to be repeated.
$this
->
setDatabaseVersion
(
$new
);
...
...
extension/Classes/Core/Form/Dirty.php
View file @
1cf6fd11
...
...
@@ -146,7 +146,7 @@ class Dirty {
}
/**
* Tries to get a
'D
irty
R
ecord'. Returns an array (becomes JSON) about success or failure.
* Tries to get a
lock ('d
irty
r
ecord'
)
. Returns an array (becomes JSON) about success or failure.
*
* @param int $recordId
* @param array $tableVars
...
...
extension/Tests/Unit/Core/Database/AbstractDatabaseTest.php
View file @
1cf6fd11
...
...
@@ -63,6 +63,7 @@ abstract class AbstractDatabaseTest extends TestCase {
* @throws \DbException
* @throws \UserFormException
* @throws \UserReportException
* @throws \Exception
*/
protected
function
setUp
()
{
...
...
extension/Tests/Unit/Core/Database/DatabaseFunction.php
View file @
1cf6fd11
...
...
@@ -115,6 +115,7 @@ class DatabaseFunction extends AbstractDatabaseTest {
* @throws \DbException
* @throws \UserFormException
* @throws \UserReportException
* @throws \Exception
*/
protected
function
setUp
()
{
parent
::
setUp
();
...
...
extension/Tests/Unit/Core/Database/DatabaseTest.php
View file @
1cf6fd11
...
...
@@ -15,6 +15,9 @@ require_once(__DIR__ . '/AbstractDatabaseTest.php');
class
DatabaseTest
extends
AbstractDatabaseTest
{
/**
* @throws \CodeException
* @throws \DbException
* @throws \UserFormException
*/
public
function
testFetchAll
()
{
$allRows
=
$this
->
dbArray
[
DB_INDEX_DEFAULT
]
->
sql
(
'SELECT * FROM Person ORDER BY id LIMIT 2'
);
...
...
@@ -25,7 +28,9 @@ class DatabaseTest extends AbstractDatabaseTest {
}
/**
*
* @throws \CodeException
* @throws \DbException
* @throws \UserFormException
*/
public
function
testFetchAllEmpty
()
{
$allRows
=
$this
->
dbArray
[
DB_INDEX_DEFAULT
]
->
sql
(
'SELECT * FROM Person WHERE id=0 ORDER BY id'
);
...
...
@@ -35,6 +40,7 @@ class DatabaseTest extends AbstractDatabaseTest {
/**
* @throws \CodeException
* @throws \DbException
* @throws \UserFormException
*/
public
function
testQuerySimple
()
{
...
...
@@ -65,7 +71,7 @@ class DatabaseTest extends AbstractDatabaseTest {
$this
->
assertEquals
(
1
,
$this
->
store
->
getVar
(
SYSTEM_SQL_COUNT
,
STORE_SYSTEM
));
// Check read rows
$dataArray
=
$this
->
dbArray
[
DB_INDEX_DEFAULT
]
->
sql
(
'SELECT id,name,firstName,adrId,gender,groups FROM Person ORDER BY id LIMIT 2'
);
$dataArray
=
$this
->
dbArray
[
DB_INDEX_DEFAULT
]
->
sql
(
'SELECT id,name,firstName,adrId,gender,
`
groups
`
FROM Person ORDER BY id LIMIT 2'
);
// Check count
$this
->
assertEquals
(
2
,
$this
->
store
->
getVar
(
SYSTEM_SQL_COUNT
,
STORE_SYSTEM
));
...
...
@@ -74,7 +80,7 @@ class DatabaseTest extends AbstractDatabaseTest {
// Check rows
// Same as above, but specify 'ROW_REGULAR'
$dataArray
=
$this
->
dbArray
[
DB_INDEX_DEFAULT
]
->
sql
(
'SELECT id,name,firstName,adrId,gender,groups FROM Person ORDER BY id LIMIT 2'
,
ROW_REGULAR
);
$dataArray
=
$this
->
dbArray
[
DB_INDEX_DEFAULT
]
->
sql
(
'SELECT id,name,firstName,adrId,gender,
`
groups
`
FROM Person ORDER BY id LIMIT 2'
,
ROW_REGULAR
);
$this
->
assertEquals
(
2
,
$this
->
store
->
getVar
(
SYSTEM_SQL_COUNT
,
STORE_SYSTEM
));
// Check rows
$this
->
assertEquals
(
$expected
,
$dataArray
);
...
...
@@ -86,13 +92,13 @@ class DatabaseTest extends AbstractDatabaseTest {
$this
->
assertEquals
(
array
(),
$dataArray
);
// ROW_EXPECT_1
$dataArray
=
$this
->
dbArray
[
DB_INDEX_DEFAULT
]
->
sql
(
'SELECT id,name,firstName,adrId,gender,groups FROM Person WHERE id=1'
,
ROW_EXPECT_1
);
$dataArray
=
$this
->
dbArray
[
DB_INDEX_DEFAULT
]
->
sql
(
'SELECT id,name,firstName,adrId,gender,
`
groups
`
FROM Person WHERE id=1'
,
ROW_EXPECT_1
);
$this
->
assertEquals
(
1
,
$this
->
store
->
getVar
(
SYSTEM_SQL_COUNT
,
STORE_SYSTEM
));
// Check rows
$this
->
assertEquals
(
$expected
[
0
],
$dataArray
);
// ROW_EXPECT_0_1: 1
$dataArray
=
$this
->
dbArray
[
DB_INDEX_DEFAULT
]
->
sql
(
'SELECT id,name,firstName,adrId,gender,groups FROM Person WHERE id=1'
,
ROW_EXPECT_0_1
);
$dataArray
=
$this
->
dbArray
[
DB_INDEX_DEFAULT
]
->
sql
(
'SELECT id,name,firstName,adrId,gender,
`
groups
`
FROM Person WHERE id=1'
,
ROW_EXPECT_0_1
);
$this
->
assertEquals
(
1
,
$this
->
store
->
getVar
(
SYSTEM_SQL_COUNT
,
STORE_SYSTEM
));
// Check rows
$this
->
assertEquals
(
$expected
[
0
],
$dataArray
);
...
...
@@ -104,23 +110,23 @@ class DatabaseTest extends AbstractDatabaseTest {
$this
->
assertEquals
(
array
(),
$dataArray
);
//ROW_EXPECT_GE_1 - one record
$dataArray
=
$this
->
dbArray
[
DB_INDEX_DEFAULT
]
->
sql
(
'SELECT id,name,firstName,adrId,gender,groups FROM Person WHERE id=1'
,
ROW_EXPECT_GE_1
);
$dataArray
=
$this
->
dbArray
[
DB_INDEX_DEFAULT
]
->
sql
(
'SELECT id,name,firstName,adrId,gender,
`
groups
`
FROM Person WHERE id=1'
,
ROW_EXPECT_GE_1
);
$this
->
assertEquals
(
1
,
$this
->
store
->
getVar
(
SYSTEM_SQL_COUNT
,
STORE_SYSTEM
));
// Check rows
$this
->
assertEquals
([
$expected
[
0
]],
$dataArray
);
// ROW_EXPECT_GE_1 - two records
$dataArray
=
$this
->
dbArray
[
DB_INDEX_DEFAULT
]
->
sql
(
'SELECT id,name,firstName,adrId,gender,groups FROM Person ORDER BY id LIMIT 2'
,
ROW_EXPECT_GE_1
);
$dataArray
=
$this
->
dbArray
[
DB_INDEX_DEFAULT
]
->
sql
(
'SELECT id,name,firstName,adrId,gender,
`
groups
`
FROM Person ORDER BY id LIMIT 2'
,
ROW_EXPECT_GE_1
);
$this
->
assertEquals
(
2
,
$this
->
store
->
getVar
(
SYSTEM_SQL_COUNT
,
STORE_SYSTEM
));
// Check rows
$this
->
assertEquals
(
$expected
,
$dataArray
);
// Check Implode: 2 records
$data
=
$this
->
dbArray
[
DB_INDEX_DEFAULT
]
->
sql
(
'SELECT id,name,firstName,adrId,gender,groups FROM Person ORDER BY id LIMIT 2'
,
ROW_IMPLODE_ALL
);
$data
=
$this
->
dbArray
[
DB_INDEX_DEFAULT
]
->
sql
(
'SELECT id,name,firstName,adrId,gender,
`
groups
`
FROM Person ORDER BY id LIMIT 2'
,
ROW_IMPLODE_ALL
);
$this
->
assertEquals
(
implode
(
$expected
[
0
])
.
implode
(
$expected
[
1
]),
$data
);
// Check Implode: 1 record
$data
=
$this
->
dbArray
[
DB_INDEX_DEFAULT
]
->
sql
(
'SELECT id,name,firstName,adrId,gender,groups FROM Person ORDER BY id LIMIT 1'
,
ROW_IMPLODE_ALL
);
$data
=
$this
->
dbArray
[
DB_INDEX_DEFAULT
]
->
sql
(
'SELECT id,name,firstName,adrId,gender,
`
groups
`
FROM Person ORDER BY id LIMIT 1'
,
ROW_IMPLODE_ALL
);
$this
->
assertEquals
(
implode
(
$expected
[
0
]),
$data
);
// Check Implode 0 record
...
...
@@ -142,6 +148,7 @@ class DatabaseTest extends AbstractDatabaseTest {
/**
* @throws \CodeException
* @throws \DbException
* @throws \UserFormException
*/
public
function
testQuerySimpleParameter
()
{
...
...
@@ -153,7 +160,7 @@ class DatabaseTest extends AbstractDatabaseTest {
// Check count
$this
->
assertEquals
(
1
,
$this
->
store
->
getVar
(
SYSTEM_SQL_COUNT
,
STORE_SYSTEM
));
$dataArray
=
$this
->
dbArray
[
DB_INDEX_DEFAULT
]
->
sql
(
'UPDATE Person SET groups = ?'
,
ROW_REGULAR
,
[
'a,b,c'
]);
$dataArray
=
$this
->
dbArray
[
DB_INDEX_DEFAULT
]
->
sql
(
'UPDATE Person SET
`
groups
`
= ?'
,
ROW_REGULAR
,
[
'a,b,c'
]);
$this
->
assertEquals
(
2
,
$this
->
store
->
getVar
(
SYSTEM_SQL_COUNT
,
STORE_SYSTEM
));
$dataArray
=
$this
->
dbArray
[
DB_INDEX_DEFAULT
]
->
sql
(
'INSERT INTO Person (`name`, `firstname`, `groups`) VALUES ( ?, ? ,? )'
,
ROW_REGULAR
,
[
'Meier'
,
'John'
,
'a'
],
'fake'
,
$dummy
,
$stat
);
...
...
@@ -171,6 +178,10 @@ class DatabaseTest extends AbstractDatabaseTest {
/**
* @expectedException DbException
*
* @throws \CodeException
* @throws \DbException
* @throws \UserFormException
*/
public
function
testSqlExceptionExpect0
()
{
$data
=
$this
->
dbArray
[
DB_INDEX_DEFAULT
]
->
sql
(
'SELECT * FROM Person ORDER BY id LIMIT 1'
,
ROW_EXPECT_0
);
...
...
@@ -178,6 +189,10 @@ class DatabaseTest extends AbstractDatabaseTest {
/**
* @expectedException DbException
*
* @throws \CodeException
* @throws \DbException
* @throws \UserFormException
*/
public
function
testSqlExceptionExpect1_0
()
{
$data
=
$this
->
dbArray
[
DB_INDEX_DEFAULT
]
->
sql
(
'SELECT * FROM Person ORDER BY id LIMIT 0'
,
ROW_EXPECT_1
);
...
...
@@ -185,6 +200,10 @@ class DatabaseTest extends AbstractDatabaseTest {
/**
* @expectedException DbException
*
* @throws \CodeException
* @throws \DbException
* @throws \UserFormException
*/
public
function
testSqlExceptionExpect1_2
()
{
$data
=
$this
->
dbArray
[
DB_INDEX_DEFAULT
]
->
sql
(
'SELECT * FROM Person ORDER BY id '
,
ROW_EXPECT_1
);
...
...
@@ -192,6 +211,10 @@ class DatabaseTest extends AbstractDatabaseTest {
/**
* @expectedException DbException
*
* @throws \CodeException
* @throws \DbException
* @throws \UserFormException
*/
public
function
testSqlExceptionExpect01
()
{
$data
=
$this
->
dbArray
[
DB_INDEX_DEFAULT
]
->
sql
(
'SELECT * FROM Person ORDER BY id '
,
ROW_EXPECT_0_1
);
...
...
@@ -199,6 +222,10 @@ class DatabaseTest extends AbstractDatabaseTest {
/**
* @expectedException DbException
*
* @throws \CodeException
* @throws \DbException
* @throws \UserFormException
*/
public
function
testSqlExceptionExpectGE1
()
{
$data
=
$this
->
dbArray
[
DB_INDEX_DEFAULT
]
->
sql
(
'SELECT * FROM Person ORDER BY id LIMIT 0'
,
ROW_EXPECT_GE_1
);
...
...
@@ -206,13 +233,34 @@ class DatabaseTest extends AbstractDatabaseTest {
/**
* @expectedException DbException
*
* @throws \CodeException
* @throws \DbException
* @throws \UserFormException
*/
public
function
testSanitizeException
()
{
$this
->
dbArray
[
DB_INDEX_DEFAULT
]
->
sql
(
'some garbage'
);
}
/**
* Check to skip mysqli errno 1060
*
* @throws \CodeException
* @throws \DbException
* @throws \UserFormException
*/
public
function
testSkipErrno
()
{
$dummy
=
array
();
$result
=
$this
->
dbArray
[
DB_INDEX_DEFAULT
]
->
sql
(
"ALTER TABLE `Person` ADD `name` CHAR(16) NOT NULL AFTER `id`"
,
ROW_REGULAR
,
array
(),
''
,
$dummy
,
$dummy
,
[
1060
]);
$this
->
assertEquals
(
'-1'
,
$result
);
}
/**
* @throws \CodeException
* @throws \DbException
* @throws \UserFormException
*/
public
function
testGetSetValueList
()
{
$valueList
=
$this
->
dbArray
[
DB_INDEX_DEFAULT
]
->
getEnumSetValueList
(
'Person'
,
'gender'
);
...
...
@@ -225,6 +273,9 @@ class DatabaseTest extends AbstractDatabaseTest {
}
/**
* @throws \CodeException
* @throws \DbException
* @throws \UserFormException
*/
public
function
testSelectReturn
()
{
$dummy
=
array
();
...
...
@@ -240,6 +291,9 @@ class DatabaseTest extends AbstractDatabaseTest {
}
/**
* @throws \CodeException
* @throws \DbException
* @throws \UserFormException
*/
public
function
testShowReturn
()
{
$dummy
=
array
();
...
...
@@ -259,6 +313,9 @@ class DatabaseTest extends AbstractDatabaseTest {
}
/**
* @throws \CodeException
* @throws \DbException
* @throws \UserFormException
*/
public
function
testExplainReturn
()
{
$dummy
=
array
();
...
...
@@ -273,12 +330,15 @@ class DatabaseTest extends AbstractDatabaseTest {
}
/**
* @throws \CodeException
* @throws \DbException
* @throws \UserFormException
*/
public
function
testInsertReturn
()
{
$dummy
=
array
();
$stat
=
array
();
$sql
=
"INSERT INTO Person (id, name, firstname, gender, groups) VALUES (NULL, 'Doe', 'Jonni', 'male','')"
;
$sql
=
"INSERT INTO Person (id, name, firstname, gender,
`
groups
`
) VALUES (NULL, 'Doe', 'Jonni', 'male','')"
;
$rc
=
$this
->
dbArray
[
DB_INDEX_DEFAULT
]
->
sql
(
$sql
,
ROW_REGULAR
,
$dummy
,
'fake'
,
$dummy
,
$stat
);
// DB_NUM_ROWS | DB_INSERT_ID | DB_AFFECTED_ROWS
...
...
@@ -289,12 +349,15 @@ class DatabaseTest extends AbstractDatabaseTest {
}
/**
* @throws \CodeException
* @throws \DbException
* @throws \UserFormException
*/
public
function
testUpdateReturn
()
{
$dummy
=
array
();
$stat
=
array
();
$sql
=
"UPDATE Person SET groups = 'a'"
;
$sql
=
"UPDATE Person SET
`
groups
`
= 'a'"
;
$rc
=
$this
->
dbArray
[
DB_INDEX_DEFAULT
]
->
sql
(
$sql
,
ROW_REGULAR
,
$dummy
,
'fake'
,
$dummy
,
$stat
);
...
...
@@ -305,6 +368,7 @@ class DatabaseTest extends AbstractDatabaseTest {
}
/**
* @throws \Exception
*/
public
function
testDeleteReturn
()
{
$dummy
=
array
();
...
...
@@ -325,6 +389,7 @@ class DatabaseTest extends AbstractDatabaseTest {
/**
* @throws \Exception
*/
public
function
testReplaceReturn
()
{
$dummy
=
array
();
...
...
@@ -332,7 +397,7 @@ class DatabaseTest extends AbstractDatabaseTest {
$this
->
executeSQLFile
(
__DIR__
.
'/fixtures/Generic.sql'
,
true
);
$sql
=
"REPLACE INTO Person (id, name, firstname, gender, groups) VALUES (1, 'Doe', 'John', 'male','')"
;
$sql
=
"REPLACE INTO Person (id, name, firstname, gender,
`
groups
`
) VALUES (1, 'Doe', 'John', 'male','')"
;
$rc
=
$this
->
dbArray
[
DB_INDEX_DEFAULT
]
->
sql
(
$sql
,
ROW_REGULAR
,
$dummy
,
'fake'
,
$dummy
,
$stat
);
// DB_NUM_ROWS | DB_INSERT_ID | DB_AFFECTED_ROWS
...
...
@@ -342,7 +407,7 @@ class DatabaseTest extends AbstractDatabaseTest {
$this
->
assertEquals
(
1
,
$rc
);
$sql
=
"REPLACE INTO Person (id, name, firstname, gender, groups) VALUES (100, 'Lincoln', 'Abraham', 'male','')"
;
$sql
=
"REPLACE INTO Person (id, name, firstname, gender,
`
groups
`
) VALUES (100, 'Lincoln', 'Abraham', 'male','')"
;
$rc
=
$this
->
dbArray
[
DB_INDEX_DEFAULT
]
->
sql
(
$sql
,
ROW_REGULAR
,
$dummy
,
'fake'
,
$dummy
,
$stat
);
// DB_NUM_ROWS | DB_INSERT_ID | DB_AFFECTED_ROWS
...
...
@@ -371,7 +436,9 @@ class DatabaseTest extends AbstractDatabaseTest {
}
/**
*
* @throws \CodeException
* @throws \DbException
* @throws \UserFormException
*/
public
function
testSqlKeys
()
{
$keys
=
array
();
...
...
@@ -461,6 +528,7 @@ class DatabaseTest extends AbstractDatabaseTest {
* @throws \DbException
* @throws \UserFormException
* @throws \UserReportException
* @throws \Exception
*/
protected
function
setUp
()
{
parent
::
setUp
();
...
...
javascript/src/QfqForm.js
View file @
1cf6fd11
...
...
@@ -158,11 +158,6 @@ var QfqNS = QfqNS || {};
this
.
form
.
on
(
'
form.validation.failed
'
,
this
.
validationError
);
this
.
form
.
on
(
'
form.validation.success
'
,
this
.
validationSuccess
);
// Solves problem of leaving the page without releasing locks.
window
.
onbeforeunload
=
function
(
e
)
{
that
.
releaseLock
();
};
$
(
"
.radio-inline
"
).
append
(
$
(
"
<span>
"
,
{
class
:
"
checkmark
"
,
aria
:
"
hidden
"
}));
$
(
"
.checkbox-inline
"
).
append
(
$
(
"
<span>
"
,
{
class
:
"
checkmark
"
,
aria
:
"
hidden
"
}));
$
(
"
.radio
"
).
append
(
$
(
"
<span>
"
,
{
class
:
"
checkmark
"
,
aria
:
"
hidden
"
}));
...
...
@@ -581,7 +576,6 @@ var QfqNS = QfqNS || {};
};
n
.
QfqForm
.
prototype
.
callSave
=
function
(
uri
)
{
console
.
log
(
"
target:
"
+
uri
);
if
(
this
.
isFormChanged
())
{
this
.
handleSaveClick
();
this
.
goToAfterSave
=
uri
;
...
...
@@ -1389,9 +1383,6 @@ var QfqNS = QfqNS || {};
*/
n
.
QfqForm
.
prototype
.
goBack
=
function
()
{
var
alert
;
if
(
this
.
lockAcquired
)
{
this
.
releaseLock
();
}
if
(
window
.
history
.
length
<
2
)
{
alert
=
new
n
.
Alert
(
...
...
javascript/src/QfqPage.js
View file @
1cf6fd11
...
...
@@ -81,7 +81,7 @@ var QfqNS = QfqNS || {};
// We have to use 'pagehide'. 'unload' is too late and the ajax request is lost.
window
.
addEventListener
(
"
pagehide
"
,
(
function
(
that
)
{
return
function
()
{
that
.
qfqForm
.
releaseLock
(
fals
e
);
that
.
qfqForm
.
releaseLock
(
tru
e
);
};
})(
this
));
}
catch
(
e
)
{
...
...
@@ -115,18 +115,19 @@ var QfqNS = QfqNS || {};
/**
* @private
*
* Releaselock has to be handled at the pagehide event, not here
*/
n
.
QfqPage
.
prototype
.
beforeUnloadHandler
=
function
(
event
)
{
var
message
=
"
\
0/
"
;<