From a62280c0bef6280e6e02bd8cdc4a75db7fda2c47 Mon Sep 17 00:00:00 2001 From: Ludwig Rafelsberger <ludwig.rafelsberger@gmx.at> Date: Fri, 15 Jan 2016 18:37:31 +0100 Subject: [PATCH] [FEATURE] Allow exclusion of hidden records on export MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow editors to exclude all disabled records during export preparation (EXT:impexp). When preparing to export a page tree, users can now: - choose to exclude all disabled records recursively. This is the new default behaviour - toggle all disabled records which are scheduled to be exported (convenience method, this was already possible by manually checking all these records. Resolves: #19157 Releases: master Change-Id: Ibb3534151a9d08cf4a60b54430678563d6feb5be Reviewed-on: https://review.typo3.org/45960 Reviewed-by: Anja Leichsenring <aleichsenring@ab-softlab.de> Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de> Reviewed-by: Reinhard Führicht <rf@typoheads.at> Tested-by: Reinhard Führicht <rf@typoheads.at> Reviewed-by: Morton Jonuschat <m.jonuschat@mojocode.de> Tested-by: Morton Jonuschat <m.jonuschat@mojocode.de> --- ...dHaveAnOptionToExcludeAllHiddenRecords.rst | 14 ++++ .../Controller/ImportExportController.php | 34 +++++++- typo3/sysext/impexp/Classes/Export.php | 3 + typo3/sysext/impexp/Classes/ImportExport.php | 81 ++++++++++++++++++- .../Resources/Private/Language/locallang.xlf | 14 +++- .../Private/Partials/ContentOverview.html | 17 +++- .../Partials/Export/Configuration.html | 8 +- .../Public/JavaScript/ImportExport.js | 5 ++ 8 files changed, 160 insertions(+), 16 deletions(-) create mode 100644 typo3/sysext/core/Documentation/Changelog/master/Feature-19157-impexpCouldHaveAnOptionToExcludeAllHiddenRecords.rst diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-19157-impexpCouldHaveAnOptionToExcludeAllHiddenRecords.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-19157-impexpCouldHaveAnOptionToExcludeAllHiddenRecords.rst new file mode 100644 index 000000000000..7cb091612ea4 --- /dev/null +++ b/typo3/sysext/core/Documentation/Changelog/master/Feature-19157-impexpCouldHaveAnOptionToExcludeAllHiddenRecords.rst @@ -0,0 +1,14 @@ +======================================================================== +Feature: #19157 - Add option to exclude all hidden records in EXT:impexp +======================================================================== + +Description +=========== + +The export configuration of EXT:impexp has been extended to allow to +completely deactivate exporting of hidden/deactivated records. This +behaviour can be controlled via a new option which is checked by default. + +Furthermore, if the inclusion of hidden records is activated (which is +now an explicit choice), then an additional button is shown, allowing +users to preselect all hidden records for manual exclusion. diff --git a/typo3/sysext/impexp/Classes/Controller/ImportExportController.php b/typo3/sysext/impexp/Classes/Controller/ImportExportController.php index df846cac03c0..1a9f3808d936 100644 --- a/typo3/sysext/impexp/Classes/Controller/ImportExportController.php +++ b/typo3/sysext/impexp/Classes/Controller/ImportExportController.php @@ -34,12 +34,12 @@ use TYPO3\CMS\Core\Utility\ExtensionManagementUtility; use TYPO3\CMS\Core\Utility\File\ExtendedFileUtility; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Utility\MathUtility; +use TYPO3\CMS\Fluid\View\StandaloneView; use TYPO3\CMS\Impexp\Domain\Repository\PresetRepository; use TYPO3\CMS\Impexp\Export; use TYPO3\CMS\Impexp\Import; use TYPO3\CMS\Impexp\View\ExportPageTreeView; use TYPO3\CMS\Lang\LanguageService; -use TYPO3\CMS\Fluid\View\StandaloneView; /** * Main script class for the Import / Export facility @@ -126,6 +126,11 @@ class ImportExportController extends BaseScriptClass */ protected $standaloneView = null; + /** + * @var bool + */ + protected $excludeDisabledRecords = false; + /** * Constructor */ @@ -185,6 +190,10 @@ class ImportExportController extends BaseScriptClass // Input data grabbed: $inData = GeneralUtility::_GP('tx_impexp'); + if (!array_key_exists('excludeDisabled', $inData)) { + // flag doesn't exist initially; state is on by default + $inData['excludeDisabled'] = 1; + } $this->standaloneView->assign('moduleUrl', BackendUtility::getModuleUrl('xMOD_tximpexp')); $this->standaloneView->assign('id', $this->id); $this->standaloneView->assign('inData', $inData); @@ -343,6 +352,8 @@ class ImportExportController extends BaseScriptClass $this->export->extensionDependencies = (array)$inData['extension_dep']; $this->export->showStaticRelations = $inData['showStaticRelations']; $this->export->includeExtFileResources = !$inData['excludeHTMLfileResources']; + $this->excludeDisabledRecords = (bool)$inData['excludeDisabled']; + $this->export->setExcludeDisabledRecords($this->excludeDisabledRecords); // Static tables: if (is_array($inData['external_static']['tables'])) { @@ -396,6 +407,9 @@ class ImportExportController extends BaseScriptClass $idH = null; if ($inData['pagetree']['levels'] == -1) { $pagetree = GeneralUtility::makeInstance(ExportPageTreeView::class); + if ($this->excludeDisabledRecords) { + $pagetree->init(BackendUtility::BEenableFields('pages')); + } $tree = $pagetree->ext_tree($inData['pagetree']['id'], $this->filterPageIds($this->export->excludeMap)); $this->treeHTML = $pagetree->printTree($tree); $idH = $pagetree->buffer_idH; @@ -416,7 +430,11 @@ class ImportExportController extends BaseScriptClass if (is_array($sPage)) { $pid = $inData['pagetree']['id']; $tree = GeneralUtility::makeInstance(PageTreeView::class); - $tree->init('AND ' . $this->perms_clause . $this->filterPageIds($this->export->excludeMap)); + $initClause = 'AND ' . $this->perms_clause . $this->filterPageIds($this->export->excludeMap); + if ($this->excludeDisabledRecords) { + $initClause .= BackendUtility::BEenableFields('pages'); + } + $tree->init($initClause); $HTML = $this->iconFactory->getIconForRecord('pages', $sPage, Icon::SIZE_SMALL)->render(); $tree->tree[] = array('row' => $sPage, 'HTML' => $HTML); $tree->buffer_idH = array(); @@ -539,7 +557,10 @@ class ImportExportController extends BaseScriptClass $this->standaloneView->assign('errors', $this->export->errorLog); // Generate overview: - $this->standaloneView->assign('contentOverview', $this->export->displayContentOverview()); + $this->standaloneView->assign( + 'contentOverview', + $this->export->displayContentOverview() + ); } /** @@ -583,10 +604,15 @@ class ImportExportController extends BaseScriptClass $orderBy = $GLOBALS['TCA'][$table]['ctrl']['sortby'] ? 'ORDER BY ' . $GLOBALS['TCA'][$table]['ctrl']['sortby'] : $GLOBALS['TCA'][$table]['ctrl']['default_sortby']; + + $whereClause = 'pid=' . (int)$pid . BackendUtility::deleteClause($table) . BackendUtility::versioningPlaceholderClause($table); + if ($this->excludeDisabledRecords) { + $whereClause .= BackendUtility::BEenableFields($table); + } $res = $db->exec_SELECTquery( '*', $table, - 'pid=' . (int)$pid . BackendUtility::deleteClause($table) . BackendUtility::versioningPlaceholderClause($table), + $whereClause, '', $db->stripOrderBy($orderBy), $limit diff --git a/typo3/sysext/impexp/Classes/Export.php b/typo3/sysext/impexp/Classes/Export.php index 66ad7c6f75a4..1ebfaee7ce15 100644 --- a/typo3/sysext/impexp/Classes/Export.php +++ b/typo3/sysext/impexp/Classes/Export.php @@ -307,6 +307,9 @@ class Export extends ImportExport public function export_addRecord($table, $row, $relationLevel = 0) { BackendUtility::workspaceOL($table, $row); + if ($this->excludeDisabledRecords && !$this->isActive($table, $row['uid'])) { + return; + } if ((string)$table !== '' && is_array($row) && $row['uid'] > 0 && !$this->excludeMap[$table . ':' . $row['uid']]) { if ($this->checkPID($table === 'pages' ? $row['uid'] : $row['pid'])) { if (!isset($this->dat['records'][$table . ':' . $row['uid']])) { diff --git a/typo3/sysext/impexp/Classes/ImportExport.php b/typo3/sysext/impexp/Classes/ImportExport.php index 2ba411cb2678..4f75bcbf57a4 100644 --- a/typo3/sysext/impexp/Classes/ImportExport.php +++ b/typo3/sysext/impexp/Classes/ImportExport.php @@ -252,6 +252,14 @@ abstract class ImportExport */ protected $iconFactory; + /** + * Flag to control whether all disabled records and their children are excluded (true) or included (false). Defaults + * to the old behaviour of including everything. + * + * @var bool + */ + protected $excludeDisabledRecords = false; + /** * The constructor */ @@ -305,7 +313,7 @@ abstract class ImportExport if (is_array($this->dat['header']['pagetree'])) { reset($this->dat['header']['pagetree']); $lines = array(); - $this->traversePageTree($this->dat['header']['pagetree'], $lines); + $this->traversePageTree($this->dat['header']['pagetree'], $lines, ''); $viewData['dat'] = $this->dat; $viewData['update'] = $this->update; @@ -353,6 +361,11 @@ abstract class ImportExport public function traversePageTree($pT, &$lines, $preCode = '') { foreach ($pT as $k => $v) { + if ($this->excludeDisabledRecords === true && !$this->isActive('pages', $k)) { + $this->excludePageAndRecords($k, $v); + continue; + } + // Add this page: $this->singleRecordLines('pages', $k, $lines, $preCode); // Subrecords: @@ -373,6 +386,53 @@ abstract class ImportExport } } + /** + * Test whether a record is active (i.e. not hidden) + * + * @param string $table Name of the records' database table + * @param int $uid Database uid of the record + * @return bool true if the record is active, false otherwise + */ + protected function isActive($table, $uid) + { + return + !isset($GLOBALS['TCA'][$table]['ctrl']['enablecolumns']['disabled']) + || !(bool)$this->dat['records'][$table . ':' . $uid]['data'][ + $GLOBALS['TCA']['pages']['ctrl']['enablecolumns']['disabled'] + ]; + } + + /** + * Exclude a page, its sub pages (recursively) and records placed in them from this import/export + * + * @param int $pageUid Uid of the page to exclude + * @param array $pageTree Page tree array with uid/subrow (from ->dat[header][pagetree] + * @return void + */ + protected function excludePageAndRecords($pageUid, $pageTree) + { + // Prevent having this page appear in "remaining records" table + unset($this->remainHeader['records']['pages'][$pageUid]); + + // Subrecords + if (is_array($this->dat['header']['pid_lookup'][$pageUid])) { + foreach ($this->dat['header']['pid_lookup'][$pageUid] as $table => $recordData) { + if ($table != 'pages') { + foreach (array_keys($recordData) as $uid) { + unset($this->remainHeader['records'][$table][$uid]); + } + } + } + unset($this->remainHeader['pid_lookup'][$pageUid]); + } + // Subpages excluded recursively + if (is_array($pageTree['subrow'])) { + foreach ($pageTree['subrow'] as $subPageUid => $subPageTree) { + $this->excludePageAndRecords($subPageUid, $subPageTree); + } + } + } + /** * Go through remaining pages (not in tree) * @@ -466,6 +526,9 @@ abstract class ImportExport $pInfo['msg'] = 'UNKNOWN TABLE \'' . $pInfo['ref'] . '\''; $pInfo['title'] = '<em>' . htmlspecialchars($record['title']) . '</em>'; } else { + // prepare data attribute telling whether the record is active or hidden, allowing frontend bulk selection + $pInfo['active'] = $this->isActive($table, $uid) ? 'active' : 'hidden'; + // Otherwise, set table icon and title. // Import Validation (triggered by $this->display_import_pid_record) will show messages if import is not possible of various items. if (is_array($this->display_import_pid_record) && !empty($this->display_import_pid_record)) { @@ -805,7 +868,7 @@ abstract class ImportExport { if ($this->mode === 'export') { if ($r['type'] === 'record') { - return '<input type="checkbox" name="tx_impexp[exclude][' . $r['ref'] . ']" id="checkExclude' . $r['ref'] . '" value="1" /> <label for="checkExclude' . $r['ref'] . '">' . $this->getLanguageService()->getLL('impexpcore_singlereco_exclude', true) . '</label>'; + return '<input type="checkbox" class="t3js-exclude-checkbox" name="tx_impexp[exclude][' . $r['ref'] . ']" id="checkExclude' . $r['ref'] . '" value="1" /> <label for="checkExclude' . $r['ref'] . '">' . $this->getLanguageService()->getLL('impexpcore_singlereco_exclude', true) . '</label>'; } else { return $r['type'] == 'softref' ? $this->softrefSelector($r['_softRefInfo']) : ''; } @@ -1182,6 +1245,19 @@ abstract class ImportExport } } + /** + * Set flag to control whether disabled records and their children are excluded (true) or included (false). Defaults + * to the old behaviour of including everything. + * + * @param bool $excludeDisabledRecords Set to true if if all disabled records should be excluded, false otherwise + * @return \TYPO3\CMS\Impexp\ImportExport $this for fluent calls + */ + public function setExcludeDisabledRecords($excludeDisabledRecords = false) + { + $this->excludeDisabledRecords = $excludeDisabledRecords; + return $this; + } + /***************************** * Error handling *****************************/ @@ -1230,5 +1306,4 @@ abstract class ImportExport { return $GLOBALS['LANG']; } - } diff --git a/typo3/sysext/impexp/Resources/Private/Language/locallang.xlf b/typo3/sysext/impexp/Resources/Private/Language/locallang.xlf index 4cbd983aad20..818ae8dce449 100644 --- a/typo3/sysext/impexp/Resources/Private/Language/locallang.xlf +++ b/typo3/sysext/impexp/Resources/Private/Language/locallang.xlf @@ -45,6 +45,9 @@ <trans-unit id="execlistqu_structureToBeExported"> <source>Structure to be exported:</source> </trans-unit> + <trans-unit id="impexpcore_toggle_all_disabled_records"> + <source>Toggle disabled records</source> + </trans-unit> <trans-unit id="execlistqu_maxNumberLimit"> <source>Max number limit!</source> </trans-unit> @@ -108,11 +111,14 @@ <trans-unit id="makeconfig_excludeElements"> <source>Exclude elements:</source> </trans-unit> - <trans-unit id="makeconfig_clearAllExclusions"> - <source>Clear all exclusions:</source> + <trans-unit id="makeconfig_clearAllManualExclusions"> + <source>Clear all manual exclusions:</source> + </trans-unit> + <trans-unit id="makeconfig_noManuallyExcludedElementsYet"> + <source>No manually excluded elements yet. Exclude by setting checkboxes below in the element display.</source> </trans-unit> - <trans-unit id="makeconfig_noExcludedElementsYet"> - <source>No excluded elements yet. Exclude by setting checkboxes below in the element display.</source> + <trans-unit id="makeconfig_excludeDisabledElements"> + <source>Exclude disabled elements</source> </trans-unit> <trans-unit id="makeadvanc_update"> <source>Update</source> diff --git a/typo3/sysext/impexp/Resources/Private/Partials/ContentOverview.html b/typo3/sysext/impexp/Resources/Private/Partials/ContentOverview.html index 0026384097e6..d877488fa3de 100644 --- a/typo3/sysext/impexp/Resources/Private/Partials/ContentOverview.html +++ b/typo3/sysext/impexp/Resources/Private/Partials/ContentOverview.html @@ -19,9 +19,18 @@ </f:else> </f:if> <div> + <f:if condition="{inData.excludeDisabled}"> + <f:else> + <f:if condition="{inData.action} == 'export'"> + <f:form.button class="btn btn-default t3js-impexp-toggledisabled" type="button"> + <f:translate key="impexpcore_toggle_all_disabled_records" /> + </f:form.button> + </f:if> + </f:else> + </f:if> <f:if condition="{contentOverview.dat.header.pagetree -> f:count()} > 0"> <h3><f:translate key="impexpcore_displaycon_insidePagetree" /></h3> - <table class="table table-striped table-hover"> + <table class="table table-striped table-hover t3js-impexp-preview"> <tbody> <tr> <th><f:translate key="impexpcore_displaycon_controls" /></th> @@ -37,7 +46,7 @@ </f:if> </tr> <f:for each="{contentOverview.pagetreeLines}" as="line"> - <tr> + <tr data-active="{line.active}"> <td><f:format.raw>{line.controls}</f:format.raw></td> <td class="col-nowrap"><f:format.raw>{line.preCode}{line.title}</f:format.raw></td> <td class="col-nowrap"><f:format.raw>{line.fileSize}</f:format.raw></td> @@ -56,9 +65,9 @@ </f:if> <f:if condition="{contentOverview.remainingRecords -> f:count()} > 0"> <h3><f:translate key="impexpcore_singlereco_outsidePagetree" /></h3> - <table class="table table-striped table-hover"> + <table class="table table-striped table-hover t3js-impexp-preview"> <tbody> - <tr> + <tr data-active="{line.active}"> <th><f:translate key="impexpcore_displaycon_controls" /></th> <th><f:translate key="impexpcore_displaycon_title" /></th> <th><f:translate key="impexpcore_displaycon_size" /></th> diff --git a/typo3/sysext/impexp/Resources/Private/Partials/Export/Configuration.html b/typo3/sysext/impexp/Resources/Private/Partials/Export/Configuration.html index b8deaff5b21f..db45732e6c6f 100644 --- a/typo3/sysext/impexp/Resources/Private/Partials/Export/Configuration.html +++ b/typo3/sysext/impexp/Resources/Private/Partials/Export/Configuration.html @@ -143,10 +143,16 @@ </label> </f:then> <f:else> - <f:translate key="makeconfig_noExcludedElementsYet" /> + <f:translate key="makeconfig_noManuallyExcludedElementsYet" /> </f:else> </f:if> </p> + <p class="form-control-static"> + <label for="checkExcludeDisabled"> + <f:form.checkbox name="tx_impexp[excludeDisabled]" id="checkExcludeDisabled" value="1" checked="{inData.excludeDisabled}" /> + <f:translate key="makeconfig_excludeDisabledElements" /> + </label> + </p> </div> <div class="form-group"> diff --git a/typo3/sysext/impexp/Resources/Public/JavaScript/ImportExport.js b/typo3/sysext/impexp/Resources/Public/JavaScript/ImportExport.js index 8ab3de89a449..cc5f843feda2 100644 --- a/typo3/sysext/impexp/Resources/Public/JavaScript/ImportExport.js +++ b/typo3/sysext/impexp/Resources/Public/JavaScript/ImportExport.js @@ -33,5 +33,10 @@ define(['jquery', 'TYPO3/CMS/Backend/Modal'], function ($, Modal) { Modal.currentModal.trigger('modal-dismiss'); }); }); + + $('.t3js-impexp-toggledisabled').on('click', function() { + var $checkboxes = $('table.t3js-impexp-preview tr[data-active="hidden"] input.t3js-exclude-checkbox'); + $checkboxes.prop('checked', !$checkboxes.get(0).checked); + }); }); }); -- GitLab