Commit e615411b authored by Manuel Selbach's avatar Manuel Selbach Committed by Morton Jonuschat
Browse files

[TASK] migrate ext:backend/Utility to doctrine

Convert all SQL statements in backend utility class
to the new Doctrine DBAL based API.

Change-Id: I8febf022d8a5c40756baf051496521885bed1ab1
Releases: master
Resolves: #75650
Reviewed-on: https://review.typo3.org/48040

Reviewed-by: Manuel Selbach's avatarManuel Selbach <manuel_selbach@yahoo.de>
Reviewed-by: Christian Kuhn's avatarChristian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn's avatarChristian Kuhn <lolli@schwarzbu.ch>
Tested-by: default avatarBamboo TYPO3com <info@typo3.com>
Reviewed-by: default avatarMorton Jonuschat <m.jonuschat@mojocode.de>
Tested-by: default avatarMorton Jonuschat <m.jonuschat@mojocode.de>
parent d561ee8c
......@@ -16,7 +16,10 @@ namespace TYPO3\CMS\Backend\Form\FormDataProvider;
use TYPO3\CMS\Backend\Form\Exception\DatabaseRecordException;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Database\DatabaseConnection;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Styleguide\TcaDataGenerator\TableHandler\General;
/**
* Extended by other provider that fetch records from database
......@@ -41,18 +44,8 @@ abstract class AbstractDatabaseRecordProvider
1437656456
);
}
$database = $this->getDatabase();
$tableName = $database->quoteStr($tableName, $tableName);
$where = 'uid=' . (int)$uid . BackendUtility::deleteClause($tableName);
$row = $database->exec_SELECTgetSingleRow('*', $tableName, $where);
if ($row === null) {
// Indicates a program / usage error
throw new \RuntimeException(
'Database error fetching record from tablename ' . $tableName . ' with uid ' . $uid,
1437655862
);
}
if ($row === false) {
$row = $this->getDatabaseRow($tableName, $uid);
if (empty($row)) {
// Indicates a runtime error (eg. record was killed by other editor meanwhile) can be caught elsewhere
// and transformed to a message to the user or something
throw new DatabaseRecordException(
......@@ -63,21 +56,29 @@ abstract class AbstractDatabaseRecordProvider
(int)$uid
);
}
if (!is_array($row)) {
// Database connection behaves weird ...
throw new \UnexpectedValueException(
'Database exec_SELECTgetSingleRow() did not return error type or result',
1437656323
);
}
return $row;
}
/**
* @return DatabaseConnection
* Retrieve the requested row from the database
*
* @param string $tableName
* @param int $uid
* @return array
*/
protected function getDatabase()
protected function getDatabaseRow(string $tableName, int $uid): array
{
return $GLOBALS['TYPO3_DB'];
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($tableName);
$queryBuilder->getRestrictions()
->removeAll()
->add(GeneralUtility::makeInstance(DeletedRestriction::class));
$row = $queryBuilder->select('*')
->from($tableName)
->where($queryBuilder->expr()->eq('uid', (int)$uid))
->execute()
->fetch();
return $row ?: [];
}
}
......@@ -17,7 +17,11 @@ namespace TYPO3\CMS\Backend\Form\FormDataProvider;
use TYPO3\CMS\Backend\Module\ModuleLoader;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Database\DatabaseConnection;
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
use TYPO3\CMS\Core\Database\Query\QueryHelper;
use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
use TYPO3\CMS\Core\Database\RelationHandler;
use TYPO3\CMS\Core\Imaging\IconFactory;
use TYPO3\CMS\Core\Messaging\FlashMessage;
......@@ -417,7 +421,6 @@ abstract class AbstractItemProvider
}
$languageService = $this->getLanguageService();
$database = $this->getDatabaseConnection();
$foreignTable = $result['processedTca']['columns'][$fieldName]['config']['foreign_table'];
......@@ -429,11 +432,11 @@ abstract class AbstractItemProvider
);
}
$foreignTableQueryArray = $this->buildForeignTableQuery($result, $fieldName);
$queryResource = $database->exec_SELECT_queryArray($foreignTableQueryArray);
$queryBuilder = $this->buildForeignTableQueryBuilder($result, $fieldName);
$queryResult = $queryBuilder->execute();
// Early return on error with flash message
$databaseError = $database->sql_error();
$databaseError = $queryResult->errorInfo();
if (!empty($databaseError)) {
$msg = $databaseError . '. ';
$msg .= $languageService->sL('LLL:EXT:lang/locallang_core.xlf:error.database_schema_mismatch');
......@@ -445,7 +448,7 @@ abstract class AbstractItemProvider
/** @var $defaultFlashMessageQueue FlashMessageQueue */
$defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
$defaultFlashMessageQueue->enqueue($flashMessage);
$database->sql_free_result($queryResource);
$queryResult->closeCursor();
return $items;
}
......@@ -457,7 +460,7 @@ abstract class AbstractItemProvider
$iconFactory = GeneralUtility::makeInstance(IconFactory::class);
while ($foreignRow = $database->sql_fetch_assoc($queryResource)) {
while ($foreignRow = $queryResult->fetch()) {
BackendUtility::workspaceOL($foreignTable, $foreignRow);
if (is_array($foreignRow)) {
// If the foreign table sets selicon_field, this field can contain an image
......@@ -487,8 +490,6 @@ abstract class AbstractItemProvider
}
}
$database->sql_free_result($queryResource);
return $items;
}
......@@ -899,47 +900,77 @@ abstract class AbstractItemProvider
*
* @param array $result Result array
* @param string $localFieldName Current handle field name
* @return array Query array ready to be executed via Database->exec_SELECT_queryArray()
* @return QueryBuilder
*/
protected function buildForeignTableQuery(array $result, $localFieldName)
protected function buildForeignTableQueryBuilder(array $result, string $localFieldName): QueryBuilder
{
$backendUser = $this->getBackendUser();
$foreignTableName = $result['processedTca']['columns'][$localFieldName]['config']['foreign_table'];
$foreignTableClauseArray = $this->processForeignTableClause($result, $foreignTableName, $localFieldName);
$queryArray = [];
$queryArray['SELECT'] = BackendUtility::getCommonSelectFields($foreignTableName, $foreignTableName . '.');
$fieldList = BackendUtility::getCommonSelectFields($foreignTableName, $foreignTableName . '.');
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
->getQueryBuilderForTable($foreignTableName);
$queryBuilder->getRestrictions()
->removeAll()
->add(GeneralUtility::makeInstance(DeletedRestriction::class));
$queryBuilder
->select(...GeneralUtility::trimExplode(',', $fieldList, true))
->from($foreignTableName);
if (!empty($foreignTableClauseArray['GROUPBY'])) {
$queryBuilder->groupBy($foreignTableClauseArray['GROUPBY']);
}
if (!empty($foreignTableClauseArray['ORDERBY'])) {
foreach ($foreignTableClauseArray['ORDERBY'] as $orderPair) {
list($fieldName, $order) = $orderPair;
$queryBuilder->addOrderBy($fieldName, $order);
}
}
if (!empty($foreignTableClauseArray['LIMIT'])) {
if (!empty($foreignTableClauseArray['LIMIT'][1])) {
$queryBuilder->setMaxResults($foreignTableClauseArray['LIMIT'][1]);
$queryBuilder->setFirstResult($foreignTableClauseArray['LIMIT'][0]);
} elseif (!empty($foreignTableClauseArray['LIMIT'][0])) {
$queryBuilder->setMaxResults($foreignTableClauseArray['LIMIT'][0]);
}
}
// rootLevel = -1 means that elements can be on the rootlevel OR on any page (pid!=-1)
// rootLevel = 0 means that elements are not allowed on root level
// rootLevel = 1 means that elements are only on the root level (pid=0)
$rootLevel = 0;
if (isset($GLOBALS['TCA'][$foreignTableName]['ctrl']['rootLevel'])) {
$rootLevel = $GLOBALS['TCA'][$foreignTableName]['ctrl']['rootLevel'];
$rootLevel = (int)$GLOBALS['TCA'][$foreignTableName]['ctrl']['rootLevel'];
}
$deleteClause = BackendUtility::deleteClause($foreignTableName);
if ($rootLevel == 1 || $rootLevel == -1) {
$pidWhere = $foreignTableName . '.pid' . (($rootLevel == -1) ? '<>-1' : '=0');
$queryArray['FROM'] = $foreignTableName;
$queryArray['WHERE'] = $pidWhere . $deleteClause . $foreignTableClauseArray['WHERE'];
if ($rootLevel === -1) {
$queryBuilder->where($queryBuilder->expr()->neq($foreignTableName . '.pid', -1));
} elseif ($rootLevel === 1) {
$queryBuilder->where($queryBuilder->expr()->neq($foreignTableName . '.pid', 0));
} else {
$pageClause = $backendUser->getPagePermsClause(1);
if ($foreignTableName === 'pages') {
$queryArray['FROM'] = 'pages';
$queryArray['WHERE'] = '1=1' . $deleteClause . ' AND' . $pageClause . $foreignTableClauseArray['WHERE'];
} else {
$queryArray['FROM'] = $foreignTableName . ', pages';
$queryArray['WHERE'] = 'pages.uid=' . $foreignTableName . '.pid AND pages.deleted=0'
. $deleteClause . ' AND' . $pageClause . $foreignTableClauseArray['WHERE'];
$queryBuilder->where(
$backendUser->getPagePermsClause(1),
$foreignTableClauseArray['WHERE']
);
if ($foreignTableName !== 'pages') {
$queryBuilder
->from('pages')
->andWhere(
$queryBuilder->expr()->eq(
'pages.uid',
$queryBuilder->quoteIdentifier($foreignTableName . '.pid')
)
);
}
}
$queryArray['GROUPBY'] = $foreignTableClauseArray['GROUPBY'];
$queryArray['ORDERBY'] = $foreignTableClauseArray['ORDERBY'];
$queryArray['LIMIT'] = $foreignTableClauseArray['LIMIT'];
return $queryArray;
return $queryBuilder;
}
/**
......@@ -960,7 +991,7 @@ abstract class AbstractItemProvider
*/
protected function processForeignTableClause(array $result, $foreignTableName, $localFieldName)
{
$database = $this->getDatabaseConnection();
$connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($foreignTableName);
$localTable = $result['tableName'];
$effectivePid = $result['effectivePid'];
......@@ -986,10 +1017,10 @@ abstract class AbstractItemProvider
$rowFieldValue = $rowFieldValue[0];
}
if (substr($whereClauseParts[0], -1) === '\'' && $whereClauseSubParts[1][0] === '\'') {
$whereClauseParts[$key] = $database->quoteStr($rowFieldValue, $foreignTableName) . $whereClauseSubParts[1];
} else {
$whereClauseParts[$key] = $database->fullQuoteStr($rowFieldValue, $foreignTableName) . $whereClauseSubParts[1];
$whereClauseParts[0] = substr($whereClauseParts[0], 0, -1);
$whereClauseSubParts[1] = substr($whereClauseSubParts[1], 1);
}
$whereClauseParts[$key] = $connection->quote($rowFieldValue) . $whereClauseSubParts[1];
}
}
$foreignTableClause = implode('', $whereClauseParts);
......@@ -1038,11 +1069,11 @@ abstract class AbstractItemProvider
$pageTsConfigString = '';
if ($result['pageTsConfig']['flexHack.']['PAGE_TSCONFIG_STR']) {
// @deprecated since TYPO3 v8, will be removed in TYPO3 v9 - see also the flexHack part in TcaFlexProcess
$pageTsConfigString = $result['pageTsConfig']['flexHack.']['PAGE_TSCONFIG_STR'];
$pageTsConfigString = $connection->quote($result['pageTsConfig']['flexHack.']['PAGE_TSCONFIG_STR']);
}
if ($result['pageTsConfig']['TCEFORM.'][$localTable . '.'][$localFieldName . '.']['PAGE_TSCONFIG_STR']) {
$pageTsConfigString = $result['pageTsConfig']['TCEFORM.'][$localTable . '.'][$localFieldName . '.']['PAGE_TSCONFIG_STR'];
$pageTsConfigString = $database->quoteStr($pageTsConfigString, $foreignTableName);
$pageTsConfigString = $connection->quote($pageTsConfigString);
}
$foreignTableClause = str_replace(
......@@ -1052,6 +1083,7 @@ abstract class AbstractItemProvider
'###SITEROOT###',
'###PAGE_TSCONFIG_ID###',
'###PAGE_TSCONFIG_IDLIST###',
'\'###PAGE_TSCONFIG_STR###\'',
'###PAGE_TSCONFIG_STR###'
],
[
......@@ -1060,6 +1092,7 @@ abstract class AbstractItemProvider
$siteRootUid,
$pageTsConfigId,
$pageTsConfigIdList,
$pageTsConfigString,
$pageTsConfigString
],
$foreignTableClause
......@@ -1078,23 +1111,23 @@ abstract class AbstractItemProvider
// Find LIMIT
$reg = [];
if (preg_match('/^(.*)[[:space:]]+LIMIT[[:space:]]+([[:alnum:][:space:],._]+)$/i', $foreignTableClause, $reg)) {
$foreignTableClauseArray['LIMIT'] = trim($reg[2]);
$foreignTableClauseArray['LIMIT'] = GeneralUtility::intExplode(',', trim($reg[2]), true);
$foreignTableClause = $reg[1];
}
// Find ORDER BY
$reg = [];
if (preg_match('/^(.*)[[:space:]]+ORDER[[:space:]]+BY[[:space:]]+([[:alnum:][:space:],._]+)$/i', $foreignTableClause, $reg)) {
$foreignTableClauseArray['ORDERBY'] = trim($reg[2]);
$foreignTableClauseArray['ORDERBY'] = QueryHelper::parseOrderBy(trim($reg[2]));
$foreignTableClause = $reg[1];
}
// Find GROUP BY
$reg = [];
if (preg_match('/^(.*)[[:space:]]+GROUP[[:space:]]+BY[[:space:]]+([[:alnum:][:space:],._]+)$/i', $foreignTableClause, $reg)) {
$foreignTableClauseArray['GROUPBY'] = trim($reg[2]);
$foreignTableClauseArray['GROUPBY'] = QueryHelper::parseGroupBy(trim($reg[2]));
$foreignTableClause = $reg[1];
}
// Rest is assumed to be "WHERE" clause
$foreignTableClauseArray['WHERE'] = $foreignTableClause;
$foreignTableClauseArray['WHERE'] = QueryHelper::stripLogicalOperatorPrefix($foreignTableClause);
return $foreignTableClauseArray;
}
......
......@@ -52,11 +52,11 @@ class DatabaseLanguageRows implements FormDataProviderInterface
}
// Default language record of localized record
$defaultLanguageRow = BackendUtility::getRecordWSOL(
$defaultLanguageRow = $this->getRecordWorkspaceOverlay(
$tableNameWithDefaultRecords,
(int)$result['databaseRow'][$fieldWithUidOfDefaultRecord]
);
if (!is_array($defaultLanguageRow)) {
if (empty($defaultLanguageRow)) {
throw new DatabaseDefaultLanguageException(
'Default language record with id ' . (int)$result['databaseRow'][$fieldWithUidOfDefaultRecord]
. ' not found in table ' . $result['tableName'] . ' while editing record ' . $result['databaseRow']['uid'],
......@@ -95,7 +95,10 @@ class DatabaseLanguageRows implements FormDataProviderInterface
$additionalLanguageUid
);
if (!empty($translationInfo['translations'][$additionalLanguageUid]['uid'])) {
$record = BackendUtility::getRecordWSOL($result['tableName'], (int)$translationInfo['translations'][$additionalLanguageUid]['uid']);
$record = $this->getRecordWorkspaceOverlay(
$result['tableName'],
(int)$translationInfo['translations'][$additionalLanguageUid]['uid']
);
$result['additionalLanguageRows'][$additionalLanguageUid] = $record;
}
}
......@@ -105,4 +108,18 @@ class DatabaseLanguageRows implements FormDataProviderInterface
return $result;
}
/**
* Retrieve the requested row from the database
*
* @param string $tableName
* @param int $uid
* @return array
*/
protected function getRecordWorkspaceOverlay(string $tableName, int $uid): array
{
$row = BackendUtility::getRecordWSOL($tableName, $uid);
return $row ?: [];
}
}
......@@ -15,8 +15,10 @@ namespace TYPO3\CMS\Backend\Form\FormDataProvider;
*/
use TYPO3\CMS\Backend\Form\FormDataProviderInterface;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Database\DatabaseConnection;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Database\Query\Restriction\BackendWorkspaceRestriction;
use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* Fill the "pageLanguageOverlayRows" part of the result array
......@@ -36,33 +38,32 @@ class DatabasePageLanguageOverlayRows implements FormDataProviderInterface
return $result;
}
$database = $this->getDatabase();
$dbRows = $database->exec_SELECTgetRows(
'*',
'pages_language_overlay',
'pid=' . (int)$result['effectivePid']
. BackendUtility::deleteClause('pages_language_overlay')
. BackendUtility::versioningPlaceholderClause('pages_language_overlay')
);
if ($dbRows === null) {
throw new \UnexpectedValueException(
'Database query error ' . $database->sql_error(),
1440777705
);
}
$result['pageLanguageOverlayRows'] = $dbRows;
$result['pageLanguageOverlayRows'] = $this->getDatabaseRows((int)$result['effectivePid']);
return $result;
}
/**
* @return DatabaseConnection
* Retrieve the requested overlay row from the database
*
* @param int $pid
* @return array
*/
protected function getDatabase()
protected function getDatabaseRows(int $pid): array
{
return $GLOBALS['TYPO3_DB'];
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
->getQueryBuilderForTable('pages_language_overlay');
$queryBuilder->getRestrictions()
->removeAll()
->add(GeneralUtility::makeInstance(DeletedRestriction::class))
->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
$rows = $queryBuilder->select('*')
->from('pages_language_overlay')
->where($queryBuilder->expr()->eq('pid', $pid))
->execute()
->fetchAll();
return $rows;
}
}
......@@ -100,7 +100,7 @@ class DatabaseRecordTypeValue implements FormDataProviderInterface
$foreignUid = str_replace($foreignTable . '_', '', $foreignUid);
}
// Fetch field of this foreign row from db
$foreignRow = BackendUtility::getRecord($foreignTable, $foreignUid, $foreignTableTypeField);
$foreignRow = $this->getDatabaseRow($foreignTable, $foreignUid, $foreignTableTypeField);
if ($foreignRow[$foreignTableTypeField]) {
// @todo: It might be necessary to fetch the value from default language record as well here,
// @todo: this was buggy in the "old" implementation and never worked. It was therefor left out here for now.
......@@ -133,6 +133,20 @@ class DatabaseRecordTypeValue implements FormDataProviderInterface
return $result;
}
/**
* Retrieve the requested row from the database
*
* @param string $tableName
* @param int $uid
* @param string $fieldName
* @return array
*/
protected function getDatabaseRow(string $tableName, int $uid, string $fieldName): array
{
$row = BackendUtility::getRecord($tableName, $uid, $fieldName);
return $row ?: [];
}
/**
* If a localized row is handled, the field value of the default language record
* is used instead if tca is configured as "exclude" or "mergeIfNotBlank" with
......
......@@ -81,11 +81,13 @@ class ConditionMatcherTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
*/
private function setUpDatabaseMockForDeterminePageId()
{
$GLOBALS['TYPO3_DB'] = $this->getMockBuilder(\TYPO3\CMS\Core\Database\DatabaseConnection::class)
->setMethods(array('exec_SELECTquery', 'sql_fetch_assoc', 'sql_free_result'))
$this->matchCondition = $this->getMockBuilder(\TYPO3\CMS\Backend\Configuration\TypoScript\ConditionMatching\ConditionMatcher::class)
->setMethods(['determineRootline', 'determinePageId'])
->disableOriginalConstructor()
->getMock();
$GLOBALS['TYPO3_DB']->expects($this->any())->method('exec_SELECTquery')->will($this->returnCallback(array($this, 'determinePageIdByRecordDatabaseExecuteCallback')));
$GLOBALS['TYPO3_DB']->expects($this->any())->method('sql_fetch_assoc')->will($this->returnCallback(array($this, 'determinePageIdByRecordDatabaseFetchCallback')));
$this->matchCondition->expects($this->once())->method('determineRootline');
$this->matchCondition->expects($this->once())->method('determinePageId')->willReturn(999);
}
/**
......@@ -910,46 +912,6 @@ class ConditionMatcherTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
$this->assertEquals(999, $this->matchCondition->getPageId());
}
/**
* Callback method for pageIdCanBeDetermined test cases.
* Simulates TYPO3_DB->exec_SELECTquery().
*
* @param string $fields
* @param string $table
* @param string $where
* @return mixed
*/
public function determinePageIdByRecordDatabaseExecuteCallback($fields, $table, $where)
{
if ($table === $this->testTableName) {
return array(
'scope' => $this->testTableName,
'data' => array(
'pid' => 999,
'uid' => 998
)
);
} else {
return false;
}
}
/**
* Callback method for pageIdCanBeDetermined test cases.
* Simulates TYPO3_DB->sql_fetch_assoc().
*
* @param mixed $resource
* @return mixed
*/
public function determinePageIdByRecordDatabaseFetchCallback($resource)
{
if (is_array($resource) && $resource['scope'] === $this->testTableName) {
return $resource['data'];
} else {
return false;
}
}
/**
* @test
*/
......
......@@ -14,7 +14,6 @@ namespace TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider;
* The TYPO3 project - inspiring people to share!
*/
use Prophecy\Argument;
use Prophecy\Prophecy\ObjectProphecy;
use TYPO3\CMS\Backend\Form\Exception\DatabaseRecordException;
use TYPO3\CMS\Backend\Form\FormDataProvider\DatabaseEditRow;
......@@ -27,7 +26,7 @@ use TYPO3\CMS\Core\Tests\UnitTestCase;
class DatabaseEditRowTest extends UnitTestCase
{
/**
* @var DatabaseEditRow
* @var DatabaseEditRow|\PHPUnit_Framework_MockObject_MockObject
*/
protected $subject;
......@@ -41,7 +40,9 @@ class DatabaseEditRowTest extends UnitTestCase
$this->dbProphecy = $this->prophesize(DatabaseConnection::class);
$GLOBALS['TYPO3_DB'] = $this->dbProphecy->reveal();
$this->subject = new DatabaseEditRow();
$this->subject = $this->getMockBuilder(DatabaseEditRow::class)
->setMethods(['getDatabaseRow'])
->getMock();
}
/**
......@@ -58,9 +59,7 @@ class DatabaseEditRowTest extends UnitTestCase
'uid' => 10,
'pid' => 123
];
$this->dbProphecy->quoteStr($input['tableName'], $input['tableName'])->willReturn($input['tableName']);
$this->dbProphecy->exec_SELECTgetSingleRow('*', 'tt_content', 'uid=' . $input['vanillaUid'])->willReturn($resultRow);
$this->dbProphecy->exec_SELECTgetSingleRow(Argument::cetera())->willReturn([]);
$this->subject->expects($this->once())->method('getDatabaseRow')->willReturn($resultRow);
$result = $this->subject->addData($input);
......@@ -80,8 +79,7 @@ class DatabaseEditRowTest extends UnitTestCase
$resultRow = [
'uid' => 10,