Completed
Push — master ( cb9863...be434f )
by
unknown
40:07 queued 25:06
created

PageLayoutContext::getLanguagesToShow()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 6
nc 2
nop 0
dl 0
loc 11
rs 10
c 1
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace TYPO3\CMS\Backend\View;
6
7
/*
8
 * This file is part of the TYPO3 CMS project.
9
 *
10
 * It is free software; you can redistribute it and/or modify it under
11
 * the terms of the GNU General Public License, either version 2
12
 * of the License, or any later version.
13
 *
14
 * For the full copyright and license information, please read the
15
 * LICENSE.txt file that was distributed with this source code.
16
 *
17
 * The TYPO3 project - inspiring people to share!
18
 */
19
20
use TYPO3\CMS\Backend\Routing\UriBuilder;
21
use TYPO3\CMS\Backend\Utility\BackendUtility;
22
use TYPO3\CMS\Backend\View\BackendLayout\BackendLayout;
23
use TYPO3\CMS\Backend\View\BackendLayout\ContentFetcher;
24
use TYPO3\CMS\Backend\View\Drawing\BackendLayoutRenderer;
25
use TYPO3\CMS\Backend\View\Drawing\DrawingConfiguration;
26
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
27
use TYPO3\CMS\Core\Database\ConnectionPool;
28
use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
29
use TYPO3\CMS\Core\Database\Query\Restriction\WorkspaceRestriction;
30
use TYPO3\CMS\Core\Exception\SiteNotFoundException;
31
use TYPO3\CMS\Core\Localization\LanguageService;
32
use TYPO3\CMS\Core\Site\Entity\NullSite;
33
use TYPO3\CMS\Core\Site\Entity\Site;
34
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
35
use TYPO3\CMS\Core\Site\SiteFinder;
36
use TYPO3\CMS\Core\Type\Bitmask\Permission;
37
use TYPO3\CMS\Core\Utility\GeneralUtility;
38
39
class PageLayoutContext
40
{
41
    /**
42
     * @var BackendLayout
43
     */
44
    protected $backendLayout;
45
46
    /**
47
     * @var DrawingConfiguration
48
     */
49
    protected $drawingConfiguration;
50
51
    /**
52
     * @var ContentFetcher
53
     */
54
    protected $contentFetcher;
55
56
    /**
57
     * @var BackendLayoutRenderer
58
     */
59
    protected $backendLayoutRenderer;
60
61
    /**
62
     * @var array
63
     */
64
    protected $pageRecord;
65
66
    /**
67
     * @var array|null
68
     */
69
    protected $localizedPageRecord;
70
71
    /**
72
     * @var int
73
     */
74
    protected $pageId;
75
76
    /**
77
     * @var SiteLanguage[]
78
     */
79
    protected $siteLanguages;
80
81
    /**
82
     * @var SiteLanguage
83
     */
84
    protected $siteLanguage;
85
86
    /**
87
     * @var Site
88
     */
89
    protected $site;
90
91
    /**
92
     * Array of content type labels. Key is CType, value is either a plain text
93
     * label or an LLL:EXT:... reference to a specific label.
94
     *
95
     * @var array
96
     */
97
    protected $contentTypeLabels = [];
98
99
    /**
100
     * Labels for columns, in format of TCA select options. Numerically indexed
101
     * array of numerically indexed value arrays, with each sub-array containing
102
     * at least two values and one optional third value:
103
     *
104
     * - label (hardcoded or LLL:EXT:... reference. MANDATORY)
105
     * - value (colPos of column. MANDATORY)
106
     * - icon (icon name or file reference. OPTIONAL)
107
     *
108
     * @var array
109
     */
110
    protected $itemLabels = [];
111
112
    public function __construct(array $pageRecord, BackendLayout $backendLayout)
113
    {
114
        $this->pageId = (int)$pageRecord['uid'];
115
        try {
116
            $this->site = GeneralUtility::makeInstance(SiteFinder::class)->getSiteByPageId($this->pageId);
117
        } catch (SiteNotFoundException $e) {
118
            $this->site = new NullSite();
0 ignored issues
show
Documentation Bug introduced by
It seems like new TYPO3\CMS\Core\Site\Entity\NullSite() of type TYPO3\CMS\Core\Site\Entity\NullSite is incompatible with the declared type TYPO3\CMS\Core\Site\Entity\Site of property $site.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
119
        }
120
        // TODO: retrieve implementation class names from Site?
121
        $this->pageRecord = $pageRecord;
122
        $this->backendLayout = $backendLayout;
123
        $this->drawingConfiguration = GeneralUtility::makeInstance(DrawingConfiguration::class);
124
        $this->contentFetcher = GeneralUtility::makeInstance(ContentFetcher::class, $this);
125
        $this->backendLayoutRenderer = GeneralUtility::makeInstance(BackendLayoutRenderer::class, $this);
126
        $this->siteLanguages = $this->site->getAvailableLanguages($this->getBackendUser(), false, $this->pageId);
127
        $this->siteLanguage = $this->site->getDefaultLanguage();
128
    }
129
130
    public function cloneForLanguage(SiteLanguage $language): self
131
    {
132
        $copy = clone $this;
133
        $copy->setSiteLanguage($language);
134
        return $copy;
135
    }
136
137
    /**
138
     * @param SiteLanguage $siteLanguage
139
     */
140
    public function setSiteLanguage(SiteLanguage $siteLanguage): void
141
    {
142
        $this->siteLanguage = $siteLanguage;
143
        $languageId = $siteLanguage->getLanguageId();
144
        if ($languageId > 0) {
145
            $pageLocalizationRecord = BackendUtility::getRecordLocalization(
146
                'pages',
147
                $this->getPageId(),
148
                $languageId
149
            );
150
            $pageLocalizationRecord = reset($pageLocalizationRecord);
151
            if (!empty($pageLocalizationRecord)) {
152
                BackendUtility::workspaceOL('pages', $pageLocalizationRecord);
153
                $this->localizedPageRecord = $pageLocalizationRecord ?: null;
154
            }
155
        }
156
    }
157
158
    public function getBackendLayout(): BackendLayout
159
    {
160
        return $this->backendLayout;
161
    }
162
163
    public function getDrawingConfiguration(): DrawingConfiguration
164
    {
165
        return $this->drawingConfiguration;
166
    }
167
168
    public function getBackendLayoutRenderer(): BackendLayoutRenderer
169
    {
170
        return $this->backendLayoutRenderer;
171
    }
172
173
    public function getBackendUser(): BackendUserAuthentication
174
    {
175
        return $GLOBALS['BE_USER'];
176
    }
177
178
    public function getPageRecord(): array
179
    {
180
        return $this->pageRecord;
181
    }
182
183
    public function getPageId(): int
184
    {
185
        return $this->pageId;
186
    }
187
188
    /**
189
     * @return SiteLanguage[]
190
     */
191
    public function getSiteLanguages(): iterable
192
    {
193
        return $this->siteLanguages;
194
    }
195
196
    /**
197
     * @return SiteLanguage[]
198
     */
199
    public function getLanguagesToShow(): iterable
200
    {
201
        $selectedLanguageId = $this->drawingConfiguration->getSelectedLanguageId();
202
        if ($selectedLanguageId > 0) {
203
            // A specific language is selected; compose a list of default language plus selected language
204
            return [
205
                $this->site->getDefaultLanguage(),
206
                $this->site->getLanguageById($selectedLanguageId)
207
            ];
208
        }
209
        return $this->getSiteLanguages();
210
    }
211
212
    public function getSiteLanguage(?int $languageId = null): SiteLanguage
213
    {
214
        if ($languageId === null) {
215
            return $this->siteLanguage;
216
        }
217
        return $this->site->getLanguageById($languageId);
218
    }
219
220
    public function isPageEditable(): bool
221
    {
222
        // TODO: refactor to page permissions container
223
        if ($this->getBackendUser()->isAdmin()) {
224
            return true;
225
        }
226
        $pageRecord = $this->getPageRecord();
227
        return !$pageRecord['editlock'] && $this->getBackendUser()->doesUserHaveAccess($pageRecord, Permission::PAGE_EDIT);
228
    }
229
230
    public function getAllowNewContent(): bool
231
    {
232
        $pageId = $this->getPageId();
233
        $allowInconsistentLanguageHandling = (bool)(BackendUtility::getPagesTSconfig($pageId)['mod.']['web_layout.']['allowInconsistentLanguageHandling'] ?? false);
234
        if (!$allowInconsistentLanguageHandling && $this->getLanguageModeIdentifier() === 'connected') {
235
            return false;
236
        }
237
        return true;
238
    }
239
240
    public function getContentTypeLabels(): array
241
    {
242
        if (empty($this->contentTypeLabels)) {
243
            foreach ($GLOBALS['TCA']['tt_content']['columns']['CType']['config']['items'] as $val) {
244
                $this->contentTypeLabels[$val[1]] = $this->getLanguageService()->sL($val[0]);
245
            }
246
        }
247
        return $this->contentTypeLabels;
248
    }
249
250
    public function getItemLabels(): array
251
    {
252
        if (empty($this->itemLabels)) {
253
            foreach ($GLOBALS['TCA']['tt_content']['columns'] as $name => $val) {
254
                $this->itemLabels[$name] = $this->getLanguageService()->sL($val['label']);
255
            }
256
        }
257
        return $this->itemLabels;
258
    }
259
260
    public function getLanguageModeLabelClass(): string
261
    {
262
        $languageId = $this->siteLanguage->getLanguageId();
263
        $contentRecordsPerColumn = $this->contentFetcher->getFlatContentRecords($languageId);
264
        $translationData = $this->contentFetcher->getTranslationData($contentRecordsPerColumn, $languageId);
265
        return $translationData['mode'] === 'mixed' ? 'danger' : 'info';
266
    }
267
268
    public function getLanguageMode(): string
269
    {
270
        switch ($this->getLanguageModeIdentifier()) {
271
            case 'mixed':
272
                $languageMode = $this->getLanguageService()->getLL('languageModeMixed');
273
                break;
274
            case 'connected':
275
                $languageMode = $this->getLanguageService()->getLL('languageModeConnected');
276
                break;
277
            case 'free':
278
                $languageMode = $this->getLanguageService()->getLL('languageModeFree');
279
                break;
280
            default:
281
                $languageMode = '';
282
        }
283
        return $languageMode;
284
    }
285
286
    public function getLanguageModeIdentifier(): string
287
    {
288
        $contentRecordsPerColumn = $this->contentFetcher->getContentRecordsPerColumn(null, $this->siteLanguage->getLanguageId());
289
        $contentRecords = empty($contentRecordsPerColumn) ? [] : array_merge(...$contentRecordsPerColumn);
290
        $translationData = $this->contentFetcher->getTranslationData($contentRecords, $this->siteLanguage->getLanguageId());
291
        return $translationData['mode'] ?? '';
292
    }
293
294
    public function getNewLanguageOptions(): array
295
    {
296
        if (!$this->getBackendUser()->check('tables_modify', 'pages')) {
297
            return [];
298
        }
299
        $id = $this->getPageId();
300
301
        // First, select all languages that are available for the current user
302
        $availableTranslations = [];
303
        foreach ($this->getSiteLanguages() as $language) {
304
            if ($language->getLanguageId() === 0) {
305
                continue;
306
            }
307
            $availableTranslations[$language->getLanguageId()] = $language->getTitle();
308
        }
309
310
        // Then, subtract the languages which are already on the page:
311
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
312
        $queryBuilder->getRestrictions()->removeAll()
313
            ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
314
            ->add(GeneralUtility::makeInstance(WorkspaceRestriction::class, (int)$this->getBackendUser()->workspace));
315
        $queryBuilder->select('uid', $GLOBALS['TCA']['pages']['ctrl']['languageField'])
316
            ->from('pages')
317
            ->where(
318
                $queryBuilder->expr()->eq(
319
                    $GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField'],
320
                    $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT)
321
                )
322
            );
323
        $statement = $queryBuilder->execute();
324
        while ($row = $statement->fetch()) {
325
            unset($availableTranslations[(int)$row[$GLOBALS['TCA']['pages']['ctrl']['languageField']]]);
326
        }
327
        // If any languages are left, make selector:
328
        $options = [];
329
        if (!empty($availableTranslations)) {
330
            $options[] = $this->getLanguageService()->getLL('new_language');
331
            foreach ($availableTranslations as $languageUid => $languageTitle) {
332
                // Build localize command URL to DataHandler (tce_db)
333
                // which redirects to FormEngine (record_edit)
334
                // which, when finished editing should return back to the current page (returnUrl)
335
                $parameters = [
336
                    'justLocalized' => 'pages:' . $id . ':' . $languageUid,
337
                    'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
338
                ];
339
                $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
340
                $redirectUrl = (string)$uriBuilder->buildUriFromRoute('record_edit', $parameters);
341
                $targetUrl = BackendUtility::getLinkToDataHandlerAction(
342
                    '&cmd[pages][' . $id . '][localize]=' . $languageUid,
343
                    $redirectUrl
344
                );
345
346
                $options[$targetUrl] = $languageTitle;
347
            }
348
        }
349
        return $options;
350
    }
351
352
    public function getLocalizedPageTitle(): string
353
    {
354
        return $this->getLocalizedPageRecord()['title'] ?? $this->getPageRecord()['title'];
355
    }
356
357
    public function getLocalizedPageRecord(): ?array
358
    {
359
        return $this->localizedPageRecord;
360
    }
361
362
    protected function getLanguageService(): LanguageService
363
    {
364
        return $GLOBALS['LANG'];
365
    }
366
}
367