TYPO3  7.6
Typo3DbBackend.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Extbase\Persistence\Generic\Storage;
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
18 use TYPO3\CMS\Extbase\Persistence\Generic\Qom;
20 
25 {
31  protected $databaseHandle;
32 
36  protected $dataMapper;
37 
43  protected $pageRepository;
44 
50  protected $pageTSConfigCache = array();
51 
56 
60  protected $cacheService;
61 
65  protected $cacheManager;
66 
70  protected $tableColumnCache;
71 
75  protected $queryCache;
76 
81 
85  protected $queryParser;
86 
92  protected $queryRuntimeCache = array();
93 
97  public function injectDataMapper(\TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper $dataMapper)
98  {
99  $this->dataMapper = $dataMapper;
100  }
101 
105  public function injectConfigurationManager(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface $configurationManager)
106  {
107  $this->configurationManager = $configurationManager;
108  }
109 
113  public function injectCacheService(\TYPO3\CMS\Extbase\Service\CacheService $cacheService)
114  {
115  $this->cacheService = $cacheService;
116  }
117 
121  public function injectCacheManager(\TYPO3\CMS\Core\Cache\CacheManager $cacheManager)
122  {
123  $this->cacheManager = $cacheManager;
124  }
125 
129  public function injectEnvironmentService(\TYPO3\CMS\Extbase\Service\EnvironmentService $environmentService)
130  {
131  $this->environmentService = $environmentService;
132  }
133 
137  public function injectQueryParser(\TYPO3\CMS\Extbase\Persistence\Generic\Storage\Typo3DbQueryParser $queryParser)
138  {
139  $this->queryParser = $queryParser;
140  }
141 
145  public function __construct()
146  {
147  $this->databaseHandle = $GLOBALS['TYPO3_DB'];
148  }
149 
155  public function initializeObject()
156  {
157  $this->tableColumnCache = $this->cacheManager->getCache('extbase_typo3dbbackend_tablecolumns');
158  $this->queryCache = $this->cacheManager->getCache('extbase_typo3dbbackend_queries');
159  }
160 
169  public function addRow($tableName, array $fieldValues, $isRelation = false)
170  {
171  if (isset($fieldValues['uid'])) {
172  unset($fieldValues['uid']);
173  }
174 
175  $this->databaseHandle->exec_INSERTquery($tableName, $fieldValues);
176  $this->checkSqlErrors();
177  $uid = $this->databaseHandle->sql_insert_id();
178 
179  if (!$isRelation) {
180  $this->clearPageCache($tableName, $uid);
181  }
182  return (int)$uid;
183  }
184 
194  public function updateRow($tableName, array $fieldValues, $isRelation = false)
195  {
196  if (!isset($fieldValues['uid'])) {
197  throw new \InvalidArgumentException('The given row must contain a value for "uid".');
198  }
199 
200  $uid = (int)$fieldValues['uid'];
201  unset($fieldValues['uid']);
202 
203  $updateSuccessful = $this->databaseHandle->exec_UPDATEquery($tableName, 'uid = ' . $uid, $fieldValues);
204  $this->checkSqlErrors();
205 
206  if (!$isRelation) {
207  $this->clearPageCache($tableName, $uid);
208  }
209 
210  return $updateSuccessful;
211  }
212 
221  public function updateRelationTableRow($tableName, array $fieldValues)
222  {
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
226  );
227  }
228 
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']);
233 
234  if (!empty($fieldValues['tablenames'])) {
235  $where['tablenames'] = $fieldValues['tablenames'];
236  unset($fieldValues['tablenames']);
237  }
238  if (!empty($fieldValues['fieldname'])) {
239  $where['fieldname'] = $fieldValues['fieldname'];
240  unset($fieldValues['fieldname']);
241  }
242 
243  $updateSuccessful = $this->databaseHandle->exec_UPDATEquery(
244  $tableName,
245  $this->resolveWhereStatement($where, $tableName),
246  $fieldValues
247  );
248  $this->checkSqlErrors();
249 
250  return $updateSuccessful;
251  }
252 
261  public function removeRow($tableName, array $where, $isRelation = false)
262  {
263  $deleteSuccessful = $this->databaseHandle->exec_DELETEquery(
264  $tableName,
265  $this->resolveWhereStatement($where, $tableName)
266  );
267  $this->checkSqlErrors();
268 
269  if (!$isRelation && isset($where['uid'])) {
270  $this->clearPageCache($tableName, $where['uid']);
271  }
272 
273  return $deleteSuccessful;
274  }
275 
284  public function getMaxValueFromTable($tableName, array $where, $columnName)
285  {
286  $result = $this->databaseHandle->exec_SELECTgetSingleRow(
287  $columnName,
288  $tableName,
289  $this->resolveWhereStatement($where, $tableName),
290  '',
291  $columnName . ' DESC',
292  true
293  );
294  $this->checkSqlErrors();
295 
296  return $result[0];
297  }
298 
306  public function getRowByIdentifier($tableName, array $where)
307  {
308  $row = $this->databaseHandle->exec_SELECTgetSingleRow(
309  '*',
310  $tableName,
311  $this->resolveWhereStatement($where, $tableName)
312  );
313  $this->checkSqlErrors();
314 
315  return $row ?: false;
316  }
317 
326  protected function resolveWhereStatement(array $where, $tableName = 'foo')
327  {
328  $whereStatement = array();
329 
330  foreach ($where as $fieldName => $fieldValue) {
331  $whereStatement[] = $fieldName . ' = ' . $this->databaseHandle->fullQuoteStr($fieldValue, $tableName);
332  }
333 
334  return implode(' AND ', $whereStatement);
335  }
336 
343  public function getObjectDataByQuery(QueryInterface $query)
344  {
345  $statement = $query->getStatement();
346  if ($statement instanceof Qom\Statement) {
347  $rows = $this->getObjectDataByRawQuery($statement);
348  } else {
349  $rows = $this->getRowsByStatementParts($query);
350  }
351 
352  $rows = $this->doLanguageAndWorkspaceOverlay($query->getSource(), $rows, $query->getQuerySettings());
353  return $rows;
354  }
355 
363  protected function createQueryCommandParametersFromStatementParts(array $statementParts)
364  {
365  return array(
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'])
371  : ''
372  ),
373  'orderBy' => (!empty($statementParts['orderings']) ? implode(', ', $statementParts['orderings']) : ''),
374  'limit' => ($statementParts['offset'] ? $statementParts['offset'] . ', ' : '')
375  . ($statementParts['limit'] ? $statementParts['limit'] : '')
376  );
377  }
378 
385  protected function getRowsByStatementParts(QueryInterface $query)
386  {
387  if ($query->getQuerySettings()->getUsePreparedStatement()) {
388  list($statementParts, $parameters) = $this->getStatementParts($query, false);
389  $rows = $this->getRowsFromPreparedDatabase($statementParts, $parameters);
390  } else {
391  list($statementParts) = $this->getStatementParts($query);
392  $rows = $this->getRowsFromDatabase($statementParts);
393  }
394 
395  return $rows;
396  }
397 
404  protected function getRowsFromDatabase(array $statementParts)
405  {
406  $queryCommandParameters = $this->createQueryCommandParametersFromStatementParts($statementParts);
407  $rows = $this->databaseHandle->exec_SELECTgetRows(
408  $queryCommandParameters['selectFields'],
409  $queryCommandParameters['fromTable'],
410  $queryCommandParameters['whereClause'],
411  '',
412  $queryCommandParameters['orderBy'],
413  $queryCommandParameters['limit']
414  );
415  $this->checkSqlErrors();
416 
417  return $rows;
418  }
419 
427  protected function getRowsFromPreparedDatabase(array $statementParts, array $parameters)
428  {
429  $queryCommandParameters = $this->createQueryCommandParametersFromStatementParts($statementParts);
430  $preparedStatement = $this->databaseHandle->prepare_SELECTquery(
431  $queryCommandParameters['selectFields'],
432  $queryCommandParameters['fromTable'],
433  $queryCommandParameters['whereClause'],
434  '',
435  $queryCommandParameters['orderBy'],
436  $queryCommandParameters['limit']
437  );
438 
439  $preparedStatement->execute($parameters);
440  $rows = $preparedStatement->fetchAll();
441 
442  $preparedStatement->free();
443  return $rows;
444  }
445 
452  protected function getObjectDataByRawQuery(Qom\Statement $statement)
453  {
454  $realStatement = $statement->getStatement();
455  $parameters = $statement->getBoundVariables();
456 
457  if ($realStatement instanceof \TYPO3\CMS\Core\Database\PreparedStatement) {
458  $realStatement->execute($parameters);
459  $rows = $realStatement->fetchAll();
460 
461  $realStatement->free();
462  } else {
463  $result = $this->databaseHandle->sql_query($realStatement);
464  $this->checkSqlErrors();
465 
466  $rows = array();
467  while ($row = $this->databaseHandle->sql_fetch_assoc($result)) {
468  if (is_array($row)) {
469  $rows[] = $row;
470  }
471  }
472  $this->databaseHandle->sql_free_result($result);
473  }
474 
475  return $rows;
476  }
477 
485  public function getObjectCountByQuery(QueryInterface $query)
486  {
487  if ($query->getConstraint() instanceof Qom\Statement) {
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);
489  }
490 
491  list($statementParts) = $this->getStatementParts($query);
492 
493  $fields = '*';
494  if (isset($statementParts['keywords']['distinct'])) {
495  $fields = 'DISTINCT ' . reset($statementParts['tables']) . '.uid';
496  }
497 
498  $queryCommandParameters = $this->createQueryCommandParametersFromStatementParts($statementParts);
499  $count = $this->databaseHandle->exec_SELECTcountRows(
500  $fields,
501  $queryCommandParameters['fromTable'],
502  $queryCommandParameters['whereClause']
503  );
504  $this->checkSqlErrors();
505 
506  if ($statementParts['offset']) {
507  $count -= $statementParts['offset'];
508  }
509 
510  if ($statementParts['limit']) {
511  $count = min($count, $statementParts['limit']);
512  }
513 
514  return (int)max(0, $count);
515  }
516 
525  protected function getStatementParts($query, $resolveParameterPlaceholders = true)
526  {
536  list($queryHash, $parameters) = $this->queryParser->preparseQuery($query);
537 
538  if ($query->getQuerySettings()->getUseQueryCache()) {
539  $statementParts = $this->getQueryCacheEntry($queryHash);
540  if ($queryHash && !$statementParts) {
541  $statementParts = $this->queryParser->parseQuery($query);
542  $this->setQueryCacheEntry($queryHash, $statementParts);
543  }
544  } else {
545  $statementParts = $this->queryParser->parseQuery($query);
546  }
547 
548  if (!$statementParts) {
549  throw new \RuntimeException('Your query could not be built.', 1394453197);
550  }
551 
552  $this->queryParser->addDynamicQueryParts($query->getQuerySettings(), $statementParts);
553 
554  // Limit and offset are not cached to allow caching of pagebrowser queries.
555  $statementParts['limit'] = ((int)$query->getLimit() ?: null);
556  $statementParts['offset'] = ((int)$query->getOffset() ?: null);
557 
558  if ($resolveParameterPlaceholders === true) {
559  $statementParts = $this->resolveParameterPlaceholders($statementParts, $parameters);
560  }
561 
562  return array($statementParts, $parameters);
563  }
564 
572  protected function resolveParameterPlaceholders(array $statementParts, array $parameters)
573  {
574  $tableName = reset($statementParts['tables']) ?: 'foo';
575 
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']);
579  }
580 
581  return $statementParts;
582  }
583 
591  public function quoteTextValueCallback($value, $parameters)
592  {
593  return $this->databaseHandle->fullQuoteStr($value, $parameters['tablename']);
594  }
595 
603  public function getUidOfAlreadyPersistedValueObject(\TYPO3\CMS\Extbase\DomainObject\AbstractValueObject $object)
604  {
605  $fields = array();
606  $parameters = array();
607  $dataMap = $this->dataMapper->getDataMap(get_class($object));
608  $properties = $object->_getProperties();
609  foreach ($properties as $propertyName => $propertyValue) {
610  // @todo We couple the Backend to the Entity implementation (uid, isClone); changes there breaks this method
611  if ($dataMap->isPersistableProperty($propertyName) && $propertyName !== 'uid' && $propertyName !== 'pid' && $propertyName !== 'isClone') {
612  if ($propertyValue === null) {
613  $fields[] = $dataMap->getColumnMap($propertyName)->getColumnName() . ' IS NULL';
614  } else {
615  $fields[] = $dataMap->getColumnMap($propertyName)->getColumnName() . '=?';
616  $parameters[] = $this->dataMapper->getPlainValue($propertyValue);
617  }
618  }
619  }
620  $sql = array();
621  $sql['additionalWhereClause'] = array();
622  $tableName = $dataMap->getTableName();
623  $this->addVisibilityConstraintStatement(new \TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings(), $tableName, $sql);
624  $statement = 'SELECT * FROM ' . $tableName;
625  $statement .= ' WHERE ' . implode(' AND ', $fields);
626  if (!empty($sql['additionalWhereClause'])) {
627  $statement .= ' AND ' . implode(' AND ', $sql['additionalWhereClause']);
628  }
629  $this->replacePlaceholders($statement, $parameters, $tableName);
630  // debug($statement,-2);
631  $res = $this->databaseHandle->sql_query($statement);
632  $this->checkSqlErrors($statement);
633  $row = $this->databaseHandle->sql_fetch_assoc($res);
634  if ($row !== false) {
635  return (int)$row['uid'];
636  } else {
637  return false;
638  }
639  }
640 
653  protected function replacePlaceholders(&$sqlString, array $parameters, $tableName = 'foo')
654  {
655  // @todo profile this method again
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);
658  }
659  $offset = 0;
660  foreach ($parameters as $parameter) {
661  $markPosition = strpos($sqlString, '?', $offset);
662  if ($markPosition !== false) {
663  if ($parameter === null) {
664  $parameter = 'NULL';
665  } elseif (is_array($parameter) || $parameter instanceof \ArrayAccess || $parameter instanceof \Traversable) {
666  $items = array();
667  foreach ($parameter as $item) {
668  $items[] = $this->databaseHandle->fullQuoteStr($item, $tableName);
669  }
670  $parameter = '(' . implode(',', $items) . ')';
671  } else {
672  $parameter = $this->databaseHandle->fullQuoteStr($parameter, $tableName);
673  }
674  $sqlString = substr($sqlString, 0, $markPosition) . $parameter . substr($sqlString, ($markPosition + 1));
675  }
676  $offset = $markPosition + strlen($parameter);
677  }
678  }
679 
689  protected function addVisibilityConstraintStatement(\TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface $querySettings, $tableName, array &$sql)
690  {
691  $statement = '';
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()) {
697  $statement .= $this->getFrontendConstraintStatement($tableName, $ignoreEnableFields, $enableFieldsToBeIgnored, $includeDeleted);
698  } else {
699  // TYPO3_MODE === 'BE'
700  $statement .= $this->getBackendConstraintStatement($tableName, $ignoreEnableFields, $includeDeleted);
701  }
702  if (!empty($statement)) {
703  $statement = strtolower(substr($statement, 1, 3)) === 'and' ? substr($statement, 5) : $statement;
704  $sql['additionalWhereClause'][] = $statement;
705  }
706  }
707  }
708 
720  protected function getFrontendConstraintStatement($tableName, $ignoreEnableFields, array $enableFieldsToBeIgnored = array(), $includeDeleted)
721  {
722  $statement = '';
723  if ($ignoreEnableFields && !$includeDeleted) {
724  if (!empty($enableFieldsToBeIgnored)) {
725  // array_combine() is necessary because of the way \TYPO3\CMS\Frontend\Page\PageRepository::enableFields() is implemented
726  $statement .= $this->getPageRepository()->enableFields($tableName, -1, array_combine($enableFieldsToBeIgnored, $enableFieldsToBeIgnored));
727  } else {
728  $statement .= $this->getPageRepository()->deleteClause($tableName);
729  }
730  } elseif (!$ignoreEnableFields && !$includeDeleted) {
731  $statement .= $this->getPageRepository()->enableFields($tableName);
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);
734  }
735  return $statement;
736  }
737 
747  protected function getBackendConstraintStatement($tableName, $ignoreEnableFields, $includeDeleted)
748  {
749  $statement = '';
750  if (!$ignoreEnableFields) {
751  $statement .= BackendUtility::BEenableFields($tableName);
752  }
753  if (!$includeDeleted) {
754  $statement .= BackendUtility::deleteClause($tableName);
755  }
756  return $statement;
757  }
758 
769  protected function doLanguageAndWorkspaceOverlay(Qom\SourceInterface $source, array $rows, \TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface $querySettings, $workspaceUid = null)
770  {
771  if ($source instanceof Qom\SelectorInterface) {
772  $tableName = $source->getSelectorName();
773  } elseif ($source instanceof Qom\JoinInterface) {
774  $tableName = $source->getRight()->getSelectorName();
775  } else {
776  // No proper source, so we do not have a table name here
777  // we cannot do an overlay and return the original rows instead.
778  return $rows;
779  }
780 
782  if (is_object($GLOBALS['TSFE'])) {
783  if ($workspaceUid !== null) {
784  $pageRepository->versioningWorkspaceId = $workspaceUid;
785  }
786  } else {
787  if ($workspaceUid === null) {
788  $workspaceUid = $GLOBALS['BE_USER']->workspace;
789  }
790  $pageRepository->versioningWorkspaceId = $workspaceUid;
791  }
792 
793  // Fetches the move-placeholder in case it is supported
794  // by the table and if there's only one row in the result set
795  // (applying this to all rows does not work, since the sorting
796  // order would be destroyed and possible limits not met anymore)
797  if (!empty($pageRepository->versioningWorkspaceId)
799  && count($rows) === 1
800  ) {
801  $movePlaceholder = $this->databaseHandle->exec_SELECTgetSingleRow(
802  $tableName . '.*',
803  $tableName,
804  't3ver_state=3 AND t3ver_wsid=' . $pageRepository->versioningWorkspaceId
805  . ' AND t3ver_move_id=' . $rows[0]['uid']
806  );
807  if (!empty($movePlaceholder)) {
808  $rows = array($movePlaceholder);
809  }
810  }
811 
812  $overlaidRows = array();
813  foreach ($rows as $row) {
814  // If current row is a translation select its parent
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'])
819  ) {
820  if (isset($row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']])
821  && $row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']] > 0
822  ) {
823  $row = $this->databaseHandle->exec_SELECTgetSingleRow(
824  $tableName . '.*',
825  $tableName,
826  $tableName . '.uid=' . (int)$row[$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField']] .
827  ' AND ' . $tableName . '.' . $GLOBALS['TCA'][$tableName]['ctrl']['languageField'] . '=0'
828  );
829  }
830  }
831  $pageRepository->versionOL($tableName, $row, true);
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'])
837  ) {
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);
841  }
842  }
843  if ($row !== null && is_array($row)) {
844  $overlaidRows[] = $row;
845  }
846  }
847  return $overlaidRows;
848  }
849 
853  protected function getPageRepository()
854  {
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;
858  } else {
859  $this->pageRepository = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Frontend\Page\PageRepository::class);
860  }
861  }
862 
863  return $this->pageRepository;
864  }
865 
873  protected function checkSqlErrors($sql = '')
874  {
875  $error = $this->databaseHandle->sql_error();
876  if ($error !== '') {
877  $error .= $sql ? ': ' . $sql : '';
878  throw new \TYPO3\CMS\Extbase\Persistence\Generic\Storage\Exception\SqlErrorException($error, 1247602160);
879  }
880  }
881 
893  protected function clearPageCache($tableName, $uid)
894  {
895  $frameworkConfiguration = $this->configurationManager->getConfiguration(\TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
896  if (isset($frameworkConfiguration['persistence']['enableAutomaticCacheClearing']) && $frameworkConfiguration['persistence']['enableAutomaticCacheClearing'] === '1') {
897  } else {
898  // if disabled, return
899  return;
900  }
901  $pageIdsToClear = array();
902  $storagePage = null;
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;
909  }
910  } elseif (isset($GLOBALS['TSFE'])) {
911  // No PID column - we can do a best-effort to clear the cache of the current page if in FE
912  $storagePage = $GLOBALS['TSFE']->id;
913  $pageIdsToClear[] = $storagePage;
914  }
915  if ($storagePage === null) {
916  return;
917  }
918  if (!isset($this->pageTSConfigCache[$storagePage])) {
919  $this->pageTSConfigCache[$storagePage] = BackendUtility::getPagesTSconfig($storagePage);
920  }
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;
927  }
928  }
929  }
930 
931  foreach ($pageIdsToClear as $pageIdToClear) {
932  $this->cacheService->getPageIdStack()->push($pageIdToClear);
933  }
934  }
935 
942  protected function getQueryCacheEntry($entryIdentifier)
943  {
944  if (!isset($this->queryRuntimeCache[$entryIdentifier])) {
945  $this->queryRuntimeCache[$entryIdentifier] = $this->queryCache->get($entryIdentifier);
946  }
947  return $this->queryRuntimeCache[$entryIdentifier];
948  }
949 
957  protected function setQueryCacheEntry($entryIdentifier, $variable)
958  {
959  $this->queryRuntimeCache[$entryIdentifier] = $variable;
960  $this->queryCache->set($entryIdentifier, $variable, array(), 0);
961  }
962 }