| Total Complexity | 93 |
| Total Lines | 447 |
| Duplicated Lines | 0 % |
| Changes | 1 | ||
| Bugs | 0 | Features | 0 |
Complex classes like GridColumnItem often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use GridColumnItem, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 38 | class GridColumnItem extends AbstractGridObject |
||
| 39 | { |
||
| 40 | protected $record = []; |
||
| 41 | |||
| 42 | /** |
||
| 43 | * @var GridColumn |
||
| 44 | */ |
||
| 45 | protected $column; |
||
| 46 | |||
| 47 | public function __construct(BackendLayout $backendLayout, GridColumn $column, array $record) |
||
| 48 | { |
||
| 49 | parent::__construct($backendLayout); |
||
| 50 | $this->column = $column; |
||
| 51 | $this->record = $record; |
||
| 52 | $backendLayout->getRecordRememberer()->rememberRecordUid($record['uid']); |
||
| 53 | $backendLayout->getRecordRememberer()->rememberRecordUid($record['l18n_parent']); |
||
| 54 | } |
||
| 55 | |||
| 56 | public function isVersioned(): bool |
||
| 57 | { |
||
| 58 | return $this->record['_ORIG_uid'] > 0; |
||
| 59 | } |
||
| 60 | |||
| 61 | public function getPreview(): string |
||
| 62 | { |
||
| 63 | $item = $this; |
||
| 64 | $row = $item->getRecord(); |
||
| 65 | $configuration = $this->backendLayout->getDrawingConfiguration(); |
||
| 66 | $out = ''; |
||
| 67 | $outHeader = ''; |
||
| 68 | |||
| 69 | if ($row['header']) { |
||
| 70 | $hiddenHeaderNote = ''; |
||
| 71 | // If header layout is set to 'hidden', display an accordant note: |
||
| 72 | if ($row['header_layout'] == 100) { |
||
| 73 | $hiddenHeaderNote = ' <em>[' . htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.hidden')) . ']</em>'; |
||
| 74 | } |
||
| 75 | $outHeader = $row['date'] |
||
| 76 | ? htmlspecialchars($configuration->getItemLabels()['date'] . ' ' . BackendUtility::date($row['date'])) . '<br />' |
||
|
|
|||
| 77 | : ''; |
||
| 78 | $outHeader .= '<strong>' . $this->linkEditContent($this->renderText($row['header']), $row) |
||
| 79 | . $hiddenHeaderNote . '</strong><br />'; |
||
| 80 | } |
||
| 81 | |||
| 82 | $drawItem = true; |
||
| 83 | |||
| 84 | // Draw preview of the item depending on its CType (if not disabled by previous hook): |
||
| 85 | if ($drawItem) { |
||
| 86 | switch ($row['CType']) { |
||
| 87 | case 'header': |
||
| 88 | if ($row['subheader']) { |
||
| 89 | $out .= $this->linkEditContent($this->renderText($row['subheader']), $row) . '<br />'; |
||
| 90 | } |
||
| 91 | break; |
||
| 92 | case 'bullets': |
||
| 93 | case 'table': |
||
| 94 | if ($row['bodytext']) { |
||
| 95 | $out .= $this->linkEditContent($this->renderText($row['bodytext']), $row) . '<br />'; |
||
| 96 | } |
||
| 97 | break; |
||
| 98 | case 'uploads': |
||
| 99 | if ($row['media']) { |
||
| 100 | $out .= $this->linkEditContent($this->getThumbCodeUnlinked($row, 'tt_content', 'media'), $row) . '<br />'; |
||
| 101 | } |
||
| 102 | break; |
||
| 103 | case 'shortcut': |
||
| 104 | if (!empty($row['records'])) { |
||
| 105 | $shortcutContent = []; |
||
| 106 | $recordList = explode(',', $row['records']); |
||
| 107 | foreach ($recordList as $recordIdentifier) { |
||
| 108 | $split = BackendUtility::splitTable_Uid($recordIdentifier); |
||
| 109 | $tableName = empty($split[0]) ? 'tt_content' : $split[0]; |
||
| 110 | $shortcutRecord = BackendUtility::getRecord($tableName, $split[1]); |
||
| 111 | if (is_array($shortcutRecord)) { |
||
| 112 | $icon = $this->iconFactory->getIconForRecord($tableName, $shortcutRecord, Icon::SIZE_SMALL)->render(); |
||
| 113 | $icon = BackendUtility::wrapClickMenuOnIcon( |
||
| 114 | $icon, |
||
| 115 | $tableName, |
||
| 116 | $shortcutRecord['uid'] |
||
| 117 | ); |
||
| 118 | $shortcutContent[] = $icon |
||
| 119 | . htmlspecialchars(BackendUtility::getRecordTitle($tableName, $shortcutRecord)); |
||
| 120 | } |
||
| 121 | } |
||
| 122 | $out .= implode('<br />', $shortcutContent) . '<br />'; |
||
| 123 | } |
||
| 124 | break; |
||
| 125 | case 'list': |
||
| 126 | $hookOut = ''; |
||
| 127 | $_params = ['pObj' => &$this, 'row' => $row, 'infoArr' => []]; |
||
| 128 | foreach ( |
||
| 129 | $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/class.tx_cms_layout.php']['list_type_Info'][$row['list_type']] ?? |
||
| 130 | $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/class.tx_cms_layout.php']['list_type_Info']['_DEFAULT'] ?? |
||
| 131 | [] as $_funcRef |
||
| 132 | ) { |
||
| 133 | $hookOut .= GeneralUtility::callUserFunction($_funcRef, $_params, $this); |
||
| 134 | } |
||
| 135 | if ((string)$hookOut !== '') { |
||
| 136 | $out .= $hookOut; |
||
| 137 | } elseif (!empty($row['list_type'])) { |
||
| 138 | $label = BackendUtility::getLabelFromItemListMerged($row['pid'], 'tt_content', 'list_type', $row['list_type']); |
||
| 139 | if (!empty($label)) { |
||
| 140 | $out .= $this->linkEditContent('<strong>' . htmlspecialchars($this->getLanguageService()->sL($label)) . '</strong>', $row) . '<br />'; |
||
| 141 | } else { |
||
| 142 | $message = sprintf($this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.noMatchingValue'), $row['list_type']); |
||
| 143 | $out .= '<span class="label label-warning">' . htmlspecialchars($message) . '</span>'; |
||
| 144 | } |
||
| 145 | } else { |
||
| 146 | $out .= '<strong>' . $this->getLanguageService()->getLL('noPluginSelected') . '</strong>'; |
||
| 147 | } |
||
| 148 | $out .= htmlspecialchars($this->getLanguageService()->sL( |
||
| 149 | BackendUtility::getLabelFromItemlist('tt_content', 'pages', $row['pages']) |
||
| 150 | )) . '<br />'; |
||
| 151 | break; |
||
| 152 | default: |
||
| 153 | $contentType = $this->backendLayout->getDrawingConfiguration()->getContentTypeLabels()[$row['CType']]; |
||
| 154 | if (!isset($contentType)) { |
||
| 155 | $contentType = BackendUtility::getLabelFromItemListMerged($row['pid'], 'tt_content', 'CType', $row['CType']); |
||
| 156 | } |
||
| 157 | |||
| 158 | if ($contentType) { |
||
| 159 | $out .= $this->linkEditContent('<strong>' . htmlspecialchars($contentType) . '</strong>', $row) . '<br />'; |
||
| 160 | if ($row['bodytext']) { |
||
| 161 | $out .= $this->linkEditContent($this->renderText($row['bodytext']), $row) . '<br />'; |
||
| 162 | } |
||
| 163 | if ($row['image']) { |
||
| 164 | $out .= $this->linkEditContent($this->getThumbCodeUnlinked($row, 'tt_content', 'image'), $row) . '<br />'; |
||
| 165 | } |
||
| 166 | } else { |
||
| 167 | $message = sprintf( |
||
| 168 | $this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.noMatchingValue'), |
||
| 169 | $row['CType'] |
||
| 170 | ); |
||
| 171 | $out .= '<span class="label label-warning">' . htmlspecialchars($message) . '</span>'; |
||
| 172 | } |
||
| 173 | } |
||
| 174 | } |
||
| 175 | $out = '<span class="exampleContent">' . $out . '</span>'; |
||
| 176 | $out = $outHeader . $out; |
||
| 177 | if ($item->isDisabled()) { |
||
| 178 | return '<span class="text-muted">' . $out . '</span>'; |
||
| 179 | } |
||
| 180 | return $out; |
||
| 181 | } |
||
| 182 | |||
| 183 | public function getWrapperClassName(): string |
||
| 184 | { |
||
| 185 | $wrapperClassNames = []; |
||
| 186 | if ($this->isDisabled()) { |
||
| 187 | $wrapperClassNames[] = 't3-page-ce-hidden t3js-hidden-record'; |
||
| 188 | } elseif (!in_array($this->record['colPos'], $this->backendLayout->getColumnPositionNumbers())) { |
||
| 189 | $wrapperClassNames[] = 't3-page-ce-warning'; |
||
| 190 | } |
||
| 191 | |||
| 192 | return implode(' ', $wrapperClassNames); |
||
| 193 | } |
||
| 194 | |||
| 195 | public function isDelible(): bool |
||
| 196 | { |
||
| 197 | $backendUser = $this->getBackendUser(); |
||
| 198 | if (!$backendUser->doesUserHaveAccess($this->pageinfo, Permission::CONTENT_EDIT)) { |
||
| 199 | return false; |
||
| 200 | } |
||
| 201 | return !(bool)($backendUser->getTSConfig()['options.']['disableDelete.']['tt_content'] ?? $backendUser->getTSConfig()['options.']['disableDelete'] ?? false); |
||
| 202 | } |
||
| 203 | |||
| 204 | public function getDeleteUrl(): string |
||
| 205 | { |
||
| 206 | $params = '&cmd[tt_content][' . $this->record['uid'] . '][delete]=1'; |
||
| 207 | return BackendUtility::getLinkToDataHandlerAction($params); |
||
| 208 | } |
||
| 209 | |||
| 210 | public function getDeleteTitle(): string |
||
| 211 | { |
||
| 212 | return $this->getLanguageService()->getLL('deleteItem'); |
||
| 213 | } |
||
| 214 | |||
| 215 | public function getDeleteConfirmText(): string |
||
| 216 | { |
||
| 217 | return $this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_alt_doc.xlf:label.confirm.delete_record.title'); |
||
| 218 | } |
||
| 219 | |||
| 220 | public function getDeleteCancelText(): string |
||
| 221 | { |
||
| 222 | return $this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:cancel'); |
||
| 223 | } |
||
| 224 | |||
| 225 | public function getFooterInfo(): iterable |
||
| 226 | { |
||
| 227 | $info = []; |
||
| 228 | $this->getProcessedValue('starttime,endtime,fe_group,space_before_class,space_after_class', $info); |
||
| 229 | |||
| 230 | if (!empty($GLOBALS['TCA']['tt_content']['ctrl']['descriptionColumn']) && !empty($this->record[$GLOBALS['TCA']['tt_content']['ctrl']['descriptionColumn']])) { |
||
| 231 | $info[] = $this->record[$GLOBALS['TCA']['tt_content']['ctrl']['descriptionColumn']]; |
||
| 232 | } |
||
| 233 | |||
| 234 | return $info; |
||
| 235 | } |
||
| 236 | |||
| 237 | /** |
||
| 238 | * Renders the language flag and language title, but only if an icon is given, otherwise just the language |
||
| 239 | * |
||
| 240 | * @param SiteLanguage $language |
||
| 241 | * @return string |
||
| 242 | */ |
||
| 243 | protected function renderLanguageFlag(SiteLanguage $language) |
||
| 244 | { |
||
| 245 | $title = htmlspecialchars($language->getTitle()); |
||
| 246 | if ($language->getFlagIdentifier()) { |
||
| 247 | $icon = $this->iconFactory->getIcon( |
||
| 248 | $language->getFlagIdentifier(), |
||
| 249 | Icon::SIZE_SMALL |
||
| 250 | )->render(); |
||
| 251 | return '<span title="' . $title . '">' . $icon . '</span> ' . $title; |
||
| 252 | } |
||
| 253 | return $title; |
||
| 254 | } |
||
| 255 | |||
| 256 | /** |
||
| 257 | * Create thumbnail code for record/field but not linked |
||
| 258 | * |
||
| 259 | * @param mixed[] $row Record array |
||
| 260 | * @param string $table Table (record is from) |
||
| 261 | * @param string $field Field name for which thumbnail are to be rendered. |
||
| 262 | * @return string HTML for thumbnails, if any. |
||
| 263 | */ |
||
| 264 | protected function getThumbCodeUnlinked($row, $table, $field) |
||
| 265 | { |
||
| 266 | return BackendUtility::thumbCode($row, $table, $field, '', '', null, 0, '', '', false); |
||
| 267 | } |
||
| 268 | |||
| 269 | /** |
||
| 270 | * Will create a link on the input string and possibly a big button after the string which links to editing in the RTE. |
||
| 271 | * Used for content element content displayed so the user can click the content / "Edit in Rich Text Editor" button |
||
| 272 | * |
||
| 273 | * @param string $str String to link. Must be prepared for HTML output. |
||
| 274 | * @param array $row The row. |
||
| 275 | * @return string If the whole thing was editable $str is return with link around. Otherwise just $str. |
||
| 276 | */ |
||
| 277 | public function linkEditContent($str, $row) |
||
| 293 | } |
||
| 294 | |||
| 295 | /** |
||
| 296 | * Processing of larger amounts of text (usually from RTE/bodytext fields) with word wrapping etc. |
||
| 297 | * |
||
| 298 | * @param string $input Input string |
||
| 299 | * @return string Output string |
||
| 300 | */ |
||
| 301 | public function renderText($input): string |
||
| 302 | { |
||
| 303 | $input = strip_tags($input); |
||
| 304 | $input = GeneralUtility::fixed_lgd_cs($input, 1500); |
||
| 305 | return nl2br(htmlspecialchars(trim($input), ENT_QUOTES, 'UTF-8', false)); |
||
| 306 | } |
||
| 307 | |||
| 308 | protected function getProcessedValue(string $fieldList, array &$info): void |
||
| 309 | { |
||
| 310 | $itemLabels = $this->backendLayout->getDrawingConfiguration()->getItemLabels(); |
||
| 311 | $fieldArr = explode(',', $fieldList); |
||
| 312 | foreach ($fieldArr as $field) { |
||
| 313 | if ($this->record[$field]) { |
||
| 314 | $info[] = '<strong>' . htmlspecialchars($itemLabels[$field]) . '</strong> ' |
||
| 315 | . htmlspecialchars(BackendUtility::getProcessedValue('tt_content', $field, $this->record[$field])); |
||
| 316 | } |
||
| 317 | } |
||
| 318 | } |
||
| 319 | |||
| 320 | public function getIcons(): string |
||
| 321 | { |
||
| 322 | $table = 'tt_content'; |
||
| 323 | $row = $this->record; |
||
| 324 | $icons = []; |
||
| 325 | |||
| 326 | if ($this->getBackendUser()->recordEditAccessInternals($table, $row)) { |
||
| 327 | $toolTip = BackendUtility::getRecordToolTip($row, $table); |
||
| 328 | $icon = '<span ' . $toolTip . '>' . $this->iconFactory->getIconForRecord($table, $row, Icon::SIZE_SMALL)->render() . '</span>'; |
||
| 329 | $icons[] = BackendUtility::wrapClickMenuOnIcon($icon, $table, $row['uid']); |
||
| 330 | } |
||
| 331 | $icons[] = $this->renderLanguageFlag($this->backendLayout->getDrawingConfiguration()->getSiteLanguage((int)$row['sys_language_uid'])); |
||
| 332 | |||
| 333 | if ($lockInfo = BackendUtility::isRecordLocked('tt_content', $row['uid'])) { |
||
| 334 | $icons[] = '<a href="#" data-toggle="tooltip" data-title="' . htmlspecialchars($lockInfo['msg']) . '">' |
||
| 335 | . $this->iconFactory->getIcon('warning-in-use', Icon::SIZE_SMALL)->render() . '</a>'; |
||
| 336 | } |
||
| 337 | |||
| 338 | $_params = ['tt_content', $row['uid'], &$row]; |
||
| 339 | foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['recStatInfoHooks'] ?? [] as $_funcRef) { |
||
| 340 | $icons[] = GeneralUtility::callUserFunction($_funcRef, $_params, $this); |
||
| 341 | } |
||
| 342 | return implode(' ', $icons); |
||
| 343 | } |
||
| 344 | |||
| 345 | public function getRecord(): array |
||
| 346 | { |
||
| 347 | return $this->record; |
||
| 348 | } |
||
| 349 | |||
| 350 | public function getColumn(): GridColumn |
||
| 351 | { |
||
| 352 | return $this->column; |
||
| 353 | } |
||
| 354 | |||
| 355 | public function isDisabled(): bool |
||
| 356 | { |
||
| 357 | $table = 'tt_content'; |
||
| 358 | $row = $this->getRecord(); |
||
| 359 | $enableCols = $GLOBALS['TCA'][$table]['ctrl']['enablecolumns']; |
||
| 360 | return $enableCols['disabled'] && $row[$enableCols['disabled']] |
||
| 361 | || $enableCols['starttime'] && $row[$enableCols['starttime']] > $GLOBALS['EXEC_TIME'] |
||
| 362 | || $enableCols['endtime'] && $row[$enableCols['endtime']] && $row[$enableCols['endtime']] < $GLOBALS['EXEC_TIME']; |
||
| 363 | } |
||
| 364 | |||
| 365 | public function hasTranslation(): bool |
||
| 366 | { |
||
| 367 | $contentElements = $this->column->getRecords(); |
||
| 368 | $id = $this->backendLayout->getDrawingConfiguration()->getPageId(); |
||
| 369 | $language = $this->backendLayout->getDrawingConfiguration()->getLanguageColumnsPointer(); |
||
| 370 | // If in default language, you may always create new entries |
||
| 371 | // Also, you may override this strict behavior via user TS Config |
||
| 372 | // If you do so, you're on your own and cannot rely on any support by the TYPO3 core. |
||
| 373 | $allowInconsistentLanguageHandling = (bool)(BackendUtility::getPagesTSconfig($id)['mod.']['web_layout.']['allowInconsistentLanguageHandling'] ?? false); |
||
| 374 | if ($language === 0 || $allowInconsistentLanguageHandling) { |
||
| 375 | return false; |
||
| 376 | } |
||
| 377 | |||
| 378 | return $this->backendLayout->getContentFetcher()->getTranslationData($contentElements, $language)['hasTranslations'] ?? false; |
||
| 379 | } |
||
| 380 | |||
| 381 | public function isDeletePlaceholder(): bool |
||
| 384 | } |
||
| 385 | |||
| 386 | public function isEditable(): bool |
||
| 387 | { |
||
| 388 | $languageId = $this->backendLayout->getDrawingConfiguration()->getLanguageColumnsPointer(); |
||
| 389 | if ($this->getBackendUser()->isAdmin()) { |
||
| 390 | return true; |
||
| 391 | } |
||
| 392 | $pageRecord = $this->backendLayout->getDrawingConfiguration()->getPageRecord(); |
||
| 393 | return !$pageRecord['editlock'] |
||
| 394 | && $this->getBackendUser()->doesUserHaveAccess($pageRecord, Permission::CONTENT_EDIT) |
||
| 395 | && ($languageId === null || $this->getBackendUser()->checkLanguageAccess($languageId)); |
||
| 396 | } |
||
| 397 | |||
| 398 | public function isDragAndDropAllowed(): bool |
||
| 399 | { |
||
| 400 | $pageRecord = $this->backendLayout->getDrawingConfiguration()->getPageRecord(); |
||
| 401 | return (int)$this->record['l18n_parent'] === 0 && |
||
| 402 | ( |
||
| 403 | $this->getBackendUser()->isAdmin() |
||
| 404 | || ((int)$this->record['editlock'] === 0 && (int)$pageRecord['editlock'] === 0) |
||
| 405 | && $this->getBackendUser()->doesUserHaveAccess($pageRecord, Permission::CONTENT_EDIT) |
||
| 406 | && $this->getBackendUser()->checkAuthMode('tt_content', 'CType', $this->record['CType'], $GLOBALS['TYPO3_CONF_VARS']['BE']['explicitADmode']) |
||
| 407 | ) |
||
| 408 | ; |
||
| 409 | } |
||
| 410 | |||
| 411 | public function getNewContentAfterLinkTitle(): string |
||
| 412 | { |
||
| 413 | return $this->getLanguageService()->getLL('newContentElement'); |
||
| 414 | } |
||
| 415 | |||
| 416 | public function getNewContentAfterTitle(): string |
||
| 417 | { |
||
| 418 | return $this->getLanguageService()->getLL('content'); |
||
| 419 | } |
||
| 420 | |||
| 421 | public function getNewContentAfterUrl(): string |
||
| 422 | { |
||
| 423 | $pageId = $this->backendLayout->getDrawingConfiguration()->getPageId(); |
||
| 424 | $urlParameters = [ |
||
| 425 | 'id' => $pageId, |
||
| 426 | 'sys_language_uid' => $this->backendLayout->getDrawingConfiguration()->getLanguageColumnsPointer(), |
||
| 427 | 'colPos' => $this->column->getColumnNumber(), |
||
| 428 | 'uid_pid' => -$this->record['uid'], |
||
| 429 | 'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI') |
||
| 430 | ]; |
||
| 431 | $routeName = BackendUtility::getPagesTSconfig($pageId)['mod.']['newContentElementWizard.']['override'] |
||
| 432 | ?? 'new_content_element_wizard'; |
||
| 433 | $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class); |
||
| 434 | return (string)$uriBuilder->buildUriFromRoute($routeName, $urlParameters); |
||
| 435 | } |
||
| 436 | |||
| 437 | public function getVisibilityToggleUrl(): string |
||
| 448 | } |
||
| 449 | |||
| 450 | public function getVisibilityToggleTitle(): string |
||
| 451 | { |
||
| 452 | $hiddenField = $GLOBALS['TCA']['tt_content']['ctrl']['enablecolumns']['disabled']; |
||
| 453 | return $this->getLanguageService()->getLL($this->record[$hiddenField] ? 'unhide' : 'hide'); |
||
| 454 | } |
||
| 455 | |||
| 456 | public function getVisibilityToggleIconName(): string |
||
| 460 | } |
||
| 461 | |||
| 462 | public function isVisibilityToggling(): bool |
||
| 463 | { |
||
| 464 | $hiddenField = $GLOBALS['TCA']['tt_content']['ctrl']['enablecolumns']['disabled']; |
||
| 465 | return $hiddenField && $GLOBALS['TCA']['tt_content']['columns'][$hiddenField] |
||
| 466 | && ( |
||
| 467 | !$GLOBALS['TCA']['tt_content']['columns'][$hiddenField]['exclude'] |
||
| 468 | || $this->getBackendUser()->check('non_exclude_fields', 'tt_content:' . $hiddenField) |
||
| 469 | ) |
||
| 470 | ; |
||
| 471 | } |
||
| 472 | |||
| 473 | public function getEditUrl(): string |
||
| 485 | } |
||
| 486 | } |
||
| 487 |