[TASK] Call explicit render() on icon objects
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Tree / Pagetree / Commands.php
1 <?php
2 namespace TYPO3\CMS\Backend\Tree\Pagetree;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Backend\Utility\BackendUtility;
18 use TYPO3\CMS\Core\Imaging\Icon;
19 use TYPO3\CMS\Core\Imaging\IconFactory;
20 use TYPO3\CMS\Core\Utility\GeneralUtility;
21 use TYPO3\CMS\Core\Utility\MathUtility;
22 use TYPO3\CMS\Core\Versioning\VersionState;
23
24 /**
25 * Page Tree and Context Menu Commands
26 */
27 class Commands {
28
29 /**
30 * @var bool|null
31 */
32 static protected $useNavTitle = NULL;
33
34 /**
35 * @var bool|null
36 */
37 static protected $addIdAsPrefix = NULL;
38
39 /**
40 * @var bool|null
41 */
42 static protected $addDomainName = NULL;
43
44 /**
45 * @var array|null
46 */
47 static protected $backgroundColors = NULL;
48
49 /**
50 * @var int|null
51 */
52 static protected $titleLength = NULL;
53
54 /**
55 * Visibly the page
56 *
57 * @param \TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNode $node
58 * @return void
59 */
60 static public function visiblyNode(\TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNode $node) {
61 $data['pages'][$node->getWorkspaceId()]['hidden'] = 0;
62 self::processTceCmdAndDataMap(array(), $data);
63 }
64
65 /**
66 * Hide the page
67 *
68 * @param \TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNode $node
69 * @return void
70 */
71 static public function disableNode(\TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNode $node) {
72 $data['pages'][$node->getWorkspaceId()]['hidden'] = 1;
73 self::processTceCmdAndDataMap(array(), $data);
74 }
75
76 /**
77 * Delete the page
78 *
79 * @param \TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNode $node
80 * @return void
81 */
82 static public function deleteNode(\TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNode $node) {
83 $cmd['pages'][$node->getId()]['delete'] = 1;
84 self::processTceCmdAndDataMap($cmd);
85 }
86
87 /**
88 * Restore the page
89 *
90 * @param \TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNode $node
91 * @param int $targetId
92 * @return void
93 */
94 static public function restoreNode(\TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNode $node, $targetId) {
95 $cmd['pages'][$node->getId()]['undelete'] = 1;
96 self::processTceCmdAndDataMap($cmd);
97 if ($node->getId() !== $targetId) {
98 self::moveNode($node, $targetId);
99 }
100 }
101
102 /**
103 * Updates the node label
104 *
105 * @param \TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNode $node
106 * @param string $updatedLabel
107 * @return void
108 */
109 static public function updateNodeLabel(\TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNode $node, $updatedLabel) {
110 if ($GLOBALS['BE_USER']->checkLanguageAccess(0)) {
111 $data['pages'][$node->getWorkspaceId()][$node->getTextSourceField()] = $updatedLabel;
112 self::processTceCmdAndDataMap(array(), $data);
113 } else {
114 throw new \RuntimeException(implode(LF, array('Editing title of page id \'' . $node->getWorkspaceId() . '\' failed. Editing default language is not allowed.')), 1365513336);
115 }
116 }
117
118 /**
119 * Copies a page and returns the id of the new page
120 *
121 * Node: Use a negative target id to specify a sibling target else the parent is used
122 *
123 * @param \TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNode $sourceNode
124 * @param int $targetId
125 * @return int
126 */
127 static public function copyNode(\TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNode $sourceNode, $targetId) {
128 $cmd['pages'][$sourceNode->getId()]['copy'] = $targetId;
129 $returnValue = self::processTceCmdAndDataMap($cmd);
130 return $returnValue['pages'][$sourceNode->getId()];
131 }
132
133 /**
134 * Moves a page
135 *
136 * Node: Use a negative target id to specify a sibling target else the parent is used
137 *
138 * @param \TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNode $sourceNode
139 * @param int $targetId
140 * @return void
141 */
142 static public function moveNode(\TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNode $sourceNode, $targetId) {
143 $cmd['pages'][$sourceNode->getId()]['move'] = $targetId;
144 self::processTceCmdAndDataMap($cmd);
145 }
146
147 /**
148 * Creates a page of the given doktype and returns the id of the created page
149 *
150 * @param \TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNode $parentNode
151 * @param int $targetId
152 * @param int $pageType
153 * @return int
154 */
155 static public function createNode(\TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNode $parentNode, $targetId, $pageType) {
156 $placeholder = 'NEW12345';
157 $pid = (int)$parentNode->getWorkspaceId();
158 $targetId = (int)$targetId;
159
160 // Use page TsConfig as default page initialization
161 $pageTs = BackendUtility::getPagesTSconfig($pid);
162 if (array_key_exists('TCAdefaults.', $pageTs) && array_key_exists('pages.', $pageTs['TCAdefaults.'])) {
163 $data['pages'][$placeholder] = $pageTs['TCAdefaults.']['pages.'];
164 } else {
165 $data['pages'][$placeholder] = array();
166 }
167
168 $data['pages'][$placeholder]['pid'] = $pid;
169 $data['pages'][$placeholder]['doktype'] = $pageType;
170 $data['pages'][$placeholder]['title'] = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:tree.defaultPageTitle', TRUE);
171 $newPageId = self::processTceCmdAndDataMap(array(), $data);
172 $node = self::getNode($newPageId[$placeholder]);
173 if ($pid !== $targetId) {
174 self::moveNode($node, $targetId);
175 }
176
177 return $newPageId[$placeholder];
178 }
179
180 /**
181 * Process TCEMAIN commands and data maps
182 *
183 * Command Map:
184 * Used for moving, recover, remove and some more operations.
185 *
186 * Data Map:
187 * Used for creating and updating records,
188 *
189 * This API contains all necessary access checks.
190 *
191 * @param array $cmd
192 * @param array $data
193 * @return array
194 * @throws \RuntimeException if an error happened while the TCE processing
195 */
196 static protected function processTceCmdAndDataMap(array $cmd, array $data = array()) {
197 /** @var $tce \TYPO3\CMS\Core\DataHandling\DataHandler */
198 $tce = GeneralUtility::makeInstance(\TYPO3\CMS\Core\DataHandling\DataHandler::class);
199 $tce->stripslashes_values = 0;
200 $tce->start($data, $cmd);
201 $tce->copyTree = MathUtility::forceIntegerInRange($GLOBALS['BE_USER']->uc['copyLevels'], 0, 100);
202 if (!empty($cmd)) {
203 $tce->process_cmdmap();
204 $returnValues = $tce->copyMappingArray_merged;
205 } elseif (!empty($data)) {
206 $tce->process_datamap();
207 $returnValues = $tce->substNEWwithIDs;
208 } else {
209 $returnValues = array();
210 }
211 // check errors
212 if (!empty($tce->errorLog)) {
213 throw new \RuntimeException(implode(LF, $tce->errorLog), 1333754629);
214 }
215 return $returnValues;
216 }
217
218 /**
219 * Returns a node from the given node id
220 *
221 * @param int $nodeId
222 * @param bool $unsetMovePointers
223 * @return \TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNode
224 */
225 static public function getNode($nodeId, $unsetMovePointers = TRUE) {
226 $record = self::getNodeRecord($nodeId, $unsetMovePointers);
227 return self::getNewNode($record);
228 }
229
230 /**
231 * Returns the mount point path for a temporary mount or the given id
232 *
233 * @param int $uid
234 * @return string
235 */
236 static public function getMountPointPath($uid = -1) {
237 if ($uid === -1) {
238 $uid = (int)$GLOBALS['BE_USER']->uc['pageTree_temporaryMountPoint'];
239 }
240 if ($uid <= 0) {
241 return '';
242 }
243 if (self::$useNavTitle === NULL) {
244 self::$useNavTitle = $GLOBALS['BE_USER']->getTSConfigVal('options.pageTree.showNavTitle');
245 }
246 $rootline = array_reverse(BackendUtility::BEgetRootLine($uid));
247 array_shift($rootline);
248 $path = array();
249 foreach ($rootline as $rootlineElement) {
250 $record = self::getNodeRecord($rootlineElement['uid']);
251 $text = $record['title'];
252 if (self::$useNavTitle && trim($record['nav_title']) !== '') {
253 $text = $record['nav_title'];
254 }
255 $path[] = htmlspecialchars($text);
256 }
257 return '/' . implode('/', $path);
258 }
259
260 /**
261 * Returns a node record from a given id
262 *
263 * @param int $nodeId
264 * @param bool $unsetMovePointers
265 * @return array
266 */
267 static public function getNodeRecord($nodeId, $unsetMovePointers = TRUE) {
268 $record = BackendUtility::getRecordWSOL('pages', $nodeId, '*', '', TRUE, $unsetMovePointers);
269 return $record;
270 }
271
272 /**
273 * Returns the first configured domain name for a page
274 *
275 * @param int $uid
276 * @return string
277 */
278 static public function getDomainName($uid) {
279 $whereClause = 'pid=' . (int)$uid . BackendUtility::deleteClause('sys_domain') . BackendUtility::BEenableFields('sys_domain');
280 $domain = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow('domainName', 'sys_domain', $whereClause, '', 'sorting');
281 return is_array($domain) ? htmlspecialchars($domain['domainName']) : '';
282 }
283
284 /**
285 * Creates a node with the given record information
286 *
287 * @param array $record
288 * @param int $mountPoint
289 * @return \TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNode
290 */
291 static public function getNewNode($record, $mountPoint = 0) {
292 $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
293 if (self::$titleLength === NULL) {
294 self::$useNavTitle = $GLOBALS['BE_USER']->getTSConfigVal('options.pageTree.showNavTitle');
295 self::$addIdAsPrefix = $GLOBALS['BE_USER']->getTSConfigVal('options.pageTree.showPageIdWithTitle');
296 self::$addDomainName = $GLOBALS['BE_USER']->getTSConfigVal('options.pageTree.showDomainNameWithTitle');
297 self::$backgroundColors = $GLOBALS['BE_USER']->getTSConfigProp('options.pageTree.backgroundColor');
298 self::$titleLength = (int)$GLOBALS['BE_USER']->uc['titleLen'];
299 }
300 /** @var $subNode \TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNode */
301 $subNode = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Tree\Pagetree\PagetreeNode::class);
302 $subNode->setRecord($record);
303 $subNode->setCls($record['_CSSCLASS']);
304 $subNode->setType('pages');
305 $subNode->setId($record['uid']);
306 $subNode->setMountPoint($mountPoint);
307 $subNode->setWorkspaceId($record['_ORIG_uid'] ?: $record['uid']);
308 $subNode->setBackgroundColor(self::$backgroundColors[$record['uid']]);
309 $field = 'title';
310 $text = $record['title'];
311 if (self::$useNavTitle && trim($record['nav_title']) !== '') {
312 $field = 'nav_title';
313 $text = $record['nav_title'];
314 }
315 if (trim($text) === '') {
316 $visibleText = '[' . $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.no_title', TRUE) . ']';
317 } else {
318 $visibleText = $text;
319 }
320 $visibleText = GeneralUtility::fixed_lgd_cs($visibleText, self::$titleLength);
321 $suffix = '';
322 if (self::$addDomainName) {
323 $domain = self::getDomainName($record['uid']);
324 $suffix = $domain !== '' ? ' [' . $domain . ']' : '';
325 }
326 $qtip = str_replace(' - ', '<br />', htmlspecialchars(BackendUtility::titleAttribForPages($record, '', FALSE)));
327 $prefix = '';
328 $lockInfo = BackendUtility::isRecordLocked('pages', $record['uid']);
329 if (is_array($lockInfo)) {
330 $qtip .= '<br />' . htmlspecialchars($lockInfo['msg']);
331 $prefix .= '<span class="typo3-pagetree-status">' . $iconFactory->getIcon('status-warning-in-use', Icon::SIZE_SMALL)->render() . '</span>';
332 }
333 // Call stats information hook
334 $stat = '';
335 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['recStatInfoHooks'])) {
336 $_params = array('pages', $record['uid']);
337 $fakeThis = NULL;
338 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['recStatInfoHooks'] as $_funcRef) {
339 $stat .= GeneralUtility::callUserFunction($_funcRef, $_params, $fakeThis);
340 }
341 }
342 $prefix .= htmlspecialchars(self::$addIdAsPrefix ? '[' . $record['uid'] . '] ' : '');
343 $subNode->setEditableText($text);
344 $subNode->setText(htmlspecialchars($visibleText), $field, $prefix, htmlspecialchars($suffix) . $stat);
345 $subNode->setQTip($qtip);
346 if ((int)$record['uid'] !== 0) {
347 $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
348 $spriteIconCode = $iconFactory->getIconForRecord('pages', $record, Icon::SIZE_SMALL)->render();
349 } else {
350 $spriteIconCode = $iconFactory->getIcon('apps-pagetree-root', Icon::SIZE_SMALL)->render();
351 }
352 $subNode->setSpriteIconCode($spriteIconCode);
353 if (
354 !$subNode->canCreateNewPages()
355 || VersionState::cast($record['t3ver_state'])->equals(VersionState::DELETE_PLACEHOLDER)
356 ) {
357 $subNode->setIsDropTarget(FALSE);
358 }
359 if (
360 !$subNode->canBeEdited()
361 || !$subNode->canBeRemoved()
362 || VersionState::cast($record['t3ver_state'])->equals(VersionState::DELETE_PLACEHOLDER)
363 ) {
364 $subNode->setDraggable(FALSE);
365 }
366 return $subNode;
367 }
368
369 }