[TASK] Use ImageInfo class instead of direct PHP GD call
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Form / Utility / FormEngineUtility.php
1 <?php
2 namespace TYPO3\CMS\Backend\Form\Utility;
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\Authentication\BackendUserAuthentication;
19 use TYPO3\CMS\Core\Imaging\Icon;
20 use TYPO3\CMS\Core\Imaging\IconFactory;
21 use TYPO3\CMS\Core\Utility\ArrayUtility;
22 use TYPO3\CMS\Core\Utility\GeneralUtility;
23 use TYPO3\CMS\Core\Utility\PathUtility;
24
25 /**
26 * This is a static, internal and intermediate helper class for various
27 * FormEngine related tasks.
28 *
29 * This class was introduced to help disentangling FormEngine and
30 * its sub classes. It MUST NOT be used in other extensions and will
31 * change or vanish without further notice.
32 *
33 * @internal
34 * @todo: These helpers are target to be dropped if further FormEngine refactoring is done
35 */
36 class FormEngineUtility
37 {
38 /**
39 * Whitelist that allows TCA field configuration to be overridden by TSconfig
40 *
41 * @see overrideFieldConf()
42 * @var array
43 */
44 protected static $allowOverrideMatrix = [
45 'input' => ['size', 'max', 'readOnly'],
46 'text' => ['cols', 'rows', 'wrap', 'max', 'readOnly'],
47 'check' => ['cols', 'readOnly'],
48 'select' => ['size', 'autoSizeMax', 'maxitems', 'minitems', 'readOnly', 'treeConfig'],
49 'group' => ['size', 'autoSizeMax', 'max_size', 'maxitems', 'minitems', 'readOnly'],
50 'inline' => ['appearance', 'behaviour', 'foreign_label', 'foreign_selector', 'foreign_unique', 'maxitems', 'minitems', 'size', 'autoSizeMax', 'symmetric_label', 'readOnly'],
51 'imageManipulation' => ['ratios', 'cropVariants']
52 ];
53
54 /**
55 * Overrides the TCA field configuration by TSconfig settings.
56 *
57 * Example TSconfig: TCEform.<table>.<field>.config.appearance.useSortable = 1
58 * This overrides the setting in $GLOBALS['TCA'][<table>]['columns'][<field>]['config']['appearance']['useSortable'].
59 *
60 * @param array $fieldConfig $GLOBALS['TCA'] field configuration
61 * @param array $TSconfig TSconfig
62 * @return array Changed TCA field configuration
63 * @internal
64 */
65 public static function overrideFieldConf($fieldConfig, $TSconfig)
66 {
67 if (is_array($TSconfig)) {
68 $TSconfig = GeneralUtility::removeDotsFromTS($TSconfig);
69 $type = $fieldConfig['type'];
70 if (is_array($TSconfig['config']) && is_array(static::$allowOverrideMatrix[$type])) {
71 // Check if the keys in TSconfig['config'] are allowed to override TCA field config:
72 foreach ($TSconfig['config'] as $key => $_) {
73 if (!in_array($key, static::$allowOverrideMatrix[$type], true)) {
74 unset($TSconfig['config'][$key]);
75 }
76 }
77 // Override $GLOBALS['TCA'] field config by remaining TSconfig['config']:
78 if (!empty($TSconfig['config'])) {
79 ArrayUtility::mergeRecursiveWithOverrule($fieldConfig, $TSconfig['config']);
80 }
81 }
82 }
83 return $fieldConfig;
84 }
85
86 /**
87 * Returns TSconfig for given table and row
88 *
89 * @param string $table The table name
90 * @param array $row The table row - Must at least contain the "uid" value, even if "NEW..." string.
91 * The "pid" field is important as well, negative values will be interpreted as pointing to a record from the same table.
92 * @param string $field Optionally specify the field name as well. In that case the TSconfig for this field is returned.
93 * @return mixed The TSconfig values - probably in an array
94 * @internal
95 */
96 public static function getTSconfigForTableRow($table, $row, $field = '')
97 {
98 static $cache;
99 if (is_null($cache)) {
100 $cache = [];
101 }
102 $cacheIdentifier = $table . ':' . $row['uid'];
103 if (!isset($cache[$cacheIdentifier])) {
104 $cache[$cacheIdentifier] = BackendUtility::getTCEFORM_TSconfig($table, $row);
105 }
106 if ($field) {
107 return $cache[$cacheIdentifier][$field];
108 }
109 return $cache[$cacheIdentifier];
110 }
111
112 /**
113 * Renders the $icon, supports a filename for skinImg or sprite-icon-name
114 *
115 * @param string $icon The icon passed, could be a file-reference or a sprite Icon name
116 * @param string $alt Alt attribute of the icon returned
117 * @param string $title Title attribute of the icon return
118 * @return string A tag representing to show the asked icon
119 * @internal
120 */
121 public static function getIconHtml($icon, $alt = '', $title = '')
122 {
123 $icon = (string)$icon;
124 $absoluteFilePath = GeneralUtility::getFileAbsFileName($icon);
125 if (!empty($absoluteFilePath) && is_file($absoluteFilePath)) {
126 return '<img'
127 . ' src="' . htmlspecialchars(PathUtility::getAbsoluteWebPath($absoluteFilePath)) . '"'
128 . ' alt="' . htmlspecialchars($alt) . '" '
129 . ($title ? 'title="' . htmlspecialchars($title) . '"' : '')
130 . ' />';
131 }
132
133 $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
134 return '<span title="' . htmlspecialchars($title) . '">'
135 . $iconFactory->getIcon($icon, Icon::SIZE_SMALL)->render()
136 . '</span>';
137 }
138
139 /**
140 * Update expanded/collapsed states on new inline records if any.
141 *
142 * @param array $uc The uc array to be processed and saved (by reference)
143 * @param \TYPO3\CMS\Core\DataHandling\DataHandler $tce Instance of FormEngine that saved data before
144 * @internal
145 */
146 public static function updateInlineView(&$uc, $tce)
147 {
148 $backendUser = static::getBackendUserAuthentication();
149 if (isset($uc['inlineView']) && is_array($uc['inlineView'])) {
150 $inlineView = (array)unserialize($backendUser->uc['inlineView']);
151 foreach ($uc['inlineView'] as $topTable => $topRecords) {
152 foreach ($topRecords as $topUid => $childElements) {
153 foreach ($childElements as $childTable => $childRecords) {
154 $uids = array_keys($tce->substNEWwithIDs_table, $childTable);
155 if (!empty($uids)) {
156 $newExpandedChildren = [];
157 foreach ($childRecords as $childUid => $state) {
158 if ($state && in_array($childUid, $uids)) {
159 $newChildUid = $tce->substNEWwithIDs[$childUid];
160 $newExpandedChildren[] = $newChildUid;
161 }
162 }
163 // Add new expanded child records to UC (if any):
164 if (!empty($newExpandedChildren)) {
165 $inlineViewCurrent = &$inlineView[$topTable][$topUid][$childTable];
166 if (is_array($inlineViewCurrent)) {
167 $inlineViewCurrent = array_unique(array_merge($inlineViewCurrent, $newExpandedChildren));
168 } else {
169 $inlineViewCurrent = $newExpandedChildren;
170 }
171 }
172 }
173 }
174 }
175 }
176 $backendUser->uc['inlineView'] = serialize($inlineView);
177 $backendUser->writeUC();
178 }
179 }
180
181 /**
182 * Compatibility layer for methods not in FormEngine scope.
183 *
184 * databaseRow was a flat array with single elements in select and group fields as comma separated list.
185 * With new data handling in FormEngine, this is now an array of element values. There are however "old"
186 * methods that still expect the flat array.
187 * This method implodes the array again to fake the old behavior of a database row before it is given
188 * to those methods.
189 *
190 * @param array $row Incoming array
191 * @return array Flat array
192 * @internal
193 */
194 public static function databaseRowCompatibility(array $row)
195 {
196 $newRow = [];
197 foreach ($row as $fieldName => $fieldValue) {
198 if (!is_array($fieldValue)) {
199 $newRow[$fieldName] = $fieldValue;
200 } else {
201 $newElementValue = [];
202 foreach ($fieldValue as $itemNumber => $itemValue) {
203 if (is_array($itemValue) && array_key_exists(1, $itemValue)) {
204 $newElementValue[] = $itemValue[1];
205 } else {
206 $newElementValue[] = $itemValue;
207 }
208 }
209 $newRow[$fieldName] = implode(',', $newElementValue);
210 }
211 }
212 return $newRow;
213 }
214
215 /**
216 * @return BackendUserAuthentication
217 */
218 protected static function getBackendUserAuthentication()
219 {
220 return $GLOBALS['BE_USER'];
221 }
222 }