‪TYPO3CMS  ‪main
SiteLanguageContainer.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
25 
32 {
33  private const ‪FOREIGN_TABLE = 'site_language';
34  private const ‪FOREIGN_FIELD = 'languageId';
35 
36  protected array ‪$inlineData;
37 
43  protected ‪$defaultFieldInformation = [
44  'tcaDescription' => [
45  'renderType' => 'tcaDescription',
46  ],
47  ];
48 
49  public function ‪__construct(
50  private readonly ‪InlineStackProcessor $inlineStackProcessor,
51  private readonly ‪SiteLanguagePresets $siteLanguagePresets,
52  private readonly ‪HashService $hashService,
53  ) {}
54 
55  public function ‪render(): array
56  {
57  $this->inlineData = $this->data['inlineData'];
58 
59  $this->inlineStackProcessor->initializeByGivenStructure($this->data['inlineStructure']);
60 
61  $row = $this->data['databaseRow'];
62  $parameterArray = $this->data['parameterArray'];
63  $config = $parameterArray['fieldConf']['config'];
64  $resultArray = $this->‪initializeResultArray();
65 
66  // Add the current inline job to the structure stack
67  $this->inlineStackProcessor->pushStableStructureItem([
68  'table' => $this->data['tableName'],
69  'uid' => $row['uid'],
70  'field' => $this->data['fieldName'],
71  'config' => $config,
72  ]);
73 
74  // Hand over original returnUrl to SiteInlineAjaxController. Needed if opening for instance a
75  // nested element in a new view to then go back to the original returnUrl and not the url of
76  // the site inline ajax controller.
77  $config['originalReturnUrl'] = $this->data['returnUrl'];
78 
79  // e.g. data[site][1][languages]
80  $nameForm = $this->inlineStackProcessor->getCurrentStructureFormPrefix();
81  // e.g. data-0-site-1-languages
82  $nameObject = $this->inlineStackProcessor->getCurrentStructureDomObjectIdPrefix($this->data['inlineFirstPid']);
83  // e.g. array('table' => 'site', 'uid' => '1', 'field' => 'languages', 'config' => array())
84  $top = $this->inlineStackProcessor->getStructureLevel(0);
85 
86  $this->inlineData['config'][$nameObject] = [
87  'table' => ‪self::FOREIGN_TABLE,
88  ];
89 
90  $configJson = (string)json_encode($config);
91  $this->inlineData['config'][$nameObject . '-' . ‪self::FOREIGN_TABLE] = [
92  'min' => $config['minitems'],
93  'max' => $config['maxitems'],
94  'sortable' => false,
95  'top' => [
96  'table' => $top['table'],
97  'uid' => $top['uid'],
98  ],
99  'context' => [
100  'config' => $configJson,
101  'hmac' => $this->hashService->hmac($configJson, 'InlineContext'),
102  ],
103  ];
104  $this->inlineData['nested'][$nameObject] = $this->data['tabAndInlineStack'];
105 
106  $uniqueIds = [];
107  foreach ($parameterArray['fieldConf']['children'] as $children) {
108  $value = (int)($children['databaseRow'][self::FOREIGN_FIELD]['0'] ?? 0);
109  if (isset($children['databaseRow']['uid'])) {
110  $uniqueIds[$children['databaseRow']['uid']] = $value;
111  }
112  }
113 
114  $uniquePossibleRecords = $config['uniquePossibleRecords'] ?? [];
115  $possibleRecordsUidToTitle = [];
116  foreach ($uniquePossibleRecords as $possibleRecord) {
117  $possibleRecordsUidToTitle[$possibleRecord['value']] = $possibleRecord['label'];
118  }
119  $this->inlineData['unique'][$nameObject . '-' . ‪self::FOREIGN_TABLE] = [
120  // Usually "max" would be the number of possible records. However, since
121  // we also allow new languages to be created, we just use the maxitems value.
122  'max' => $config['maxitems'],
123  // "used" must be a string array
124  'used' => array_map(strval(...), $uniqueIds),
125  'table' => ‪self::FOREIGN_TABLE,
126  'elTable' => ‪self::FOREIGN_TABLE,
127  'field' => ‪self::FOREIGN_FIELD,
128  'possible' => $possibleRecordsUidToTitle,
129  ];
130 
131  $resultArray['inlineData'] = ‪$this->inlineData;
132 
133  $fieldInformationResult = $this->‪renderFieldInformation();
134  $resultArray = $this->‪mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false);
135  $selectorOptions = $childRecordUids = $childHtml = [];
136 
137  foreach ($config['uniquePossibleRecords'] ?? [] as ‪$record) {
138  // Do not add the PHP_INT_MAX placeholder or already configured languages
139  if (‪$record['value'] !== PHP_INT_MAX && !in_array(‪$record['value'], $uniqueIds, true)) {
140  $selectorOptions[] = ['value' => (string)‪$record['value'], 'label' => (string)‪$record['label']];
141  }
142  }
143 
144  foreach ($this->data['parameterArray']['fieldConf']['children'] as $children) {
145  $children['inlineParentUid'] = $row['uid'];
146  $children['inlineFirstPid'] = $this->data['inlineFirstPid'];
147  $children['inlineParentConfig'] = $config;
148  $children['inlineData'] = ‪$this->inlineData;
149  $children['inlineStructure'] = $this->inlineStackProcessor->getStructure();
150  $children['inlineExpandCollapseStateArray'] = $this->data['inlineExpandCollapseStateArray'];
151  $children['renderType'] = 'inlineRecordContainer';
152  $childResult = $this->nodeFactory->create($children)->render();
153  $childHtml[] = $childResult['html'];
154  $resultArray = $this->‪mergeChildReturnIntoExistingResult($resultArray, $childResult, false);
155  if (isset($children['databaseRow']['uid'])) {
156  $childRecordUids[] = $children['databaseRow']['uid'];
157  }
158  }
159 
160  $view = $this->backendViewFactory->create($this->data['request']);
161  $view->assignMultiple([
162  'nameObject' => $nameObject,
163  'nameForm' => $nameForm,
164  'formGroupAttributes' => GeneralUtility::implodeAttributes([
165  'class' => 'form-group',
166  'id' => $nameObject,
167  'data-uid' => (string)$row['uid'],
168  'data-local-table' => (string)$top['table'],
169  'data-local-field' => (string)$top['field'],
170  'data-foreign-table' => self::FOREIGN_TABLE,
171  'data-object-group' => $nameObject . '-' . self::FOREIGN_TABLE,
172  'data-form-field' => $nameForm,
173  'data-appearance' => (string)json_encode($config['appearance'] ?? ''),
174  ], true),
175  'fieldInformation' => $fieldInformationResult['html'],
176  'selectorConfiguration' => [
177  'identifier' => $nameObject . '-' . self::FOREIGN_TABLE . '_selector',
178  'options' => $selectorOptions,
179  ],
180  'inlineRecords' => [
181  'identifier' => $nameObject . '_records',
182  'title' => trim($parameterArray['fieldConf']['label'] ?? ''),
183  'records' => implode(PHP_EOL, $childHtml),
184  ],
185  'childRecordUids' => implode(',', $childRecordUids),
186  'validationRules' => $this->‪getValidationDataAsJsonString([
187  'type' => 'inline',
188  'minitems' => $config['minitems'] ?? null,
189  'maxitems' => $config['maxitems'] ?? null,
190  ]),
191  'presetOptions' => [
192  'identifier' => $nameObject . '_preset',
193  'options' => $this->siteLanguagePresets->getAllForSelector(),
194  ],
195  ]);
196 
197  $resultArray['html'] = $this->‪wrapWithFieldsetAndLegend($view->render('Form/SiteLanguageContainer'));
198  $resultArray['javaScriptModules'][] = ‪JavaScriptModuleInstruction::create('@typo3/backend/form-engine/container/site-language-container.js');
199 
200  return $resultArray;
201  }
202 }
‪TYPO3\CMS\Backend\Form\AbstractNode\mergeChildReturnIntoExistingResult
‪array mergeChildReturnIntoExistingResult(array $existing, array $childReturn, bool $mergeHtml=true)
Definition: AbstractNode.php:104
‪TYPO3\CMS\Backend\Form\Container\SiteLanguageContainer\FOREIGN_TABLE
‪const FOREIGN_TABLE
Definition: SiteLanguageContainer.php:33
‪TYPO3\CMS\Backend\Form\Container\SiteLanguageContainer\$inlineData
‪array $inlineData
Definition: SiteLanguageContainer.php:36
‪TYPO3\CMS\Backend\Form\Container\SiteLanguageContainer\render
‪render()
Definition: SiteLanguageContainer.php:54
‪TYPO3\CMS\Core\Page\JavaScriptModuleInstruction\create
‪static create(string $name, string $exportName=null)
Definition: JavaScriptModuleInstruction.php:47
‪TYPO3\CMS\Backend\Form\Container
Definition: AbstractContainer.php:16
‪TYPO3\CMS\Backend\Form\Container\AbstractContainer\wrapWithFieldsetAndLegend
‪wrapWithFieldsetAndLegend(string $fieldContent)
Definition: AbstractContainer.php:140
‪TYPO3\CMS\Core\Page\JavaScriptModuleInstruction
Definition: JavaScriptModuleInstruction.php:23
‪TYPO3\CMS\Backend\Form\Container\SiteLanguageContainer\__construct
‪__construct(private readonly InlineStackProcessor $inlineStackProcessor, private readonly SiteLanguagePresets $siteLanguagePresets, private readonly HashService $hashService,)
Definition: SiteLanguageContainer.php:48
‪TYPO3\CMS\Backend\Form\Container\SiteLanguageContainer\$defaultFieldInformation
‪array $defaultFieldInformation
Definition: SiteLanguageContainer.php:42
‪TYPO3\CMS\Backend\Form\Container\AbstractContainer
Definition: AbstractContainer.php:29
‪TYPO3\CMS\Webhooks\Message\$record
‪identifier readonly int readonly array $record
Definition: PageModificationMessage.php:36
‪TYPO3\CMS\Backend\Form\Container\SiteLanguageContainer
Definition: SiteLanguageContainer.php:32
‪TYPO3\CMS\Backend\Form\Container\AbstractContainer\renderFieldInformation
‪array renderFieldInformation()
Definition: AbstractContainer.php:52
‪TYPO3\CMS\Backend\Form\Container\SiteLanguageContainer\FOREIGN_FIELD
‪const FOREIGN_FIELD
Definition: SiteLanguageContainer.php:34
‪TYPO3\CMS\Backend\Form\AbstractNode\getValidationDataAsJsonString
‪getValidationDataAsJsonString(array $config)
Definition: AbstractNode.php:133
‪TYPO3\CMS\Core\Site\SiteLanguagePresets
Definition: SiteLanguagePresets.php:25
‪TYPO3\CMS\Backend\Form\InlineStackProcessor
Definition: InlineStackProcessor.php:32
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Core\Crypto\HashService
Definition: HashService.php:27
‪TYPO3\CMS\Backend\Form\AbstractNode\initializeResultArray
‪initializeResultArray()
Definition: AbstractNode.php:77