[TASK] Move workspace preview functionality into versioning / workspace
[Packages/TYPO3.CMS.git] / typo3 / sysext / workspaces / Classes / Service / Workspaces.php
index e4753df..c6d0faa 100644 (file)
  * @package Workspaces
  * @subpackage Service
  */
-class tx_Workspaces_Service_Workspaces {
+class tx_Workspaces_Service_Workspaces implements t3lib_Singleton {
+       /**
+        * @var array
+        */
+       protected $pageCache = array();
+
        const TABLE_WORKSPACE = 'sys_workspace';
        const SELECT_ALL_WORKSPACES = -98;
        const LIVE_WORKSPACE_ID = 0;
-       const DRAFT_WORKSPACE_ID = -1;
 
        /**
         * retrieves the available workspaces from the database and checks whether
@@ -49,9 +53,6 @@ class tx_Workspaces_Service_Workspaces {
                if ($GLOBALS['BE_USER']->checkWorkspace(array('uid' => (string) self::LIVE_WORKSPACE_ID))) {
                        $availableWorkspaces[self::LIVE_WORKSPACE_ID] = self::getWorkspaceTitle(self::LIVE_WORKSPACE_ID);
                }
-               if ($GLOBALS['BE_USER']->checkWorkspace(array('uid' => (string) self::DRAFT_WORKSPACE_ID))) {
-                       $availableWorkspaces[self::DRAFT_WORKSPACE_ID] = self::getWorkspaceTitle(self::DRAFT_WORKSPACE_ID);
-               }
 
                        // add custom workspaces (selecting all, filtering by BE_USER check):
                $customWorkspaces = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid, title, adminusers, members', 'sys_workspace', 'pid = 0' . t3lib_BEfunc::deleteClause('sys_workspace'), '', 'title');
@@ -66,6 +67,19 @@ class tx_Workspaces_Service_Workspaces {
                return $availableWorkspaces;
        }
 
+       /**
+        * Gets the current workspace ID.
+        *
+        * @return integer The current workspace ID
+        */
+       public function getCurrentWorkspace() {
+               $workspaceId = $GLOBALS['BE_USER']->workspace;
+               if ($GLOBALS['BE_USER']->isAdmin()) {
+                       $activeId = $GLOBALS['BE_USER']->getSessionData('tx_workspace_activeWorkspace');
+                       $workspaceId = $activeId !== NULL ? $activeId : $workspaceId;
+               }
+               return $workspaceId;
+       }
 
        /**
         * Find the title for the requested workspace.
@@ -79,9 +93,6 @@ class tx_Workspaces_Service_Workspaces {
                        case self::LIVE_WORKSPACE_ID:
                                $title = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_misc.xml:shortcut_onlineWS');
                                break;
-                       case self::DRAFT_WORKSPACE_ID:
-                               $title = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_misc.xml:shortcut_offlineWS');
-                               break;
                        default:
                                $labelField = $GLOBALS['TCA']['sys_workspace']['ctrl']['label'];
                                $wsRecord = t3lib_beFunc::getRecord('sys_workspace', $wsId, 'uid,' . $labelField);
@@ -123,7 +134,7 @@ class tx_Workspaces_Service_Workspaces {
                        }
 
                                // Select all versions to swap:
-                       $versions = $this->selectVersionsInWorkspace($wsid, 0, $stage, ($pageId ? $pageId : -1));
+                       $versions = $this->selectVersionsInWorkspace($wsid, 0, $stage, ($pageId ? $pageId : -1), 0, 'tables_modify');
 
                                // Traverse the selection to build CMD array:
                        foreach ($versions as $table => $records) {
@@ -141,7 +152,7 @@ class tx_Workspaces_Service_Workspaces {
         * Building tcemain CMD-array for releasing all versions in a workspace.
         *
         * @param       integer         Real workspace ID, cannot be ONLINE (zero).
-        * @param       boolean         Run Flush (true) or ClearWSID (false) command
+        * @param       boolean         Run Flush (TRUE) or ClearWSID (FALSE) command
         * @param       integer         $pageId: ...
         * @return      array           Command array for tcemain
         */
@@ -155,7 +166,7 @@ class tx_Workspaces_Service_Workspaces {
                        $stage = -99;
 
                                // Select all versions to swap:
-                       $versions = $this->selectVersionsInWorkspace($wsid, 0, $stage, ($pageId ? $pageId : -1));
+                       $versions = $this->selectVersionsInWorkspace($wsid, 0, $stage, ($pageId ? $pageId : -1), 0, 'tables_modify');
 
                                // Traverse the selection to build CMD array:
                        foreach ($versions as $table => $records) {
@@ -179,9 +190,10 @@ class tx_Workspaces_Service_Workspaces {
         * @param       integer         Stage filter: -99 means no filtering, otherwise it will be used to select only elements with that stage. For publishing, that would be "10"
         * @param       integer         Page id: Live page for which to find versions in workspace!
         * @param       integer         Recursion Level - select versions recursive - parameter is only relevant if $pageId != -1
+        * @param       string          How to collect records for "listing" or "modify" these tables. Support the permissions of each type of record (@see t3lib_userAuthGroup::check).
         * @return      array           Array of all records uids etc. First key is table name, second key incremental integer. Records are associative arrays with uid, t3ver_oid and t3ver_swapmode fields. The pid of the online record is found as "livepid" the pid of the offline record is found in "wspid"
         */
-       public function selectVersionsInWorkspace($wsid, $filter = 0, $stage = -99, $pageId = -1, $recursionLevel = 0) {
+       public function selectVersionsInWorkspace($wsid, $filter = 0, $stage = -99, $pageId = -1, $recursionLevel = 0, $selectionType = 'tables_select') {
 
                $wsid = intval($wsid);
                $filter = intval($filter);
@@ -190,7 +202,7 @@ class tx_Workspaces_Service_Workspaces {
                        // Contains either nothing or a list with live-uids
                if ($pageId != -1 && $recursionLevel > 0) {
                        $pageList = $this->getTreeUids($pageId, $wsid, $recursionLevel);
-               } else if ($pageId != -1) {
+               } elseif ($pageId != -1) {
                        $pageList = $pageId;
                } else {
                        $pageList = '';
@@ -198,6 +210,12 @@ class tx_Workspaces_Service_Workspaces {
 
                        // Traversing all tables supporting versioning:
                foreach ($GLOBALS['TCA'] as $table => $cfg) {
+
+                               // we do not collect records from tables without permissions on them.
+                       if (! $GLOBALS['BE_USER']->check($selectionType, $table)) {
+                               continue;
+                       }
+
                        if ($GLOBALS['TCA'][$table]['ctrl']['versioningWS']) {
 
                                $recs = $this->selectAllVersionsFromPages($table, $pageList, $wsid, $filter, $stage);
@@ -243,7 +261,7 @@ class tx_Workspaces_Service_Workspaces {
                 */
                if ($wsid > self::SELECT_ALL_WORKSPACES) {
                        $where .= ' AND A.t3ver_wsid=' . $wsid;
-               } else if ($wsid === self::SELECT_ALL_WORKSPACES) {
+               } elseif ($wsid === self::SELECT_ALL_WORKSPACES) {
                        $where .= ' AND A.t3ver_wsid!=0';
                }
 
@@ -298,7 +316,7 @@ class tx_Workspaces_Service_Workspaces {
 
                if ($wsid > self::SELECT_ALL_WORKSPACES) {
                        $where .= ' AND A.t3ver_wsid=' . $wsid . ' AND C.t3ver_wsid=' . $wsid;
-               } else if ($wsid === self::SELECT_ALL_WORKSPACES) {
+               } elseif ($wsid === self::SELECT_ALL_WORKSPACES) {
                        $where .= ' AND A.t3ver_wsid!=0 AND C.t3ver_wsid!=0 ';
                }
 
@@ -361,31 +379,48 @@ class tx_Workspaces_Service_Workspaces {
                        }
                        $pageList = implode(',', $newList);
                }
+
                unset($searchObj);
                if (intval($GLOBALS['TCA']['pages']['ctrl']['versioningWS']) === 2 && $pageList) {
-                       if ($pageList) {
-                                       // Remove the "subbranch" if a page was moved away
-                               $movedAwayPages = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid, pid, t3ver_move_id', 'pages', 't3ver_move_id IN (' . $pageList . ') AND t3ver_wsid=' . $wsid . t3lib_BEfunc::deleteClause($table), '', 'uid', '', 't3ver_move_id');
-                               $pageIds = t3lib_div::intExplode(',', $pageList, TRUE);
-
-                                       // move all pages away
-                               $newList = array_diff($pageIds, array_keys($movedAwayPages));
-
-                                       // move back in if still connected to the "remaining" pages
-                               do {
-                                       $changed = FALSE;
-                                       foreach ($movedAwayPages as $uid => $rec) {
-                                               if (in_array($rec['pid'], $newList) && !in_array($uid, $newList)) {
-                                                       $newList[] = $uid;
-                                                       $changed = TRUE;
-                                               }
+                               // Remove the "subbranch" if a page was moved away
+                       $movedAwayPages = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
+                               'uid, pid, t3ver_move_id',
+                               'pages',
+                               't3ver_move_id IN (' . $pageList . ') AND t3ver_wsid=' . intval($wsid) . t3lib_BEfunc::deleteClause('pages'),
+                               '',
+                               'uid',
+                               '',
+                               't3ver_move_id'
+                       );
+                       $pageIds = t3lib_div::intExplode(',', $pageList, TRUE);
+
+                               // move all pages away
+                       $newList = array_diff($pageIds, array_keys($movedAwayPages));
+
+                               // keep current page in the list
+                       $newList[] = $pageId;
+                               // move back in if still connected to the "remaining" pages
+                       do {
+                               $changed = FALSE;
+                               foreach ($movedAwayPages as $uid => $rec) {
+                                       if (in_array($rec['pid'], $newList) && !in_array($uid, $newList)) {
+                                               $newList[] = $uid;
+                                               $changed = TRUE;
                                        }
-                               } while ($changed);
+                               }
+                       } while ($changed);
+                       $pageList = implode(',', $newList);
 
-                               $pageList = implode(',', $newList);
-                       }
                                // In case moving pages is enabled we need to replace all move-to pointer with their origin
-                       $pages = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid, t3ver_move_id', 'pages', 'uid IN (' . $pageList . ')' . t3lib_BEfunc::deleteClause($table), '', 'uid', '', 'uid');
+                       $pages = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
+                               'uid, t3ver_move_id',
+                               'pages',
+                               'uid IN (' . $pageList . ')' . t3lib_BEfunc::deleteClause('pages'),
+                               '',
+                               'uid',
+                               '',
+                               'uid'
+                       );
 
                        $newList = array();
                        $pageIds = t3lib_div::intExplode(',', $pageList, TRUE);
@@ -487,18 +522,18 @@ class tx_Workspaces_Service_Workspaces {
         * @param  $record
         * @return string
         */
-       public static function viewSingleRecord($table, $uid, $record=null) {
+       public static function viewSingleRecord($table, $uid, $record=NULL) {
                $viewUrl = '';
                if ($table == 'pages') {
                        $viewUrl = t3lib_BEfunc::viewOnClick(t3lib_BEfunc::getLiveVersionIdOfRecord('pages', $uid));
-               } elseif ($table == 'pages_language_oderlay' || $table == 'tt_content') {
+               } elseif ($table == 'pages_language_overlay' || $table == 'tt_content') {
                        $elementRecord = is_array($record) ? $record : t3lib_BEfunc::getLiveVersionOfRecord($table, $uid);
                        $viewUrl = t3lib_BEfunc::viewOnClick($elementRecord['pid']);
                } else {
                        if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['workspaces']['viewSingleRecord'])) {
                                $_params = array('table' => $table, 'uid' => $uid, 'record' => $record);
                                $_funcRef = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['workspaces']['viewSingleRecord'];
-                               $viewUrl = t3lib_div::callUserFunction($_funcRef, $_params, null);
+                               $viewUrl = t3lib_div::callUserFunction($_funcRef, $_params, NULL);
                        }
                }
                return $viewUrl;
@@ -524,10 +559,85 @@ class tx_Workspaces_Service_Workspaces {
                }
                return $result;
        }
+
+       /**
+        * Generates a workspace preview link.
+        *
+        * @param integer $uid The ID of the record to be linked
+        * @return string the full domain including the protocol http:// or https://, but without the trailing '/'
+        */
+       public function generateWorkspacePreviewLink($uid) {
+               $previewObject = t3lib_div::makeInstance('Tx_Version_Preview');
+               $timeToLiveHours = $previewObject->getPreviewLinkLifetime();
+               $previewKeyword = $previewObject->compilePreviewKeyword('', $GLOBALS['BE_USER']->user['uid'], ($timeToLiveHours*3600), $this->getCurrentWorkspace());
+
+               $linkParams = array(
+                       'ADMCMD_prev' => $previewKeyword,
+                       'id' => $uid
+               );
+               return t3lib_BEfunc::getViewDomain($uid) . '/index.php?' . t3lib_div::implodeArrayForUrl('', $linkParams);
+       }
+
+       /**
+        * Generates a workspace splitted preview link.
+        *
+        * @param integer $uid The ID of the record to be linked
+        * @param boolean $addDomain Parameter to decide if domain should be added to the generated link, FALSE per default
+        * @return string the preview link without the trailing '/'
+        */
+       public function generateWorkspaceSplittedPreviewLink($uid, $addDomain = FALSE) {
+                       // In case a $pageUid is submitted we need to make sure it points to a live-page
+               if ($uid >  0) {
+                       $uid = $this->getLivePageUid($uid);
+               }
+
+               $objectManager = t3lib_div::makeInstance('Tx_Extbase_Object_ObjectManager');
+               /** @var $uriBuilder Tx_Extbase_MVC_Web_Routing_UriBuilder */
+               $uriBuilder = $objectManager->create('Tx_Extbase_MVC_Web_Routing_UriBuilder');
+               /**
+                *  This seems to be very harsh to set this directly to "/typo3 but the viewOnClick also
+                *  has /index.php as fixed value here and dealing with the backPath is very error-prone
+                *
+                *  @todo make sure this would work in local extension installation too
+                */
+               $backPath = '/' . TYPO3_mainDir;
+               $redirect = $backPath . 'index.php?redirect_url=';
+                       // @todo why do we need these additional params? the URIBuilder should add the controller, but he doesn't :(
+               $additionalParams = '&tx_workspaces_web_workspacesworkspaces%5Bcontroller%5D=Preview&M=web_WorkspacesWorkspaces&id=';
+               $viewScript = $backPath . $uriBuilder->setArguments(array('tx_workspaces_web_workspacesworkspaces' => array('previewWS' => $GLOBALS['BE_USER']->workspace)))
+                                                                                               ->uriFor('index', array(), 'Tx_Workspaces_Controller_PreviewController', 'workspaces', 'web_workspacesworkspaces') . $additionalParams;
+
+               if ($addDomain === TRUE) {
+                       return t3lib_BEfunc::getViewDomain($uid) . $redirect . urlencode($viewScript) . $uid;
+               } else {
+                       return $viewScript;
+               }
+       }
+
+       /**
+        * Find the Live-Uid for a given page,
+        * the results are cached at run-time to avoid too many database-queries
+        *
+        * @throws InvalidArgumentException
+        * @param integer $uid
+        * @return integer
+        */
+       public function getLivePageUid($uid) {
+               if (!isset($this->pageCache[$uid])) {
+                       $pageRecord = t3lib_beFunc::getRecord('pages', $uid);
+                       if (is_array($pageRecord)) {
+                               $this->pageCache[$uid] = ($pageRecord['t3ver_oid'] ? $pageRecord['t3ver_oid'] : $uid);
+                       } else {
+                               throw new InvalidArgumentException('uid is supposed to point to an existing page - given value was:' . $uid, 1290628113);
+                       }
+               }
+
+               return $this->pageCache[$uid];
+       }
 }
 
 
 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/workspaces/Classes/Service/Workspaces.php'])) {
        include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/workspaces/Classes/Service/Workspaces.php']);
 }
-?>
+?>
\ No newline at end of file