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