/***************************************************************
* Copyright notice
*
- * (c) 2010 Workspaces Team (http://forge.typo3.org/projects/show/typo3v4-workspaces)
+ * (c) 2010-2011 Workspaces Team (http://forge.typo3.org/projects/show/typo3v4-workspaces)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* @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
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');
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.
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);
}
// 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) {
* 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
*/
$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) {
* @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);
// 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 = '';
// 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);
*/
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';
}
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 ';
}
**/
$perms_clause = $GLOBALS['BE_USER']->getPagePermsClause(1);
$searchObj = t3lib_div::makeInstance('t3lib_fullsearch');
- $pageList = $searchObj->getTreeList($pageId, $recursionLevel, 0, $perms_clause);
+ $pageList = FALSE;
+ if ($pageId > 0) {
+ $pageList = $searchObj->getTreeList($pageId, $recursionLevel, 0, $perms_clause);
+ } else {
+ $mountPoints = $GLOBALS['BE_USER']->uc['pageTree_temporaryMountPoint'];
+ if (!is_array($mountPoints) || empty($mountPoints)) {
+ $mountPoints = array_map('intval', $GLOBALS['BE_USER']->returnWebmounts());
+ $mountPoints = array_unique($mountPoints);
+ }
+ $newList = array();
+ foreach($mountPoints as $mountPoint) {
+ $newList[] = $searchObj->getTreeList($mountPoint, $recursionLevel, 0, $perms_clause);
+ }
+ $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');
- $newList = array();
- $pageIds = t3lib_div::intExplode(',', $pageList, TRUE);
-
- foreach ($pageIds as $tmpId) {
- if (isset($movedAwayPages[$tmpId]) && !empty($newList) && !in_array($movedAwayPages[$tmpId]['pid'], intval($newList))) {
- break;
+ // 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;
}
- $newList[] = $tmpId;
}
- $pageList = implode(',', $newList);
- }
+ } while ($changed);
+ $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);
+ if (!in_array($pageId, $pageIds)) {
+ $pageIds[] = $pageId;
+ }
foreach ($pageIds as $pageId) {
if (intval($pages[$pageId]['t3ver_move_id']) > 0) {
$newList[] = intval($pages[$pageId]['t3ver_move_id']);
* @return array
*/
protected function filterPermittedElements($recs, $table) {
- $checkField = ($table == 'pages') ? 'uid' : 'pid';
+ $checkField = ($table == 'pages') ? 'uid' : 'wspid';
$permittedElements = array();
if (is_array($recs)) {
foreach ($recs as $rec) {
}
return $isNewPage;
}
+
+ /**
+ * Generates a view link for a page.
+ *
+ * @static
+ * @param $table
+ * @param $uid
+ * @param $record
+ * @return string
+ */
+ 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_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);
+ }
+ }
+ return $viewUrl;
+ }
+
+ /**
+ * Determine whether this page for the current
+ *
+ * @param $pageUid
+ * @param $workspaceUid
+ * @return void
+ */
+ public function canCreatePreviewLink($pageUid, $workspaceUid) {
+ $result = TRUE;
+ if ($pageUid > 0 && $workspaceUid > 0) {
+ $pageRecord = t3lib_BEfunc::getRecord('pages', $pageUid);
+ t3lib_BEfunc::workspaceOL('pages', $pageRecord, $workspaceUid);
+ if (!t3lib_div::inList($GLOBALS['TYPO3_CONF_VARS']['FE']['content_doktypes'], $pageRecord['doktype'])) {
+ $result = FALSE;
+ }
+ } else {
+ $result = FALSE;
+ }
+ 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') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/workspaces/Classes/Service/Workspaces.php']) {
- include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/workspaces/Classes/Service/Workspaces.php']);
+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