|
<?php
|
|
namespace Vendor\Package\Xclass;
|
|
|
|
use TYPO3\CMS\Backend\RecordList\RecordListGetTableHookInterface;
|
|
use TYPO3\CMS\Backend\Utility\BackendUtility;
|
|
use TYPO3\CMS\Core\Imaging\Icon;
|
|
use TYPO3\CMS\Core\Messaging\FlashMessage;
|
|
use TYPO3\CMS\Core\Messaging\FlashMessageService;
|
|
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
|
|
|
/**
|
|
* Xclass for TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList
|
|
*
|
|
* Makes CSV exports without generating HTML code and accumulating rows to save memory.
|
|
*/
|
|
class DatabaseRecordList extends \TYPO3\CMS\Recordlist\RecordList\DatabaseRecordList
|
|
{
|
|
/**
|
|
* The output stream to write the CSV lines to.
|
|
*
|
|
* @var
|
|
*/
|
|
protected $outputStream;
|
|
|
|
/**
|
|
* Table name (only for CSV export)
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $exportedTable;
|
|
|
|
/**
|
|
* Table field (column) where header value is found
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $titleCol;
|
|
|
|
/**
|
|
* Creates the listing of records from a single table
|
|
*
|
|
* @param string $table Table name
|
|
* @param int $id Page id
|
|
* @param string $rowList List of fields to show in the listing. Pseudo fields will be added including the record header.
|
|
* @throws \UnexpectedValueException
|
|
* @throws \TYPO3\CMS\Core\Exception
|
|
* @return string HTML table with the listing for the record.
|
|
*/
|
|
public function getTable($table, $id, $rowList = '')
|
|
{
|
|
$rowListArray = GeneralUtility::trimExplode(',', $rowList, true);
|
|
// if no columns have been specified, show description (if configured)
|
|
if (!empty($GLOBALS['TCA'][$table]['ctrl']['descriptionColumn']) && empty($rowListArray)) {
|
|
array_push($rowListArray, $GLOBALS['TCA'][$table]['ctrl']['descriptionColumn']);
|
|
}
|
|
$backendUser = $this->getBackendUserAuthentication();
|
|
$lang = $this->getLanguageService();
|
|
$db = $this->getDatabaseConnection();
|
|
// Init
|
|
$addWhere = '';
|
|
$titleCol = $GLOBALS['TCA'][$table]['ctrl']['label'];
|
|
$thumbsCol = $GLOBALS['TCA'][$table]['ctrl']['thumbnail'];
|
|
$l10nEnabled = $GLOBALS['TCA'][$table]['ctrl']['languageField']
|
|
&& $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']
|
|
&& !$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerTable'];
|
|
$tableCollapsed = (bool)$this->tablesCollapsed[$table];
|
|
// prepare space icon
|
|
$this->spaceIcon = '<span class="btn btn-default disabled">' . $this->iconFactory->getIcon('empty-empty', Icon::SIZE_SMALL)->render() . '</span>';
|
|
// Cleaning rowlist for duplicates and place the $titleCol as the first column always!
|
|
$this->fieldArray = [];
|
|
// title Column
|
|
// Add title column
|
|
$this->fieldArray[] = $titleCol;
|
|
// Control-Panel
|
|
if (!GeneralUtility::inList($rowList, '_CONTROL_')) {
|
|
$this->fieldArray[] = '_CONTROL_';
|
|
}
|
|
// Clipboard
|
|
if ($this->showClipboard) {
|
|
$this->fieldArray[] = '_CLIPBOARD_';
|
|
}
|
|
// Ref
|
|
if (!$this->dontShowClipControlPanels) {
|
|
$this->fieldArray[] = '_REF_';
|
|
}
|
|
// Path
|
|
if ($this->searchLevels) {
|
|
$this->fieldArray[] = '_PATH_';
|
|
}
|
|
// Localization
|
|
if ($this->localizationView && $l10nEnabled) {
|
|
$this->fieldArray[] = '_LOCALIZATION_';
|
|
$this->fieldArray[] = '_LOCALIZATION_b';
|
|
// Only restrict to the default language if no search request is in place
|
|
if ($this->searchString === '') {
|
|
$addWhere .= ' AND (
|
|
' . $GLOBALS['TCA'][$table]['ctrl']['languageField'] . '<=0
|
|
OR
|
|
' . $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'] . ' = 0
|
|
)';
|
|
}
|
|
}
|
|
// Cleaning up:
|
|
$this->fieldArray = array_unique(array_merge($this->fieldArray, $rowListArray));
|
|
if ($this->noControlPanels) {
|
|
$tempArray = array_flip($this->fieldArray);
|
|
unset($tempArray['_CONTROL_']);
|
|
unset($tempArray['_CLIPBOARD_']);
|
|
$this->fieldArray = array_keys($tempArray);
|
|
}
|
|
// Creating the list of fields to include in the SQL query:
|
|
$selectFields = $this->fieldArray;
|
|
$selectFields[] = 'uid';
|
|
$selectFields[] = 'pid';
|
|
// adding column for thumbnails
|
|
if ($thumbsCol) {
|
|
$selectFields[] = $thumbsCol;
|
|
}
|
|
if ($table == 'pages') {
|
|
$selectFields[] = 'module';
|
|
$selectFields[] = 'extendToSubpages';
|
|
$selectFields[] = 'nav_hide';
|
|
$selectFields[] = 'doktype';
|
|
$selectFields[] = 'shortcut';
|
|
$selectFields[] = 'shortcut_mode';
|
|
$selectFields[] = 'mount_pid';
|
|
}
|
|
if (is_array($GLOBALS['TCA'][$table]['ctrl']['enablecolumns'])) {
|
|
$selectFields = array_merge($selectFields, $GLOBALS['TCA'][$table]['ctrl']['enablecolumns']);
|
|
}
|
|
foreach (['type', 'typeicon_column', 'editlock'] as $field) {
|
|
if ($GLOBALS['TCA'][$table]['ctrl'][$field]) {
|
|
$selectFields[] = $GLOBALS['TCA'][$table]['ctrl'][$field];
|
|
}
|
|
}
|
|
if ($GLOBALS['TCA'][$table]['ctrl']['versioningWS']) {
|
|
$selectFields[] = 't3ver_id';
|
|
$selectFields[] = 't3ver_state';
|
|
$selectFields[] = 't3ver_wsid';
|
|
}
|
|
if ($l10nEnabled) {
|
|
$selectFields[] = $GLOBALS['TCA'][$table]['ctrl']['languageField'];
|
|
$selectFields[] = $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'];
|
|
}
|
|
if ($GLOBALS['TCA'][$table]['ctrl']['label_alt']) {
|
|
$selectFields = array_merge(
|
|
$selectFields,
|
|
GeneralUtility::trimExplode(',', $GLOBALS['TCA'][$table]['ctrl']['label_alt'], true)
|
|
);
|
|
}
|
|
// Unique list!
|
|
$selectFields = array_unique($selectFields);
|
|
$fieldListFields = $this->makeFieldList($table, 1);
|
|
if (empty($fieldListFields) && $GLOBALS['TYPO3_CONF_VARS']['BE']['debug']) {
|
|
$message = sprintf($lang->sL('LLL:EXT:lang/locallang_mod_web_list.xlf:missingTcaColumnsMessage', true), $table, $table);
|
|
$messageTitle = $lang->sL('LLL:EXT:lang/locallang_mod_web_list.xlf:missingTcaColumnsMessageTitle', true);
|
|
/** @var FlashMessage $flashMessage */
|
|
$flashMessage = GeneralUtility::makeInstance(
|
|
FlashMessage::class,
|
|
$message,
|
|
$messageTitle,
|
|
FlashMessage::WARNING,
|
|
true
|
|
);
|
|
/** @var $flashMessageService FlashMessageService */
|
|
$flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
|
|
/** @var $defaultFlashMessageQueue \TYPO3\CMS\Core\Messaging\FlashMessageQueue */
|
|
$defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
|
|
$defaultFlashMessageQueue->enqueue($flashMessage);
|
|
}
|
|
// Making sure that the fields in the field-list ARE in the field-list from TCA!
|
|
$selectFields = array_intersect($selectFields, $fieldListFields);
|
|
// Implode it into a list of fields for the SQL-statement.
|
|
$selFieldList = implode(',', $selectFields);
|
|
$this->selFieldList = $selFieldList;
|
|
if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['getTable'])) {
|
|
foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['getTable'] as $classData) {
|
|
$hookObject = GeneralUtility::getUserObj($classData);
|
|
if (!$hookObject instanceof RecordListGetTableHookInterface) {
|
|
throw new \UnexpectedValueException($classData . ' must implement interface ' . RecordListGetTableHookInterface::class, 1195114460);
|
|
}
|
|
$hookObject->getDBlistQuery($table, $id, $addWhere, $selFieldList, $this);
|
|
}
|
|
}
|
|
// Create the SQL query for selecting the elements in the listing:
|
|
// do not do paging when outputting as CSV
|
|
if ($this->csvOutput) {
|
|
$this->iLimit = 0;
|
|
}
|
|
if ($this->firstElementNumber > 2 && $this->iLimit > 0) {
|
|
// Get the two previous rows for sorting if displaying page > 1
|
|
$this->firstElementNumber = $this->firstElementNumber - 2;
|
|
$this->iLimit = $this->iLimit + 2;
|
|
// (API function from TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRecordList)
|
|
$queryParts = $this->makeQueryArray($table, $id, $addWhere);
|
|
|
|
$this->firstElementNumber = $this->firstElementNumber + 2;
|
|
$this->iLimit = $this->iLimit - 2;
|
|
} else {
|
|
// (API function from TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRecordList)
|
|
$queryParts = $this->makeQueryArray($table, $id, $addWhere);
|
|
}
|
|
|
|
// Finding the total amount of records on the page
|
|
// (API function from TYPO3\CMS\Recordlist\RecordList\AbstractDatabaseRecordList)
|
|
$this->setTotalItems($queryParts);
|
|
|
|
// Init:
|
|
$dbCount = 0;
|
|
$out = '';
|
|
$tableHeader = '';
|
|
$result = null;
|
|
$listOnlyInSingleTableMode = $this->listOnlyInSingleTableMode && !$this->table;
|
|
// If the count query returned any number of records, we perform the real query,
|
|
// selecting records.
|
|
if ($this->totalItems) {
|
|
// Fetch records only if not in single table mode
|
|
if ($listOnlyInSingleTableMode) {
|
|
$dbCount = $this->totalItems;
|
|
} else {
|
|
// Set the showLimit to the number of records when outputting as CSV
|
|
if ($this->csvOutput) {
|
|
$this->showLimit = $this->totalItems;
|
|
$this->iLimit = $this->totalItems;
|
|
}
|
|
$result = $db->exec_SELECT_queryArray($queryParts);
|
|
$dbCount = $db->sql_num_rows($result);
|
|
}
|
|
}
|
|
// If any records was selected, render the list:
|
|
if ($dbCount) {
|
|
$tableTitle = $lang->sL($GLOBALS['TCA'][$table]['ctrl']['title'], true);
|
|
if ($tableTitle === '') {
|
|
$tableTitle = $table;
|
|
}
|
|
// Header line is drawn
|
|
$theData = [];
|
|
if ($this->disableSingleTableView) {
|
|
$theData[$titleCol] = '<span class="c-table">' . BackendUtility::wrapInHelp($table, '', $tableTitle)
|
|
. '</span> (<span class="t3js-table-total-items">' . $this->totalItems . '</span>)';
|
|
} else {
|
|
$icon = $this->table
|
|
? '<span title="' . $lang->getLL('contractView', true) . '">' . $this->iconFactory->getIcon('actions-view-table-collapse', Icon::SIZE_SMALL)->render() . '</span>'
|
|
: '<span title="' . $lang->getLL('expandView', true) . '">' . $this->iconFactory->getIcon('actions-view-table-expand', Icon::SIZE_SMALL)->render() . '</span>';
|
|
$theData[$titleCol] = $this->linkWrapTable($table, $tableTitle . ' (<span class="t3js-table-total-items">' . $this->totalItems . '</span>) ' . $icon);
|
|
}
|
|
if ($listOnlyInSingleTableMode) {
|
|
$tableHeader .= BackendUtility::wrapInHelp($table, '', $theData[$titleCol]);
|
|
} else {
|
|
// Render collapse button if in multi table mode
|
|
$collapseIcon = '';
|
|
if (!$this->table) {
|
|
$href = htmlspecialchars(($this->listURL() . '&collapse[' . $table . ']=' . ($tableCollapsed ? '0' : '1')));
|
|
$title = $tableCollapsed
|
|
? $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.expandTable', true)
|
|
: $lang->sL('LLL:EXT:lang/locallang_core.xlf:labels.collapseTable', true);
|
|
$icon = '<span class="collapseIcon">' . $this->iconFactory->getIcon(($tableCollapsed ? 'actions-view-list-expand' : 'actions-view-list-collapse'), Icon::SIZE_SMALL)->render() . '</span>';
|
|
$collapseIcon = '<a href="' . $href . '" title="' . $title . '" class="pull-right t3js-toggle-recordlist" data-table="' . htmlspecialchars($table) . '" data-toggle="collapse" data-target="#recordlist-' . htmlspecialchars($table) . '">' . $icon . '</a>';
|
|
}
|
|
$tableHeader .= $theData[$titleCol] . $collapseIcon;
|
|
}
|
|
// Render table rows only if in multi table view or if in single table view
|
|
$rowOutput = '';
|
|
if (!$listOnlyInSingleTableMode || $this->table) {
|
|
// Fixing an order table for sortby tables
|
|
$this->currentTable = [];
|
|
$currentIdList = [];
|
|
$doSort = $GLOBALS['TCA'][$table]['ctrl']['sortby'] && !$this->sortField;
|
|
$prevUid = 0;
|
|
$prevPrevUid = 0;
|
|
// Get first two rows and initialize prevPrevUid and prevUid if on page > 1
|
|
if ($this->firstElementNumber > 2 && $this->iLimit > 0) {
|
|
$row = $db->sql_fetch_assoc($result);
|
|
$prevPrevUid = -((int)$row['uid']);
|
|
$row = $db->sql_fetch_assoc($result);
|
|
$prevUid = $row['uid'];
|
|
}
|
|
|
|
// XCLASS: Handle CSV output without generating HTML code or accumulating rows.
|
|
if ($this->csvOutput) {
|
|
$this->outputCsvFile($table, $result);
|
|
}
|
|
|
|
$accRows = [];
|
|
// Accumulate rows here
|
|
while ($row = $db->sql_fetch_assoc($result)) {
|
|
if (!$this->isRowListingConditionFulfilled($table, $row)) {
|
|
continue;
|
|
}
|
|
// In offline workspace, look for alternative record:
|
|
BackendUtility::workspaceOL($table, $row, $backendUser->workspace, true);
|
|
if (is_array($row)) {
|
|
$accRows[] = $row;
|
|
$currentIdList[] = $row['uid'];
|
|
if ($doSort) {
|
|
if ($prevUid) {
|
|
$this->currentTable['prev'][$row['uid']] = $prevPrevUid;
|
|
$this->currentTable['next'][$prevUid] = '-' . $row['uid'];
|
|
$this->currentTable['prevUid'][$row['uid']] = $prevUid;
|
|
}
|
|
$prevPrevUid = isset($this->currentTable['prev'][$row['uid']]) ? -$prevUid : $row['pid'];
|
|
$prevUid = $row['uid'];
|
|
}
|
|
}
|
|
}
|
|
$db->sql_free_result($result);
|
|
$this->totalRowCount = count($accRows);
|
|
// CSV initiated
|
|
if ($this->csvOutput) {
|
|
$this->initCSV();
|
|
}
|
|
// Render items:
|
|
$this->CBnames = [];
|
|
$this->duplicateStack = [];
|
|
$this->eCounter = $this->firstElementNumber;
|
|
$cc = 0;
|
|
foreach ($accRows as $row) {
|
|
// Render item row if counter < limit
|
|
if ($cc < $this->iLimit) {
|
|
$cc++;
|
|
$this->translations = false;
|
|
$rowOutput .= $this->renderListRow($table, $row, $cc, $titleCol, $thumbsCol);
|
|
// If localization view is enabled and no search happened it means that the selected
|
|
// records are either default or All language and here we will not select translations
|
|
// which point to the main record:
|
|
if ($this->localizationView && $l10nEnabled && $this->searchString === '') {
|
|
// For each available translation, render the record:
|
|
if (is_array($this->translations)) {
|
|
foreach ($this->translations as $lRow) {
|
|
// $lRow isn't always what we want - if record was moved we've to work with the
|
|
// placeholder records otherwise the list is messed up a bit
|
|
if ($row['_MOVE_PLH_uid'] && $row['_MOVE_PLH_pid']) {
|
|
$where = 't3ver_move_id="' . (int)$lRow['uid'] . '" AND pid="' . $row['_MOVE_PLH_pid']
|
|
. '" AND t3ver_wsid=' . $row['t3ver_wsid'] . BackendUtility::deleteClause($table);
|
|
$tmpRow = BackendUtility::getRecordRaw($table, $where, $selFieldList);
|
|
$lRow = is_array($tmpRow) ? $tmpRow : $lRow;
|
|
}
|
|
// In offline workspace, look for alternative record:
|
|
BackendUtility::workspaceOL($table, $lRow, $backendUser->workspace, true);
|
|
if (is_array($lRow) && $backendUser->checkLanguageAccess($lRow[$GLOBALS['TCA'][$table]['ctrl']['languageField']])) {
|
|
$currentIdList[] = $lRow['uid'];
|
|
$rowOutput .= $this->renderListRow($table, $lRow, $cc, $titleCol, $thumbsCol, 18);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Counter of total rows incremented:
|
|
$this->eCounter++;
|
|
}
|
|
// Record navigation is added to the beginning and end of the table if in single
|
|
// table mode
|
|
if ($this->table) {
|
|
$rowOutput = $this->renderListNavigation('top') . $rowOutput . $this->renderListNavigation('bottom');
|
|
} else {
|
|
// Show that there are more records than shown
|
|
if ($this->totalItems > $this->itemsLimitPerTable) {
|
|
$countOnFirstPage = $this->totalItems > $this->itemsLimitSingleTable ? $this->itemsLimitSingleTable : $this->totalItems;
|
|
$hasMore = $this->totalItems > $this->itemsLimitSingleTable;
|
|
$colspan = $this->showIcon ? count($this->fieldArray) + 1 : count($this->fieldArray);
|
|
$rowOutput .= '<tr><td colspan="' . $colspan . '">
|
|
<a href="' . htmlspecialchars(($this->listURL() . '&table=' . rawurlencode($table))) . '" class="btn btn-default">'
|
|
. '<span class="t3-icon fa fa-chevron-down"></span> <i>[1 - ' . $countOnFirstPage . ($hasMore ? '+' : '') . ']</i></a>
|
|
</td></tr>';
|
|
}
|
|
}
|
|
// The header row for the table is now created:
|
|
$out .= $this->renderListHeader($table, $currentIdList);
|
|
}
|
|
|
|
$collapseClass = $tableCollapsed && !$this->table ? 'collapse' : 'collapse in';
|
|
$dataState = $tableCollapsed && !$this->table ? 'collapsed' : 'expanded';
|
|
|
|
// The list of records is added after the header:
|
|
$out .= $rowOutput;
|
|
// ... and it is all wrapped in a table:
|
|
$out = '
|
|
|
|
|
|
|
|
<!--
|
|
DB listing of elements: "' . htmlspecialchars($table) . '"
|
|
-->
|
|
<div class="panel panel-space panel-default recordlist">
|
|
<div class="panel-heading">
|
|
' . $tableHeader . '
|
|
</div>
|
|
<div class="' . $collapseClass . '" data-state="' . $dataState . '" id="recordlist-' . htmlspecialchars($table) . '">
|
|
<div class="table-fit">
|
|
<table data-table="' . htmlspecialchars($table) . '" class="table table-striped table-hover' . ($listOnlyInSingleTableMode ? ' typo3-dblist-overview' : '') . '">
|
|
' . $out . '
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
';
|
|
// Output csv if...
|
|
// This ends the page with exit.
|
|
if ($this->csvOutput) {
|
|
$this->outputCSV($table);
|
|
}
|
|
}
|
|
// Return content:
|
|
return $out;
|
|
}
|
|
|
|
/**
|
|
* Initializes internal csvLines array with the header of field names
|
|
*
|
|
* @param string $prefix Filename prefix (table name)
|
|
* @return void
|
|
*/
|
|
protected function initCsvOutput($prefix)
|
|
{
|
|
// Setting filename:
|
|
$filename = $prefix . '_' . date('dmy-Hi') . '.csv';
|
|
|
|
// Deactivate buffered output! (For huge files)
|
|
// ob_end_clean();
|
|
|
|
// Prepare output stream
|
|
$this->outputStream = fopen('php://output', 'w');
|
|
|
|
// Creating output header:
|
|
header('Content-Type: application/octet-stream');
|
|
header('Content-Disposition: attachment; filename="' . $filename . '"');
|
|
|
|
// Headers to show CSV content in browser
|
|
// header('Content-Type: text/plain');
|
|
// header('Content-Disposition: inline; filename="' . $filename . '"');
|
|
|
|
// Cache-Control header is needed here to solve an issue with browser IE and
|
|
// versions lower than 9. See for more information: http://support.microsoft.com/kb/323308
|
|
header("Cache-Control: ''");
|
|
|
|
$this->addHeaderRowToCSV();
|
|
}
|
|
|
|
/**
|
|
* Adds input row of values to the internal csvLines array as a CSV formatted line
|
|
*
|
|
* @param array $csvRow Array with values to be listed.
|
|
* @return void
|
|
*/
|
|
public function setCsvRow($csvRow)
|
|
{
|
|
if ($this->outputStream !== false) {
|
|
fputcsv($this->outputStream, $csvRow);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Output records of a single table to a downloadable CSV file before the rows get fetched to be displayed
|
|
* by the List module.
|
|
*
|
|
* @param string $table The table to be exported.
|
|
* @param bool|\mysqli_result|object $result The DB handle to read the records.
|
|
*/
|
|
protected function outputCsvFile($table, $result)
|
|
{
|
|
$backendUser = $this->getBackendUserAuthentication();
|
|
$db = $this->getDatabaseConnection();
|
|
|
|
$this->exportedTable = $table;
|
|
$this->titleCol = $GLOBALS['TCA'][$table]['ctrl']['label'];
|
|
$l10nEnabled = $GLOBALS['TCA'][$table]['ctrl']['languageField']
|
|
&& $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']
|
|
&& !$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerTable'];
|
|
|
|
$this->initCsvOutput($table);
|
|
|
|
$cc = 0;
|
|
|
|
// Accumulate rows here
|
|
while ($row = $db->sql_fetch_assoc($result)) {
|
|
if (!$this->isRowListingConditionFulfilled($table, $row)) {
|
|
continue;
|
|
}
|
|
|
|
// In offline workspace, look for alternative record:
|
|
BackendUtility::workspaceOL($table, $row, $backendUser->workspace, true);
|
|
if (is_array($row)) {
|
|
// Render item row if counter < limit
|
|
if ($cc < $this->iLimit) {
|
|
$cc++;
|
|
$this->translations = false;
|
|
|
|
$this->renderListRowForCsv($row);
|
|
|
|
// If localization view is enabled and no search happened it means that the selected
|
|
// records are either default or All language and here we will not select translations
|
|
// which point to the main record:
|
|
if ($this->localizationView && $l10nEnabled && $this->searchString === '') {
|
|
// For each available translation, render the record:
|
|
if (is_array($this->translations)) {
|
|
foreach ($this->translations as $lRow) {
|
|
// $lRow isn't always what we want - if record was moved we've to work with the
|
|
// placeholder records otherwise the list is messed up a bit
|
|
if ($row['_MOVE_PLH_uid'] && $row['_MOVE_PLH_pid']) {
|
|
$where = 't3ver_move_id="' . (int)$lRow['uid'] . '" AND pid="' . $row['_MOVE_PLH_pid']
|
|
. '" AND t3ver_wsid=' . $row['t3ver_wsid'] . BackendUtility::deleteClause($table);
|
|
$tmpRow = BackendUtility::getRecordRaw($table, $where, $this->selFieldList);
|
|
$lRow = is_array($tmpRow) ? $tmpRow : $lRow;
|
|
}
|
|
|
|
// In offline workspace, look for alternative record:
|
|
BackendUtility::workspaceOL($table, $lRow, $backendUser->workspace, true);
|
|
if (is_array($lRow) && $backendUser->checkLanguageAccess($lRow[$GLOBALS['TCA'][$table]['ctrl']['languageField']])) {
|
|
$this->renderListRowForCsv($lRow);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Counter of total rows incremented:
|
|
$this->eCounter++;
|
|
}
|
|
}
|
|
|
|
$db->sql_free_result($result);
|
|
|
|
fclose($this->outputStream);
|
|
|
|
exit();
|
|
}
|
|
|
|
/**
|
|
* Render a single row for CSV
|
|
*
|
|
* @param mixed[] $row Current record
|
|
* @return void
|
|
*/
|
|
protected function renderListRowForCsv($row)
|
|
{
|
|
if (!is_array($row)) {
|
|
return;
|
|
}
|
|
|
|
$id_orig = null;
|
|
|
|
// If in search mode, make sure the preview will show the correct page
|
|
if ((string)$this->searchString !== '') {
|
|
$id_orig = $this->id;
|
|
$this->id = $row['pid'];
|
|
}
|
|
|
|
// Incr. counter.
|
|
$this->counter++;
|
|
|
|
foreach ($this->fieldArray as $fCol) {
|
|
if ($fCol != $this->titleCol
|
|
&& $fCol != 'pid'
|
|
&& $fCol != '_PATH_'
|
|
&& $fCol != '_REF_'
|
|
&& $fCol != '_CONTROL_'
|
|
&& $fCol != '_CLIPBOARD_'
|
|
&& $fCol != '_LOCALIZATION_'
|
|
&& $fCol != '_LOCALIZATION_b'
|
|
) {
|
|
$row[$fCol] = BackendUtility::getProcessedValueExtra($this->exportedTable, $fCol, $row[$fCol], 0, $row['uid']);
|
|
}
|
|
}
|
|
|
|
// Reset the ID if it was overwritten
|
|
if ((string)$this->searchString !== '') {
|
|
$this->id = $id_orig;
|
|
}
|
|
|
|
// Add row to CSV list:
|
|
$this->addToCSV($row);
|
|
}
|
|
}
|