[BUGFIX] html-escaping of workspace-title too much
[Packages/TYPO3.CMS.git] / typo3 / sysext / workspaces / Classes / Service / Workspaces.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2010-2011 Workspaces Team (http://forge.typo3.org/projects/show/typo3v4-workspaces)
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
18 *
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27
28 /**
29 * @author Workspaces Team (http://forge.typo3.org/projects/show/typo3v4-workspaces)
30 * @package Workspaces
31 * @subpackage Service
32 */
33 class Tx_Workspaces_Service_Workspaces implements t3lib_Singleton {
34 /**
35 * @var array
36 */
37 protected $pageCache = array();
38
39 const TABLE_WORKSPACE = 'sys_workspace';
40 const SELECT_ALL_WORKSPACES = -98;
41 const LIVE_WORKSPACE_ID = 0;
42
43 /**
44 * retrieves the available workspaces from the database and checks whether
45 * they're available to the current BE user
46 *
47 * @return array array of worspaces available to the current user
48 */
49 public function getAvailableWorkspaces() {
50 $availableWorkspaces = array();
51
52 // add default workspaces
53 if ($GLOBALS['BE_USER']->checkWorkspace(array('uid' => (string) self::LIVE_WORKSPACE_ID))) {
54 $availableWorkspaces[self::LIVE_WORKSPACE_ID] = self::getWorkspaceTitle(self::LIVE_WORKSPACE_ID);
55 }
56
57 // add custom workspaces (selecting all, filtering by BE_USER check):
58 $customWorkspaces = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid, title, adminusers, members', 'sys_workspace', 'pid = 0' . t3lib_BEfunc::deleteClause('sys_workspace'), '', 'title');
59 if (count($customWorkspaces)) {
60 foreach ($customWorkspaces as $workspace) {
61 if ($GLOBALS['BE_USER']->checkWorkspace($workspace)) {
62 $availableWorkspaces[$workspace['uid']] = $workspace['title'];
63 }
64 }
65 }
66
67 return $availableWorkspaces;
68 }
69
70 /**
71 * Gets the current workspace ID.
72 *
73 * @return integer The current workspace ID
74 */
75 public function getCurrentWorkspace() {
76 $workspaceId = $GLOBALS['BE_USER']->workspace;
77 if ($GLOBALS['BE_USER']->isAdmin()) {
78 $activeId = $GLOBALS['BE_USER']->getSessionData('tx_workspace_activeWorkspace');
79 $workspaceId = $activeId !== NULL ? $activeId : $workspaceId;
80 }
81 return $workspaceId;
82 }
83
84 /**
85 * Find the title for the requested workspace.
86 *
87 * @param integer $wsId
88 * @return string
89 */
90 public static function getWorkspaceTitle($wsId) {
91 $title = FALSE;
92 switch ($wsId) {
93 case self::LIVE_WORKSPACE_ID:
94 $title = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_misc.xml:shortcut_onlineWS');
95 break;
96 default:
97 $labelField = $GLOBALS['TCA']['sys_workspace']['ctrl']['label'];
98 $wsRecord = t3lib_beFunc::getRecord('sys_workspace', $wsId, 'uid,' . $labelField);
99 if (is_array($wsRecord)) {
100 $title = $wsRecord[$labelField];
101 }
102 }
103
104 if ($title === FALSE) {
105 throw new InvalidArgumentException('No such workspace defined');
106 }
107
108 return $title;
109 }
110
111
112 /**
113 * Building tcemain CMD-array for swapping all versions in a workspace.
114 *
115 * @param integer Real workspace ID, cannot be ONLINE (zero).
116 * @param boolean If set, then the currently online versions are swapped into the workspace in exchange for the offline versions. Otherwise the workspace is emptied.
117 * @param integer $pageId: ...
118 * @return array Command array for tcemain
119 */
120 public function getCmdArrayForPublishWS($wsid, $doSwap, $pageId = 0) {
121
122 $wsid = intval($wsid);
123 $cmd = array();
124
125 if ($wsid >= -1 && $wsid!==0) {
126
127 // Define stage to select:
128 $stage = -99;
129 if ($wsid > 0) {
130 $workspaceRec = t3lib_BEfunc::getRecord('sys_workspace', $wsid);
131 if ($workspaceRec['publish_access'] & 1) {
132 $stage = Tx_Workspaces_Service_Stages::STAGE_PUBLISH_ID;
133 }
134 }
135
136 // Select all versions to swap:
137 $versions = $this->selectVersionsInWorkspace($wsid, 0, $stage, ($pageId ? $pageId : -1), 0, 'tables_modify');
138
139 // Traverse the selection to build CMD array:
140 foreach ($versions as $table => $records) {
141 foreach ($records as $rec) {
142 // Build the cmd Array:
143 $cmd[$table][$rec['t3ver_oid']]['version'] = array('action' => 'swap', 'swapWith' => $rec['uid'], 'swapIntoWS' => $doSwap ? 1 : 0);
144 }
145 }
146 }
147 return $cmd;
148 }
149
150
151 /**
152 * Building tcemain CMD-array for releasing all versions in a workspace.
153 *
154 * @param integer Real workspace ID, cannot be ONLINE (zero).
155 * @param boolean Run Flush (TRUE) or ClearWSID (FALSE) command
156 * @param integer $pageId: ...
157 * @return array Command array for tcemain
158 */
159 public function getCmdArrayForFlushWS($wsid, $flush = TRUE, $pageId = 0) {
160
161 $wsid = intval($wsid);
162 $cmd = array();
163
164 if ($wsid >= -1 && $wsid!==0) {
165 // Define stage to select:
166 $stage = -99;
167
168 // Select all versions to swap:
169 $versions = $this->selectVersionsInWorkspace($wsid, 0, $stage, ($pageId ? $pageId : -1), 0, 'tables_modify');
170
171 // Traverse the selection to build CMD array:
172 foreach ($versions as $table => $records) {
173 foreach ($records as $rec) {
174 // Build the cmd Array:
175 $cmd[$table][$rec['uid']]['version'] = array('action' => ($flush ? 'flush' : 'clearWSID'));
176 }
177 }
178 }
179 return $cmd;
180 }
181
182
183 /**
184 * Select all records from workspace pending for publishing
185 * Used from backend to display workspace overview
186 * User for auto-publishing for selecting versions for publication
187 *
188 * @param integer Workspace ID. If -99, will select ALL versions from ANY workspace. If -98 will select all but ONLINE. >=-1 will select from the actual workspace
189 * @param integer Lifecycle filter: 1 = select all drafts (never-published), 2 = select all published one or more times (archive/multiple), anything else selects all.
190 * @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"
191 * @param integer Page id: Live page for which to find versions in workspace!
192 * @param integer Recursion Level - select versions recursive - parameter is only relevant if $pageId != -1
193 * @param string How to collect records for "listing" or "modify" these tables. Support the permissions of each type of record (@see t3lib_userAuthGroup::check).
194 * @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"
195 */
196 public function selectVersionsInWorkspace($wsid, $filter = 0, $stage = -99, $pageId = -1, $recursionLevel = 0, $selectionType = 'tables_select') {
197
198 $wsid = intval($wsid);
199 $filter = intval($filter);
200 $output = array();
201
202 // Contains either nothing or a list with live-uids
203 if ($pageId != -1 && $recursionLevel > 0) {
204 $pageList = $this->getTreeUids($pageId, $wsid, $recursionLevel);
205 } elseif ($pageId != -1) {
206 $pageList = $pageId;
207 } else {
208 $pageList = '';
209 }
210
211 // Traversing all tables supporting versioning:
212 foreach ($GLOBALS['TCA'] as $table => $cfg) {
213
214 // we do not collect records from tables without permissions on them.
215 if (! $GLOBALS['BE_USER']->check($selectionType, $table)) {
216 continue;
217 }
218
219 if ($GLOBALS['TCA'][$table]['ctrl']['versioningWS']) {
220
221 $recs = $this->selectAllVersionsFromPages($table, $pageList, $wsid, $filter, $stage);
222 if (intval($GLOBALS['TCA'][$table]['ctrl']['versioningWS']) === 2) {
223 $moveRecs = $this->getMoveToPlaceHolderFromPages($table, $pageList, $wsid, $filter, $stage);
224 $recs = array_merge($recs, $moveRecs);
225 }
226 $recs = $this->filterPermittedElements($recs, $table);
227 if (count($recs)) {
228 $output[$table] = $recs;
229 }
230 }
231 }
232 return $output;
233 }
234
235 /**
236 * Find all versionized elements except moved records.
237 *
238 * @param string $table
239 * @param string $pageList
240 * @param integer $wsid
241 * @param integer $filter
242 * @param integer $stage
243 * @return array
244 */
245 protected function selectAllVersionsFromPages($table, $pageList, $wsid, $filter, $stage) {
246
247 $fields = 'A.uid, A.t3ver_oid, A.t3ver_stage, ' . ($table==='pages' ? ' A.t3ver_swapmode,' : '') . 'B.pid AS wspid, B.pid AS livepid';
248 if (t3lib_BEfunc::isTableLocalizable($table)) {
249 $fields .= ', A.' . $GLOBALS['TCA'][$table]['ctrl']['languageField'];
250 }
251 $from = $table . ' A,' . $table . ' B';
252
253 // Table A is the offline version and pid=-1 defines offline
254 $where = 'A.pid=-1 AND A.t3ver_state!=4';
255 if ($pageList) {
256 $pidField = ($table==='pages' ? 'uid' : 'pid');
257 $pidConstraint = strstr($pageList, ',') ? ' IN (' . $pageList . ')' : '=' . $pageList;
258 $where .= ' AND B.' . $pidField . $pidConstraint;
259 }
260
261 /**
262 * For "real" workspace numbers, select by that.
263 * If = -98, select all that are NOT online (zero).
264 * Anything else below -1 will not select on the wsid and therefore select all!
265 */
266 if ($wsid > self::SELECT_ALL_WORKSPACES) {
267 $where .= ' AND A.t3ver_wsid=' . $wsid;
268 } elseif ($wsid === self::SELECT_ALL_WORKSPACES) {
269 $where .= ' AND A.t3ver_wsid!=0';
270 }
271
272 /**
273 * lifecycle filter:
274 * 1 = select all drafts (never-published),
275 * 2 = select all published one or more times (archive/multiple)
276 */
277 if ($filter===1 || $filter===2) {
278 $where .= ' AND A.t3ver_count ' . ($filter === 1 ? '= 0' : '> 0');
279 }
280
281 if ($stage != -99) {
282 $where .= ' AND A.t3ver_stage=' . intval($stage);
283 }
284
285 // Table B (online) must have PID >= 0 to signify being online.
286 $where .= ' AND B.pid>=0';
287 // ... and finally the join between the two tables.
288 $where .= ' AND A.t3ver_oid=B.uid';
289 $where .= t3lib_BEfunc::deleteClause($table, 'A');
290 $where .= t3lib_BEfunc::deleteClause($table, 'B');
291
292 /**
293 * Select all records from this table in the database from the workspace
294 * This joins the online version with the offline version as tables A and B
295 * Order by UID, mostly to have a sorting in the backend overview module which doesn't "jump around" when swapping.
296 */
297 $res = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows($fields, $from, $where, '', 'B.uid');
298 return is_array($res) ? $res : array();
299 }
300
301 /**
302 * Find all moved records at their new position.
303 *
304 * @param string $table
305 * @param string $pageList
306 * @param integer $wsid
307 * @param integer $filter
308 * @param integer $stage
309 * @return array
310 */
311 protected function getMoveToPlaceHolderFromPages($table, $pageList, $wsid, $filter, $stage) {
312
313 /**
314 * Aliases:
315 * A - moveTo placeholder
316 * B - online record
317 * C - moveFrom placeholder
318 */
319 $fields = 'A.pid AS wspid, B.uid AS t3ver_oid, C.uid AS uid, B.pid AS livepid';
320 $from = $table . ' A, ' . $table . ' B,' . $table . ' C';
321 $where = 'A.t3ver_state=3 AND B.pid>0 AND B.t3ver_state=0 AND B.t3ver_wsid=0 AND C.pid=-1 AND C.t3ver_state=4';
322
323 if ($wsid > self::SELECT_ALL_WORKSPACES) {
324 $where .= ' AND A.t3ver_wsid=' . $wsid . ' AND C.t3ver_wsid=' . $wsid;
325 } elseif ($wsid === self::SELECT_ALL_WORKSPACES) {
326 $where .= ' AND A.t3ver_wsid!=0 AND C.t3ver_wsid!=0 ';
327 }
328
329 /**
330 * lifecycle filter:
331 * 1 = select all drafts (never-published),
332 * 2 = select all published one or more times (archive/multiple)
333 */
334 if ($filter===1 || $filter===2) {
335 $where .= ' AND C.t3ver_count ' . ($filter === 1 ? '= 0' : '> 0');
336 }
337
338 if ($stage != -99) {
339 $where .= ' AND C.t3ver_stage=' . intval($stage);
340 }
341
342 if ($pageList) {
343 $pidField = ($table==='pages' ? 'B.uid' : 'A.pid');
344 $pidConstraint = strstr($pageList, ',') ? ' IN (' . $pageList . ')' : '=' . $pageList;
345 $where .= ' AND ' . $pidField . $pidConstraint;
346 }
347
348 $where .= ' AND A.t3ver_move_id = B.uid AND B.uid = C.t3ver_oid';
349 $where .= t3lib_BEfunc::deleteClause($table, 'A');
350 $where .= t3lib_BEfunc::deleteClause($table, 'B');
351 $where .= t3lib_BEfunc::deleteClause($table, 'C');
352 $res = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows($fields, $from, $where, '', 'A.uid');
353
354 return is_array($res) ? $res : array();
355 }
356
357
358 /**
359 * Find all page uids recursive starting from a specific page
360 *
361 * @param integer $pageId
362 * @param integer $wsid
363 * @param integer $recursionLevel
364 * @return string Comma sep. uid list
365 */
366 protected function getTreeUids($pageId, $wsid, $recursionLevel) {
367 /**
368 * Reusing existing functionality with the drawback that
369 * mount points are not covered yet
370 **/
371 $perms_clause = $GLOBALS['BE_USER']->getPagePermsClause(1);
372 $searchObj = t3lib_div::makeInstance('t3lib_fullsearch');
373 $pageList = FALSE;
374 if ($pageId > 0) {
375 $pageList = $searchObj->getTreeList($pageId, $recursionLevel, 0, $perms_clause);
376 } else {
377 $mountPoints = $GLOBALS['BE_USER']->uc['pageTree_temporaryMountPoint'];
378 if (!is_array($mountPoints) || empty($mountPoints)) {
379 $mountPoints = array_map('intval', $GLOBALS['BE_USER']->returnWebmounts());
380 $mountPoints = array_unique($mountPoints);
381 }
382 $newList = array();
383 foreach($mountPoints as $mountPoint) {
384 $newList[] = $searchObj->getTreeList($mountPoint, $recursionLevel, 0, $perms_clause);
385 }
386 $pageList = implode(',', $newList);
387 }
388
389 unset($searchObj);
390 if (intval($GLOBALS['TCA']['pages']['ctrl']['versioningWS']) === 2 && $pageList) {
391 // Remove the "subbranch" if a page was moved away
392 $movedAwayPages = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
393 'uid, pid, t3ver_move_id',
394 'pages',
395 't3ver_move_id IN (' . $pageList . ') AND t3ver_wsid=' . intval($wsid) . t3lib_BEfunc::deleteClause('pages'),
396 '',
397 'uid',
398 '',
399 't3ver_move_id'
400 );
401 $pageIds = t3lib_div::intExplode(',', $pageList, TRUE);
402
403 // move all pages away
404 $newList = array_diff($pageIds, array_keys($movedAwayPages));
405
406 // keep current page in the list
407 $newList[] = $pageId;
408 // move back in if still connected to the "remaining" pages
409 do {
410 $changed = FALSE;
411 foreach ($movedAwayPages as $uid => $rec) {
412 if (in_array($rec['pid'], $newList) && !in_array($uid, $newList)) {
413 $newList[] = $uid;
414 $changed = TRUE;
415 }
416 }
417 } while ($changed);
418 $pageList = implode(',', $newList);
419
420 // In case moving pages is enabled we need to replace all move-to pointer with their origin
421 $pages = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
422 'uid, t3ver_move_id',
423 'pages',
424 'uid IN (' . $pageList . ')' . t3lib_BEfunc::deleteClause('pages'),
425 '',
426 'uid',
427 '',
428 'uid'
429 );
430
431 $newList = array();
432 $pageIds = t3lib_div::intExplode(',', $pageList, TRUE);
433 if (!in_array($pageId, $pageIds)) {
434 $pageIds[] = $pageId;
435 }
436 foreach ($pageIds as $pageId) {
437 if (intval($pages[$pageId]['t3ver_move_id']) > 0) {
438 $newList[] = intval($pages[$pageId]['t3ver_move_id']);
439 } else {
440 $newList[] = $pageId;
441 }
442 }
443 $pageList = implode(',', $newList);
444 }
445 return $pageList;
446 }
447
448 /**
449 * Remove all records which are not permitted for the user
450 *
451 * @param array $recs
452 * @param string $table
453 * @return array
454 */
455 protected function filterPermittedElements($recs, $table) {
456 $checkField = ($table == 'pages') ? 'uid' : 'wspid';
457 $permittedElements = array();
458 if (is_array($recs)) {
459 foreach ($recs as $rec) {
460 $page = t3lib_beFunc::getRecord('pages', $rec[$checkField], 'uid,pid,perms_userid,perms_user,perms_groupid,perms_group,perms_everybody');
461 if ($GLOBALS['BE_USER']->doesUserHaveAccess($page, 1) && $this->isLanguageAccessibleForCurrentUser($table, $rec)) {
462 $permittedElements[] = $rec;
463 }
464 }
465 }
466 return $permittedElements;
467 }
468
469 /**
470 * Check current be users language access on given record.
471 *
472 * @param string $table Name of the table
473 * @param array $record Record row to be checked
474 * @return boolean
475 */
476 protected function isLanguageAccessibleForCurrentUser($table, array $record) {
477 $languageUid = 0;
478
479 if (t3lib_BEfunc::isTableLocalizable($table)) {
480 $languageUid = $record[$GLOBALS['TCA'][$table]['ctrl']['languageField']];
481 } else {
482 return TRUE;
483 }
484
485 return $GLOBALS['BE_USER']->checkLanguageAccess($languageUid);
486 }
487
488 /**
489 * Trivial check to see if the user already migrated his workspaces
490 * to the new style (either manually or with the migrator scripts)
491 *
492 * @return bool
493 */
494 public static function isOldStyleWorkspaceUsed() {
495 $oldStyleWorkspaceIsUsed = FALSE;
496 $cacheKey = 'workspace-oldstyleworkspace-notused';
497 $cacheResult = $GLOBALS['BE_USER']->getSessionData($cacheKey);
498 if (!$cacheResult) {
499 $where = 'adminusers != "" AND adminusers NOT LIKE "%be_users%" AND adminusers NOT LIKE "%be_groups%" AND deleted=0';
500 $count = $GLOBALS['TYPO3_DB']->exec_SELECTcountRows('uid', 'sys_workspace', $where);
501 $oldStyleWorkspaceIsUsed = $count > 0;
502 $GLOBALS['BE_USER']->setAndSaveSessionData($cacheKey, !$oldStyleWorkspaceIsUsed);
503 } else {
504 $oldStyleWorkspaceIsUsed = !$cacheResult;
505 }
506 return $oldStyleWorkspaceIsUsed;
507 }
508
509 /**
510 * Determine whether a specific page is new and not yet available in the LIVE workspace
511 *
512 * @static
513 * @param $id Primary key of the page to check
514 * @param $language Language for which to check the page
515 * @return bool
516 */
517 public static function isNewPage($id, $language = 0) {
518 $isNewPage = FALSE;
519 // If the language is not default, check state of overlay
520 if ($language > 0) {
521 $whereClause = 'pid = ' . $id;
522 $whereClause .= ' AND ' .$GLOBALS['TCA']['pages_language_overlay']['ctrl']['languageField'] . ' = ' . $language;
523 $whereClause .= ' AND t3ver_wsid = ' . $GLOBALS['BE_USER']->workspace;
524 $whereClause .= t3lib_BEfunc::deleteClause('pages_language_overlay');
525 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('t3ver_state', 'pages_language_overlay', $whereClause);
526 if (($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res))) {
527 $isNewPage = (int) $row['t3ver_state'] === 1;
528 }
529
530 // Otherwise check state of page itself
531 } else {
532 $rec = t3lib_BEfunc::getRecord('pages', $id, 't3ver_state');
533 if (is_array($rec)) {
534 $isNewPage = (int) $rec['t3ver_state'] === 1;
535 }
536 }
537 return $isNewPage;
538 }
539
540 /**
541 * Generates a view link for a page.
542 *
543 * @static
544 * @param $table
545 * @param $uid
546 * @param $record
547 * @return string
548 */
549 public static function viewSingleRecord($table, $uid, $record=NULL) {
550 $viewUrl = '';
551 if ($table == 'pages') {
552 $viewUrl = t3lib_BEfunc::viewOnClick(t3lib_BEfunc::getLiveVersionIdOfRecord('pages', $uid));
553 } elseif ($table == 'pages_language_overlay' || $table == 'tt_content') {
554 $elementRecord = is_array($record) ? $record : t3lib_BEfunc::getLiveVersionOfRecord($table, $uid);
555 $viewUrl = t3lib_BEfunc::viewOnClick($elementRecord['pid']);
556 } else {
557 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['workspaces']['viewSingleRecord'])) {
558 $_params = array('table' => $table, 'uid' => $uid, 'record' => $record);
559 $_funcRef = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['workspaces']['viewSingleRecord'];
560 $null = NULL;
561 $viewUrl = t3lib_div::callUserFunction($_funcRef, $_params, $null);
562 }
563 }
564 return $viewUrl;
565 }
566
567 /**
568 * Determine whether this page for the current
569 *
570 * @param $pageUid
571 * @param $workspaceUid
572 * @return boolean
573 */
574 public function canCreatePreviewLink($pageUid, $workspaceUid) {
575 $result = TRUE;
576 if ($pageUid > 0 && $workspaceUid > 0) {
577 $pageRecord = t3lib_BEfunc::getRecord('pages', $pageUid);
578 t3lib_BEfunc::workspaceOL('pages', $pageRecord, $workspaceUid);
579 if (!t3lib_div::inList($GLOBALS['TYPO3_CONF_VARS']['FE']['content_doktypes'], $pageRecord['doktype'])) {
580 $result = FALSE;
581 }
582 } else {
583 $result = FALSE;
584 }
585 return $result;
586 }
587
588 /**
589 * Generates a workspace preview link.
590 *
591 * @param integer $uid The ID of the record to be linked
592 * @return string the full domain including the protocol http:// or https://, but without the trailing '/'
593 */
594 public function generateWorkspacePreviewLink($uid) {
595 $previewObject = t3lib_div::makeInstance('Tx_Version_Preview');
596 $timeToLiveHours = $previewObject->getPreviewLinkLifetime();
597 $previewKeyword = $previewObject->compilePreviewKeyword('', $GLOBALS['BE_USER']->user['uid'], ($timeToLiveHours*3600), $this->getCurrentWorkspace());
598
599 $linkParams = array(
600 'ADMCMD_prev' => $previewKeyword,
601 'id' => $uid
602 );
603 return t3lib_BEfunc::getViewDomain($uid) . '/index.php?' . t3lib_div::implodeArrayForUrl('', $linkParams);
604 }
605
606 /**
607 * Generates a workspace splitted preview link.
608 *
609 * @param integer $uid The ID of the record to be linked
610 * @param boolean $addDomain Parameter to decide if domain should be added to the generated link, FALSE per default
611 * @return string the preview link without the trailing '/'
612 */
613 public function generateWorkspaceSplittedPreviewLink($uid, $addDomain = FALSE) {
614 // In case a $pageUid is submitted we need to make sure it points to a live-page
615 if ($uid > 0) {
616 $uid = $this->getLivePageUid($uid);
617 }
618
619 $objectManager = t3lib_div::makeInstance('Tx_Extbase_Object_ObjectManager');
620 /** @var $uriBuilder Tx_Extbase_MVC_Web_Routing_UriBuilder */
621 $uriBuilder = $objectManager->create('Tx_Extbase_MVC_Web_Routing_UriBuilder');
622 /**
623 * This seems to be very harsh to set this directly to "/typo3 but the viewOnClick also
624 * has /index.php as fixed value here and dealing with the backPath is very error-prone
625 *
626 * @todo make sure this would work in local extension installation too
627 */
628 $backPath = '/' . TYPO3_mainDir;
629 $redirect = $backPath . 'index.php?redirect_url=';
630 // @todo why do we need these additional params? the URIBuilder should add the controller, but he doesn't :(
631 $additionalParams = '&tx_workspaces_web_workspacesworkspaces%5Bcontroller%5D=Preview&M=web_WorkspacesWorkspaces&id=';
632 $viewScript = $backPath . $uriBuilder->setArguments(array('tx_workspaces_web_workspacesworkspaces' => array('previewWS' => $GLOBALS['BE_USER']->workspace)))
633 ->uriFor('index', array(), 'Tx_Workspaces_Controller_PreviewController', 'workspaces', 'web_workspacesworkspaces') . $additionalParams;
634
635 if ($addDomain === TRUE) {
636 return t3lib_BEfunc::getViewDomain($uid) . $redirect . urlencode($viewScript) . $uid;
637 } else {
638 return $viewScript;
639 }
640 }
641
642 /**
643 * Find the Live-Uid for a given page,
644 * the results are cached at run-time to avoid too many database-queries
645 *
646 * @throws InvalidArgumentException
647 * @param integer $uid
648 * @return integer
649 */
650 public function getLivePageUid($uid) {
651 if (!isset($this->pageCache[$uid])) {
652 $pageRecord = t3lib_beFunc::getRecord('pages', $uid);
653 if (is_array($pageRecord)) {
654 $this->pageCache[$uid] = ($pageRecord['t3ver_oid'] ? $pageRecord['t3ver_oid'] : $uid);
655 } else {
656 throw new InvalidArgumentException('uid is supposed to point to an existing page - given value was:' . $uid, 1290628113);
657 }
658 }
659
660 return $this->pageCache[$uid];
661 }
662 }
663
664
665 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/workspaces/Classes/Service/Workspaces.php'])) {
666 include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['ext/workspaces/Classes/Service/Workspaces.php']);
667 }
668 ?>