/** * Get tables for menu example * * @param int $startUid UID from selected page * @param int $depth How many levels recursive * @return string The tables to be displayed */ public function getTables($startUid, $depth = 0) { $deletedRecordsTotal = 0; $lang = $this->getLanguageService(); $tables = array(); foreach (RecyclerUtility::getModifyableTables() as $tableName) { $deletedField = RecyclerUtility::getDeletedField($tableName); if ($deletedField) { // Determine whether the table has deleted records: $deletedCount = $this->getDatabaseConnection()->exec_SELECTcountRows('uid', $tableName, $deletedField . '<>0'); if ($deletedCount) { /* @var $deletedDataObject \TYPO3\CMS\Recycler\Domain\Model\DeletedRecords */ $deletedDataObject = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Recycler\Domain\Model\DeletedRecords::class); $deletedData = $deletedDataObject->loadData($startUid, $tableName, $depth)->getDeletedRows(); if (isset($deletedData[$tableName])) { if ($deletedRecordsInTable = count($deletedData[$tableName])) { $deletedRecordsTotal += $deletedRecordsInTable; $tables[] = array($tableName, $deletedRecordsInTable, RecyclerUtility::getUtf8String($lang->sL($GLOBALS['TCA'][$tableName]['ctrl']['title']))); } } } } } $jsonArray = $tables; array_unshift($jsonArray, array('', $deletedRecordsTotal, $lang->sL('LLL:EXT:recycler/mod1/locallang.xlf:label_allrecordtypes'))); return $jsonArray; }
/** * Get tables for menu example * * @param string $format: Return format (example: json) * @param boolean $withAllOption: 0 no, 1 return tables with a "all" option * @param integer $id: UID from selected page * @param integer $depth: How many levels recursive * @return string The tables to be displayed */ public function getTables($format, $withAllOption = 0, $startUid, $depth = 0) { $deletedRecordsTotal = 0; $tables = array(); foreach (array_keys($GLOBALS['TCA']) as $tableName) { $deletedField = \TYPO3\CMS\Recycler\Utility\RecyclerUtility::getDeletedField($tableName); if ($deletedField) { // Determine whether the table has deleted records: $deletedCount = $GLOBALS['TYPO3_DB']->exec_SELECTcountRows('uid', $tableName, $deletedField . '<>0'); if ($deletedCount) { $deletedDataObject = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Recycler\\Domain\\Model\\DeletedRecords'); $deletedData = $deletedDataObject->loadData($startUid, $tableName, $depth)->getDeletedRows(); if (isset($deletedData[$tableName])) { if ($deletedRecordsInTable = count($deletedData[$tableName])) { $deletedRecordsTotal += $deletedRecordsInTable; $tables[] = array($tableName, $deletedRecordsInTable, $tableName, \TYPO3\CMS\Recycler\Utility\RecyclerUtility::getUtf8String($GLOBALS['LANG']->sL($GLOBALS['TCA'][$tableName]['ctrl']['title']))); } } } } } $jsonArray = $tables; if ($withAllOption) { array_unshift($jsonArray, array('', $deletedRecordsTotal, '', $GLOBALS['LANG']->sL('LLL:EXT:recycler/mod1/locallang.xlf:label_alltables'))); } $output = json_encode($jsonArray); return $output; }
/** * Get tables for menu example * * @param int $startUid UID from selected page * @param int $depth How many levels recursive * @return string The tables to be displayed */ public function getTables($startUid, $depth = 0) { $deletedRecordsTotal = 0; $lang = $this->getLanguageService(); $tables = array(); $connection = GeneralUtility::makeInstance(ConnectionPool::class); foreach (RecyclerUtility::getModifyableTables() as $tableName) { $deletedField = RecyclerUtility::getDeletedField($tableName); if ($deletedField) { // Determine whether the table has deleted records: $queryBuilder = $connection->getQueryBuilderForTable($tableName); $queryBuilder->getQueryContext()->setContext(QueryContextType::UNRESTRICTED); $deletedCount = $queryBuilder->count('uid')->from($tableName)->where($queryBuilder->expr()->neq($deletedField, 0))->execute()->fetchColumn(); if ($deletedCount) { /* @var $deletedDataObject DeletedRecords */ $deletedDataObject = GeneralUtility::makeInstance(DeletedRecords::class); $deletedData = $deletedDataObject->loadData($startUid, $tableName, $depth)->getDeletedRows(); if (isset($deletedData[$tableName])) { if ($deletedRecordsInTable = count($deletedData[$tableName])) { $deletedRecordsTotal += $deletedRecordsInTable; $tables[] = array($tableName, $deletedRecordsInTable, $lang->sL($GLOBALS['TCA'][$tableName]['ctrl']['title'])); } } } } } $jsonArray = $tables; array_unshift($jsonArray, array('', $deletedRecordsTotal, $lang->sL('LLL:EXT:recycler/mod1/locallang.xlf:label_allrecordtypes'))); return $jsonArray; }
/** * Set all deleted rows * * @param integer $id: UID from record * @param string $table: Tablename from record * @param integer $depth: How many levels recursive * @param array $ctrl: TCA CTRL Array * @param string $filter: Filter text * @return void */ protected function setData($id = 0, $table, $depth, $tcaCtrl, $filter) { $id = intval($id); if (array_key_exists('delete', $tcaCtrl)) { // find the 'deleted' field for this table $deletedField = \TYPO3\CMS\Recycler\Utility\RecyclerUtility::getDeletedField($table); // create the filter WHERE-clause if (trim($filter) != '') { $filterWhere = ' AND (' . (\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($filter) ? 'uid = ' . $filter . ' OR pid = ' . $filter . ' OR ' : '') . $tcaCtrl['label'] . ' LIKE "%' . $this->escapeValueForLike($filter, $table) . '%"' . ')'; } // get the limit if ($this->limit != '') { // count the number of deleted records for this pid $deletedCount = $GLOBALS['TYPO3_DB']->exec_SELECTcountRows('uid', $table, $deletedField . '<>0 AND pid = ' . $id . $filterWhere); // split the limit $parts = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $this->limit); $offset = $parts[0]; $rowCount = $parts[1]; // subtract the number of deleted records from the limit's offset $result = $offset - $deletedCount; // if the result is >= 0 if ($result >= 0) { // store the new offset in the limit and go into the next depth $offset = $result; $this->limit = implode(',', array($offset, $rowCount)); // do NOT query this depth; limit also does not need to be set, we set it anyways $allowQuery = FALSE; $allowDepth = TRUE; $limit = ''; } else { // the offset for the temporary limit has to remain like the original offset // in case the original offset was just crossed by the amount of deleted records if ($offset != 0) { $tempOffset = $offset; } else { $tempOffset = 0; } // set the offset in the limit to 0 $newOffset = 0; // convert to negative result to the positive equivalent $absResult = abs($result); // if the result now is > limit's row count if ($absResult > $rowCount) { // use the limit's row count as the temporary limit $limit = implode(',', array($tempOffset, $rowCount)); // set the limit's row count to 0 $this->limit = implode(',', array($newOffset, 0)); // do not go into new depth $allowDepth = FALSE; } else { // if the result now is <= limit's row count // use the result as the temporary limit $limit = implode(',', array($tempOffset, $absResult)); // subtract the result from the row count $newCount = $rowCount - $absResult; // store the new result in the limit's row count $this->limit = implode(',', array($newOffset, $newCount)); // if the new row count is > 0 if ($newCount > 0) { // go into new depth $allowDepth = TRUE; } else { // if the new row count is <= 0 (only =0 makes sense though) // do not go into new depth $allowDepth = FALSE; } } // allow query for this depth $allowQuery = TRUE; } } else { $limit = ''; $allowDepth = TRUE; $allowQuery = TRUE; } // query for actual deleted records if ($allowQuery) { $recordsToCheck = \TYPO3\CMS\Backend\Utility\BackendUtility::getRecordsByField($table, $deletedField, '1', ' AND pid = ' . $id . $filterWhere, '', '', $limit, FALSE); if ($recordsToCheck) { $this->checkRecordAccess($table, $recordsToCheck); } } // go into depth if ($allowDepth && $depth >= 1) { // check recursively for elements beneath this page $resPages = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', 'pages', 'pid=' . $id, '', 'sorting'); if (is_resource($resPages)) { while ($rowPages = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($resPages)) { $this->setData($rowPages['uid'], $table, $depth - 1, $tcaCtrl, $filter); // some records might have been added, check if we still have the limit for further queries if ('' != $this->limit) { $parts = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $this->limit); // abort loop if LIMIT 0,0 if ($parts[0] == 0 && $parts[1] == 0) { break; } } } $GLOBALS['TYPO3_DB']->sql_free_result($resPages); } } $this->label[$table] = $tcaCtrl['label']; $this->title[$table] = $tcaCtrl['title']; } }
/** * Set all deleted rows * * @param int $id UID from record * @param string $table Tablename from record * @param int $depth How many levels recursive * @param array $tcaCtrl TCA CTRL array * @param string $filter Filter text * @return void */ protected function setData($id, $table, $depth, $tcaCtrl, $filter) { $id = (int) $id; if (!array_key_exists('delete', $tcaCtrl)) { return; } $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table); $queryBuilder->getRestrictions()->removeAll(); // find the 'deleted' field for this table $deletedField = RecyclerUtility::getDeletedField($table); // create the filter WHERE-clause $filterConstraint = null; if (trim($filter) !== '') { $labelConstraint = $queryBuilder->expr()->like($tcaCtrl['label'], $queryBuilder->createNamedParameter($queryBuilder->quote('%' . $queryBuilder->escapeLikeWildcards($filter) . '%'), \PDO::PARAM_STR)); if (MathUtility::canBeInterpretedAsInteger($filter)) { $filterConstraint = $queryBuilder->expr()->orX($queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($filter, \PDO::PARAM_INT)), $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($filter, \PDO::PARAM_INT)), $labelConstraint); } else { $filterConstraint = $labelConstraint; } } // get the limit if (!empty($this->limit)) { // count the number of deleted records for this pid $deletedCount = $queryBuilder->count('*')->from($table)->where($queryBuilder->expr()->neq($deletedField, $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)), $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT)), $filterConstraint)->execute()->fetchColumn(); // split the limit $parts = GeneralUtility::trimExplode(',', $this->limit); $offset = $parts[0]; $rowCount = $parts[1]; // subtract the number of deleted records from the limit's offset $result = $offset - $deletedCount; // if the result is >= 0 if ($result >= 0) { // store the new offset in the limit and go into the next depth $offset = $result; $this->limit = implode(',', [$offset, $rowCount]); // do NOT query this depth; limit also does not need to be set, we set it anyways $allowQuery = false; $allowDepth = true; $limit = ''; } else { // the offset for the temporary limit has to remain like the original offset // in case the original offset was just crossed by the amount of deleted records if ($offset !== 0) { $tempOffset = $offset; } else { $tempOffset = 0; } // set the offset in the limit to 0 $newOffset = 0; // convert to negative result to the positive equivalent $absResult = abs($result); // if the result now is > limit's row count if ($absResult > $rowCount) { // use the limit's row count as the temporary limit $limit = implode(',', [$tempOffset, $rowCount]); // set the limit's row count to 0 $this->limit = implode(',', [$newOffset, 0]); // do not go into new depth $allowDepth = false; } else { // if the result now is <= limit's row count // use the result as the temporary limit $limit = implode(',', [$tempOffset, $absResult]); // subtract the result from the row count $newCount = $rowCount - $absResult; // store the new result in the limit's row count $this->limit = implode(',', [$newOffset, $newCount]); // if the new row count is > 0 if ($newCount > 0) { // go into new depth $allowDepth = true; } else { // if the new row count is <= 0 (only =0 makes sense though) // do not go into new depth $allowDepth = false; } } // allow query for this depth $allowQuery = true; } } else { $limit = ''; $allowDepth = true; $allowQuery = true; } // query for actual deleted records if ($allowQuery) { $where = $queryBuilder->expr()->andX($queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT)), $filterConstraint); $recordsToCheck = BackendUtility::getRecordsByField($table, $deletedField, '1', ' AND ' . $where, '', '', $limit, false, $queryBuilder); if ($recordsToCheck) { $this->checkRecordAccess($table, $recordsToCheck); } } // go into depth if ($allowDepth && $depth >= 1) { // check recursively for elements beneath this page $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages'); $queryBuilder->getRestrictions()->removeAll(); $resPages = $queryBuilder->select('uid')->from('pages')->where($queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT)))->orderBy('sorting')->execute(); while ($row = $resPages->fetch()) { $this->setData($row['uid'], $table, $depth - 1, $tcaCtrl, $filter); // some records might have been added, check if we still have the limit for further queries if (!empty($this->limit)) { $parts = GeneralUtility::trimExplode(',', $this->limit); // abort loop if LIMIT 0,0 if ((int) $parts[0] === 0 && (int) $parts[1] === 0) { $resPages->closeCursor(); break; } } } } $this->label[$table] = $tcaCtrl['label']; $this->title[$table] = $tcaCtrl['title']; }