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