diff --git a/Classes/Hooks/DataHandler.php b/Classes/Hooks/DataHandler.php index e2dae8e..60e7afa 100644 --- a/Classes/Hooks/DataHandler.php +++ b/Classes/Hooks/DataHandler.php @@ -25,6 +25,7 @@ use TYPO3\CMS\Core\Database\DatabaseConnection; use TYPO3\CMS\Core\SingletonInterface; use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Backend\Utility\BackendUtility; /** * Class/Function which offers TCE main hook functions. @@ -95,7 +96,51 @@ public function processDatamap_afterDatabaseOperations( $hook = GeneralUtility::makeInstance(AfterDatabaseOperations::class); if (strpos($id, 'NEW') !== false) { $id = $parentObj->substNEWwithIDs[$id]; - }; + } else { + /*************************************************************************************** + * The backend module display contents elements using the "colPos" from the + * MovePlaceHolder but publishing from a workspace to Live takes "colPos" from the + * new record. This following code synchronize "colPos" value for the new record and + * its MovePlaceHolder record. + */ + + if( $table == 'tt_content' && $status == 'update' ){ + if( isset( $fieldArray['colPos'] ) ){ + //In this case, a tt_content has been moved in or out of a Grid Element + //Now looking for a MovePlaceHolder record associated with the current update + $additionnalFields = $parentObj->recordInfo($table, $id, "t3_origuid, t3ver_state, sorting"); + if ((int)$additionnalFields['t3ver_state'] === 4) { + $movePlaceHolderRecords = BackendUtility::getRecordsByField($table, 't3ver_move_id', $additionnalFields['t3_origuid'], " AND t3ver_state = 3 AND deleted = 0"); + if (is_array($movePlaceHolderRecords) && count($movePlaceHolderRecords) == 1 && is_array($movePlaceHolderRecords[0])) { + $movePlaceHolderRecord = $movePlaceHolderRecords[0]; + $parentObj->updateDB($table, $movePlaceHolderRecord['uid'], array('colPos' => $fieldArray['colPos'] )); + } + } + } + if( isset( $fieldArray['tx_gridelements_container'] ) ) { + $additionnalFields = $parentObj->recordInfo($table, $id, "t3_origuid, t3ver_state, sorting"); + if ((int)$additionnalFields['t3ver_state'] === 4) { + $movePlaceHolderRecords = BackendUtility::getRecordsByField($table, 't3ver_move_id', $additionnalFields['t3_origuid'], " AND t3ver_state = 3 AND deleted = 0"); + if (is_array($movePlaceHolderRecords) && count($movePlaceHolderRecords) == 1 && is_array($movePlaceHolderRecords[0])) { + $movePlaceHolderRecord = $movePlaceHolderRecords[0]; + $parentObj->updateDB($table, $movePlaceHolderRecord['uid'], array( 'tx_gridelements_container' => $fieldArray['tx_gridelements_container'] ) ); + } + } + } + if( isset( $fieldArray['tx_gridelements_columns'] ) ){ + $additionnalFields = $parentObj->recordInfo($table, $id, "t3_origuid, t3ver_state, sorting"); + if ((int)$additionnalFields['t3ver_state'] === 4) { + $movePlaceHolderRecords = BackendUtility::getRecordsByField($table, 't3ver_move_id', $additionnalFields['t3_origuid'], " AND t3ver_state = 3 AND deleted = 0"); + if (is_array($movePlaceHolderRecords) && count($movePlaceHolderRecords) == 1 && is_array($movePlaceHolderRecords[0])) { + $movePlaceHolderRecord = $movePlaceHolderRecords[0]; + $parentObj->updateDB($table, $movePlaceHolderRecord['uid'], array('tx_gridelements_columns' => $fieldArray['tx_gridelements_columns'] )); + } + } + } + } + + /**************************************************************************************/ + } $hook->execute_afterDatabaseOperations($fieldArray, $table, $id, $parentObj); } } diff --git a/Classes/Hooks/DrawItem.php b/Classes/Hooks/DrawItem.php index b40ea1c..85b4662 100644 --- a/Classes/Hooks/DrawItem.php +++ b/Classes/Hooks/DrawItem.php @@ -407,22 +407,77 @@ public function collectItemsForColumns(PageLayoutView $parentObject, &$colPosVal $showLanguage = ''; } - $where = ''; - if ($this->helper->getBackendUser()->workspace > 0 && $row['t3ver_wsid'] > 0) { - $where .= 'AND t3ver_wsid = ' . (int)$row['t3ver_wsid']; + /******************************************************************************************* + * To get the tt_contents related to the current workspace, I used the same method as in + * this function: + * + * \TYPO3\CMS\Backend\Controller\PageLayoutController->makeQuickEditMenu() + * + * NOTICE: In javascript, checking/unchecking the "Show hidden content elements" trigger + * an ajax request to refresh the view. This doesn't influence tt_content inside + * gridelements. This is why the SQL query will always include hidden elements. + */ + $whereClause = ' colPos = -1 ' . BackendUtility::deleteClause('tt_content') + . BackendUtility::versioningPlaceholderClause('tt_content') + . ' AND tx_gridelements_container = ' . $specificIds['uid'] + . ' AND tx_gridelements_columns IN (' . $colPosList . ')' . $showHidden . $deleteClause . $showLanguage . ';'; + $displayRecords = array(); + $res = $this->databaseConnection->exec_SELECTquery('*', 'tt_content', $whereClause, ''); + $newRecords = array(); + while ($cRow = $this->databaseConnection->sql_fetch_assoc($res)) { + $sorting = $cRow['sorting']; + if( $cRow['t3ver_state'] != 1 ){ + BackendUtility::workspaceOL('tt_content', $cRow ); + $cRow['sorting'] = $sorting; + } + if( is_array($cRow) && $cRow['tx_gridelements_container'] == $row['uid'] && $cRow['pid'] == $row['pid'] ) { + $displayRecords[$cRow['uid']] = $cRow; + } + if( $cRow['t3ver_state'] == -1 ){ + $newRecords[$cRow['uid']] = $cRow; + } + } + // Looking for associated MovePlaceHolder records to fetch the sorting value + $t3VerMoveIds = array(); + foreach( $displayRecords as $displayRecord ){ + if( $displayRecord['t3ver_state'] == 4 ){ + $t3VerMoveIds[] = $displayRecord['uid']; + } + if( $displayRecord['t3ver_state'] == 1 ){ + foreach( $newRecords as $newUid => $newRecord ){ + if( $displayRecord['uid'] == $newRecord['t3ver_oid'] ){ + $displayRecords[$newRecord['t3ver_oid']]['hidden'] = $newRecord['hidden']; + $displayRecords[$newRecord['t3ver_oid']]['sorting'] = $newRecord['sorting']; + $displayRecords[$newRecord['t3ver_oid']]['bodytext'] = $newRecord['bodytext']; + } + } + } } - $where .= ' AND colPos = -1 - AND tx_gridelements_container IN (' . (int)$row['uid'] . ',' . $specificIds['uid'] . ') - AND tx_gridelements_columns IN (' . $colPosList . ')' . $showHidden . $deleteClause . $showLanguage; - - $queryParts = $parentObject->makeQueryArray('tt_content', $row['pid'], $where); - - // Due to the pid being "NOT USED" in makeQueryArray we have to reset pidSelect here - $parentObject->pidSelect = $originalPidSelect; - $result = $this->databaseConnection->exec_SELECT_queryArray($queryParts); + if( count( $t3VerMoveIds ) > 0 ){ + $whereClause = $originalPidSelect + . BackendUtility::deleteClause('tt_content') + . ' AND t3ver_state = 3 AND t3ver_move_id IN (' . implode( ',', $t3VerMoveIds ) . ')' + . $showHidden . ';'; + $res = $this->databaseConnection->exec_SELECTquery('*', 'tt_content', $whereClause, ''); + while ($cRow = $this->databaseConnection->sql_fetch_assoc($res)) { + $displayRecords[$cRow['t3ver_move_id']]['sorting'] = $cRow['sorting']; + } + } - return $parentObject->getResult($result); + /* tt_contents are displayed in the order of the returned array. Sorting is + not done using SQL query. The following usort() re-order the tt_contents using the + "sorting" field. + */ + usort( $displayRecords, function( $a, $b){ + if( $a['sorting'] > $b['sorting'] ){ + return 1; + } else{ + return -1; + } + }); + return $displayRecords; + /**************************************************************************************/ } /** @@ -433,7 +488,7 @@ public function collectItemsForColumns(PageLayoutView $parentObject, &$colPosVal * @param int $colPos : The column position we want to get the content for * @param array $values : The layout configuration values for the grid column * @param array $gridContent : The rendered content data of the grid column - * @param $row + * @param array $row : Gridelement row * @param array $editUidList : determines if we will get edit icons or not */ protected function renderSingleGridColumn( @@ -824,6 +879,19 @@ public function collectContentData($shortcutItem, &$collectedItems, &$showHidden */ public function renderSingleElementHTML(PageLayoutView $parentObject, $itemRow) { + /******************************************************************************************* + * With the patch in $this->collectItemsForColumns() function, we need to add tt_content + * ids in the PageLayoutView parent object. Otherwise, the URL generated to edit the + * tt_content caused an error by missing the uid of the tt_content to edit. + */ + if( !isset( $parentObject->tt_contentData['nextThree'][$itemRow['uid']] ) ){ + $parentObject->tt_contentData['nextThree'][$itemRow['uid']] = $itemRow['uid']; + } else { + $parentObject->tt_contentData['nextThree'][$itemRow['uid']] .= "," . $itemRow['uid']; + } + /******************************************************************************************/ + + // @todo $parentObject->lP is gone, defLangBinding is proably not enough for the third param to act correctly $singleElementHTML = $parentObject->tt_content_drawHeader($itemRow, $parentObject->tt_contentConfig['showInfo'] ? 15 : 5, $parentObject->defLangBinding, true, true); @@ -875,6 +943,7 @@ protected function tt_content_drawFooter(PageLayoutView $parentObject, array $ro if (!empty($content)) { $content = '
'; } + return $content; }