2 namespace TYPO3\CMS\Extbase\Persistence\Generic\Storage;
18 use TYPO3\CMS\Extbase\Persistence\Generic\Qom;
147 $this->databaseHandle =
$GLOBALS[
'TYPO3_DB'];
157 $this->tableColumnCache = $this->cacheManager->getCache(
'extbase_typo3dbbackend_tablecolumns');
158 $this->queryCache = $this->cacheManager->getCache(
'extbase_typo3dbbackend_queries');
169 public function addRow($tableName, array $fieldValues, $isRelation =
false)
171 if (isset($fieldValues[
'uid'])) {
172 unset($fieldValues[
'uid']);
175 $this->databaseHandle->exec_INSERTquery($tableName, $fieldValues);
177 $uid = $this->databaseHandle->sql_insert_id();
194 public function updateRow($tableName, array $fieldValues, $isRelation =
false)
196 if (!isset($fieldValues[
'uid'])) {
197 throw new \InvalidArgumentException(
'The given row must contain a value for "uid".');
200 $uid = (int)$fieldValues[
'uid'];
201 unset($fieldValues[
'uid']);
203 $updateSuccessful = $this->databaseHandle->exec_UPDATEquery($tableName,
'uid = ' . $uid, $fieldValues);
210 return $updateSuccessful;
223 if (!isset($fieldValues[
'uid_local']) && !isset($fieldValues[
'uid_foreign'])) {
224 throw new \InvalidArgumentException(
225 'The given fieldValues must contain a value for "uid_local" and "uid_foreign".', 1360500126
229 $where[
'uid_local'] = (int)$fieldValues[
'uid_local'];
230 $where[
'uid_foreign'] = (int)$fieldValues[
'uid_foreign'];
231 unset($fieldValues[
'uid_local']);
232 unset($fieldValues[
'uid_foreign']);
234 if (!empty($fieldValues[
'tablenames'])) {
235 $where[
'tablenames'] = $fieldValues[
'tablenames'];
236 unset($fieldValues[
'tablenames']);
238 if (!empty($fieldValues[
'fieldname'])) {
239 $where[
'fieldname'] = $fieldValues[
'fieldname'];
240 unset($fieldValues[
'fieldname']);
243 $updateSuccessful = $this->databaseHandle->exec_UPDATEquery(
250 return $updateSuccessful;
261 public function removeRow($tableName, array $where, $isRelation =
false)
263 $deleteSuccessful = $this->databaseHandle->exec_DELETEquery(
269 if (!$isRelation && isset($where[
'uid'])) {
273 return $deleteSuccessful;
286 $result = $this->databaseHandle->exec_SELECTgetSingleRow(
291 $columnName .
' DESC',
308 $row = $this->databaseHandle->exec_SELECTgetSingleRow(
315 return $row ?:
false;
328 $whereStatement = array();
330 foreach ($where as $fieldName => $fieldValue) {
331 $whereStatement[] = $fieldName .
' = ' . $this->databaseHandle->fullQuoteStr($fieldValue, $tableName);
334 return implode(
' AND ', $whereStatement);
346 if ($statement instanceof Qom\
Statement) {
366 'selectFields' => implode(
' ', $statementParts[
'keywords']) .
' ' . implode(
',', $statementParts[
'fields']),
367 'fromTable' => implode(
' ', $statementParts[
'tables']) .
' ' . implode(
' ', $statementParts[
'unions']),
368 'whereClause' => (!empty($statementParts[
'where']) ? implode(
'', $statementParts[
'where']) :
'1=1')
369 . (!empty($statementParts[
'additionalWhereClause'])
370 ?
' AND ' . implode(
' AND ', $statementParts[
'additionalWhereClause'])
373 'orderBy' => (!empty($statementParts[
'orderings']) ? implode(
', ', $statementParts[
'orderings']) :
''),
374 'limit' => ($statementParts[
'offset'] ? $statementParts[
'offset'] .
', ' :
'')
375 . ($statementParts[
'limit'] ? $statementParts[
'limit'] :
'')
407 $rows = $this->databaseHandle->exec_SELECTgetRows(
408 $queryCommandParameters[
'selectFields'],
409 $queryCommandParameters[
'fromTable'],
410 $queryCommandParameters[
'whereClause'],
412 $queryCommandParameters[
'orderBy'],
413 $queryCommandParameters[
'limit']
430 $preparedStatement = $this->databaseHandle->prepare_SELECTquery(
431 $queryCommandParameters[
'selectFields'],
432 $queryCommandParameters[
'fromTable'],
433 $queryCommandParameters[
'whereClause'],
435 $queryCommandParameters[
'orderBy'],
436 $queryCommandParameters[
'limit']
439 $preparedStatement->execute($parameters);
440 $rows = $preparedStatement->fetchAll();
442 $preparedStatement->free();
454 $realStatement = $statement->getStatement();
455 $parameters = $statement->getBoundVariables();
457 if ($realStatement instanceof \TYPO3\CMS\Core\Database\PreparedStatement) {
458 $realStatement->execute($parameters);
459 $rows = $realStatement->fetchAll();
461 $realStatement->free();
463 $result = $this->databaseHandle->sql_query($realStatement);
467 while ($row = $this->databaseHandle->sql_fetch_assoc($result)) {
468 if (is_array($row)) {
472 $this->databaseHandle->sql_free_result($result);
488 throw new \TYPO3\CMS\Extbase\Persistence\Generic\Storage\Exception\BadConstraintException(
'Could not execute count on queries with a constraint of type TYPO3\\CMS\\Extbase\\Persistence\\Generic\\Qom\\Statement', 1256661045);
494 if (isset($statementParts[
'keywords'][
'distinct'])) {
495 $fields =
'DISTINCT ' . reset($statementParts[
'tables']) .
'.uid';
499 $count = $this->databaseHandle->exec_SELECTcountRows(
501 $queryCommandParameters[
'fromTable'],
502 $queryCommandParameters[
'whereClause']
506 if ($statementParts[
'offset']) {
507 $count -= $statementParts[
'offset'];
510 if ($statementParts[
'limit']) {
511 $count = min($count, $statementParts[
'limit']);
514 return (
int)max(0, $count);
536 list($queryHash, $parameters) = $this->queryParser->preparseQuery($query);
538 if ($query->getQuerySettings()->getUseQueryCache()) {
540 if ($queryHash && !$statementParts) {
541 $statementParts = $this->queryParser->parseQuery($query);
545 $statementParts = $this->queryParser->parseQuery($query);
548 if (!$statementParts) {
549 throw new \RuntimeException(
'Your query could not be built.', 1394453197);
552 $this->queryParser->addDynamicQueryParts($query->getQuerySettings(), $statementParts);
555 $statementParts[
'limit'] = ((int)$query->getLimit() ?: null);
556 $statementParts[
'offset'] = ((int)$query->getOffset() ?: null);
558 if ($resolveParameterPlaceholders ===
true) {
562 return array($statementParts, $parameters);
574 $tableName = reset($statementParts[
'tables']) ?:
'foo';
576 foreach ($parameters as $parameterPlaceholder => $parameter) {
577 $parameter = $this->dataMapper->getPlainValue($parameter, null, array($this,
'quoteTextValueCallback'), array(
'tablename' => $tableName));
578 $statementParts[
'where'] = str_replace($parameterPlaceholder, $parameter, $statementParts[
'where']);
581 return $statementParts;
593 return $this->databaseHandle->fullQuoteStr($value, $parameters[
'tablename']);
606 $parameters = array();
607 $dataMap = $this->dataMapper->getDataMap(get_class($object));
608 $properties = $object->_getProperties();
609 foreach ($properties as $propertyName => $propertyValue) {
611 if ($dataMap->isPersistableProperty($propertyName) && $propertyName !==
'uid' && $propertyName !==
'pid' && $propertyName !==
'isClone') {
612 if ($propertyValue === null) {
613 $fields[] = $dataMap->getColumnMap($propertyName)->getColumnName() .
' IS NULL';
615 $fields[] = $dataMap->getColumnMap($propertyName)->getColumnName() .
'=?';
616 $parameters[] = $this->dataMapper->getPlainValue($propertyValue);
621 $sql[
'additionalWhereClause'] = array();
622 $tableName = $dataMap->getTableName();
624 $statement =
'SELECT * FROM ' . $tableName;
625 $statement .=
' WHERE ' . implode(
' AND ', $fields);
626 if (!empty($sql[
'additionalWhereClause'])) {
627 $statement .=
' AND ' . implode(
' AND ', $sql[
'additionalWhereClause']);
631 $res = $this->databaseHandle->sql_query($statement);
633 $row = $this->databaseHandle->sql_fetch_assoc($res);
634 if ($row !==
false) {
635 return (
int)$row[
'uid'];
656 if (substr_count($sqlString,
'?') !== count($parameters)) {
657 throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception(
'The number of question marks to replace must be equal to the number of parameters.', 1242816074);
660 foreach ($parameters as $parameter) {
661 $markPosition = strpos($sqlString,
'?', $offset);
662 if ($markPosition !==
false) {
663 if ($parameter === null) {
665 }
elseif (is_array($parameter) || $parameter instanceof \ArrayAccess || $parameter instanceof \Traversable) {
667 foreach ($parameter as $item) {
668 $items[] = $this->databaseHandle->fullQuoteStr($item, $tableName);
670 $parameter =
'(' . implode(
',', $items) .
')';
672 $parameter = $this->databaseHandle->fullQuoteStr($parameter, $tableName);
674 $sqlString = substr($sqlString, 0, $markPosition) . $parameter . substr($sqlString, ($markPosition + 1));
676 $offset = $markPosition + strlen($parameter);
692 if (is_array(
$GLOBALS[
'TCA'][$tableName][
'ctrl'])) {
693 $ignoreEnableFields = $querySettings->getIgnoreEnableFields();
694 $enableFieldsToBeIgnored = $querySettings->getEnableFieldsToBeIgnored();
695 $includeDeleted = $querySettings->getIncludeDeleted();
696 if ($this->environmentService->isEnvironmentInFrontendMode()) {
702 if (!empty($statement)) {
703 $statement = strtolower(substr($statement, 1, 3)) ===
'and' ? substr($statement, 5) : $statement;
704 $sql[
'additionalWhereClause'][] = $statement;
723 if ($ignoreEnableFields && !$includeDeleted) {
724 if (!empty($enableFieldsToBeIgnored)) {
726 $statement .= $this->
getPageRepository()->enableFields($tableName, -1, array_combine($enableFieldsToBeIgnored, $enableFieldsToBeIgnored));
730 }
elseif (!$ignoreEnableFields && !$includeDeleted) {
732 }
elseif (!$ignoreEnableFields && $includeDeleted) {
733 throw new \TYPO3\CMS\Extbase\Persistence\Generic\Exception\InconsistentQuerySettingsException(
'Query setting "ignoreEnableFields=FALSE" can not be used together with "includeDeleted=TRUE" in frontend context.', 1327678173);
750 if (!$ignoreEnableFields) {
753 if (!$includeDeleted) {
772 $tableName = $source->getSelectorName();
774 $tableName = $source->getRight()->getSelectorName();
783 if ($workspaceUid !== null) {
787 if ($workspaceUid === null) {
788 $workspaceUid =
$GLOBALS[
'BE_USER']->workspace;
799 && count($rows) === 1
801 $movePlaceholder = $this->databaseHandle->exec_SELECTgetSingleRow(
804 't3ver_state=3 AND t3ver_wsid=' .
$pageRepository->versioningWorkspaceId
805 .
' AND t3ver_move_id=' . $rows[0][
'uid']
807 if (!empty($movePlaceholder)) {
808 $rows = array($movePlaceholder);
812 $overlaidRows = array();
813 foreach ($rows as $row) {
815 if (isset($tableName) && isset(
$GLOBALS[
'TCA'][$tableName])
816 && isset(
$GLOBALS[
'TCA'][$tableName][
'ctrl'][
'languageField'])
817 && isset(
$GLOBALS[
'TCA'][$tableName][
'ctrl'][
'transOrigPointerField'])
818 && !isset(
$GLOBALS[
'TCA'][$tableName][
'ctrl'][
'transOrigPointerTable'])
820 if (isset($row[
$GLOBALS[
'TCA'][$tableName][
'ctrl'][
'transOrigPointerField']])
821 && $row[
$GLOBALS[
'TCA'][$tableName][
'ctrl'][
'transOrigPointerField']] > 0
823 $row = $this->databaseHandle->exec_SELECTgetSingleRow(
826 $tableName .
'.uid=' . (
int)$row[
$GLOBALS[
'TCA'][$tableName][
'ctrl'][
'transOrigPointerField']] .
827 ' AND ' . $tableName .
'.' .
$GLOBALS[
'TCA'][$tableName][
'ctrl'][
'languageField'] .
'=0'
832 if ($tableName ==
'pages') {
833 $row =
$pageRepository->getPageOverlay($row, $querySettings->getLanguageUid());
834 }
elseif (isset(
$GLOBALS[
'TCA'][$tableName][
'ctrl'][
'languageField'])
835 &&
$GLOBALS[
'TCA'][$tableName][
'ctrl'][
'languageField'] !==
''
836 && !isset(
$GLOBALS[
'TCA'][$tableName][
'ctrl'][
'transOrigPointerTable'])
838 if (in_array($row[
$GLOBALS[
'TCA'][$tableName][
'ctrl'][
'languageField']], array(-1, 0))) {
839 $overlayMode = $querySettings->getLanguageMode() ===
'strict' ?
'hideNonTranslated' :
'';
840 $row =
$pageRepository->getRecordOverlay($tableName, $row, $querySettings->getLanguageUid(), $overlayMode);
843 if ($row !== null && is_array($row)) {
844 $overlaidRows[] = $row;
847 return $overlaidRows;
855 if (!$this->pageRepository instanceof \TYPO3\CMS\Frontend\Page\PageRepository) {
856 if ($this->environmentService->isEnvironmentInFrontendMode() && is_object(
$GLOBALS[
'TSFE'])) {
857 $this->pageRepository =
$GLOBALS[
'TSFE']->sys_page;
859 $this->pageRepository = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Frontend\Page\PageRepository::class);
875 $error = $this->databaseHandle->sql_error();
877 $error .= $sql ?
': ' . $sql :
'';
878 throw new \TYPO3\CMS\Extbase\Persistence\Generic\Storage\Exception\SqlErrorException($error, 1247602160);
895 $frameworkConfiguration = $this->configurationManager->getConfiguration(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
896 if (isset($frameworkConfiguration[
'persistence'][
'enableAutomaticCacheClearing']) && $frameworkConfiguration[
'persistence'][
'enableAutomaticCacheClearing'] ===
'1') {
901 $pageIdsToClear = array();
903 $columns = $this->databaseHandle->admin_get_fields($tableName);
904 if (array_key_exists(
'pid', $columns)) {
905 $result = $this->databaseHandle->exec_SELECTquery(
'pid', $tableName,
'uid=' . (
int)$uid);
906 if ($row = $this->databaseHandle->sql_fetch_assoc($result)) {
907 $storagePage = $row[
'pid'];
908 $pageIdsToClear[] = $storagePage;
912 $storagePage =
$GLOBALS[
'TSFE']->id;
913 $pageIdsToClear[] = $storagePage;
915 if ($storagePage === null) {
918 if (!isset($this->pageTSConfigCache[$storagePage])) {
921 if (isset($this->pageTSConfigCache[$storagePage][
'TCEMAIN.'][
'clearCacheCmd'])) {
922 $clearCacheCommands = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(
',', strtolower($this->pageTSConfigCache[$storagePage][
'TCEMAIN.'][
'clearCacheCmd']),
true);
923 $clearCacheCommands = array_unique($clearCacheCommands);
924 foreach ($clearCacheCommands as $clearCacheCommand) {
925 if (\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($clearCacheCommand)) {
926 $pageIdsToClear[] = $clearCacheCommand;
931 foreach ($pageIdsToClear as $pageIdToClear) {
932 $this->cacheService->getPageIdStack()->push($pageIdToClear);
944 if (!isset($this->queryRuntimeCache[$entryIdentifier])) {
945 $this->queryRuntimeCache[$entryIdentifier] = $this->queryCache->get($entryIdentifier);
947 return $this->queryRuntimeCache[$entryIdentifier];
959 $this->queryRuntimeCache[$entryIdentifier] = $variable;
960 $this->queryCache->set($entryIdentifier, $variable, array(), 0);