Completed
Push — master ( 0a63e5...44f21d )
by Tim
02:15
created

getCustomModelFields()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 26
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
dl 0
loc 26
ccs 0
cts 4
cp 0
rs 8.8571
c 0
b 0
f 0
cc 3
eloc 18
nc 3
nop 1
crap 12
1
<?php
2
3
/**
4
 * SmartObjectInformationService.php.
5
 */
6
declare(strict_types=1);
7
8
namespace HDNET\Autoloader\Service;
9
10
use HDNET\Autoloader\DataSet;
11
use HDNET\Autoloader\Mapper;
12
use HDNET\Autoloader\Utility\ArrayUtility;
13
use HDNET\Autoloader\Utility\ClassNamingUtility;
14
use HDNET\Autoloader\Utility\ExtendedUtility;
15
use HDNET\Autoloader\Utility\IconUtility;
16
use HDNET\Autoloader\Utility\ModelUtility;
17
use HDNET\Autoloader\Utility\ReflectionUtility;
18
use HDNET\Autoloader\Utility\TranslateUtility;
19
use TYPO3\CMS\Core\Utility\GeneralUtility;
20
21
/**
22
 * SmartObjectInformationService.
23
 */
24
class SmartObjectInformationService
25
{
26
27
    /**
28
     * Get a instance of this object.
29
     *
30
     * @return \HDNET\Autoloader\Service\SmartObjectInformationService
31
     */
32
    public static function getInstance()
33
    {
34
        return GeneralUtility::makeInstance(self::class);
35
    }
36
37
    /**
38
     * Get database information.
39
     *
40
     * @param $modelClassName
41
     *
42
     * @return string
43
     */
44
    public function getDatabaseInformation($modelClassName)
45
    {
46
        $tableName = ModelUtility::getTableName($modelClassName);
47
        $custom = $this->getCustomDatabaseInformation($modelClassName);
48
49
        // disable complete table generation
50
        // for extending existing tables
51
        if ('' !== ModelUtility::getTableNameByModelReflectionAnnotation($modelClassName)) {
52
            return $this->generateSqlQuery($tableName, $custom);
53
        }
54
55
        return $this->generateCompleteSqlQuery($modelClassName, $tableName, $custom);
56
    }
57
58
    /**
59
     * Get the custom Model field TCA structure.
60
     *
61
     * @param       $modelClassName
62
     * @param array $searchFields
63
     *
64
     * @return array
65
     */
66
    public function getCustomModelFieldTca($modelClassName, &$searchFields = [])
67
    {
68
        $modelInformation = ClassNamingUtility::explodeObjectModelName($modelClassName);
69
        $extensionName = GeneralUtility::camelCaseToLowerCaseUnderscored($modelInformation['extensionName']);
70
        $tableName = ModelUtility::getTableName($modelClassName);
71
        $customFieldInfo = $this->getCustomModelFields($modelClassName);
72
        $searchFields = [];
73
        $customFields = [];
74
        foreach ($customFieldInfo as $info) {
75
            $key = $tableName . '.' . $info['name'];
76
77
            if ($this->useTableNameFileBase()) {
78
                // Without prefix !
79
                $key = $info['name'];
80
            }
81
82
            try {
83
                TranslateUtility::assureLabel($key, $extensionName, $info['name'], null, $tableName);
84
                $label = TranslateUtility::getLllOrHelpMessage($key, $extensionName, $tableName);
85
            } catch (\Exception $ex) {
86
                $label = $info['name'];
87
            }
88
89
            /** @var Mapper $mapper */
90
            $mapper = ExtendedUtility::create(Mapper::class);
91
            $field = $mapper->getTcaConfiguration(\trim($info['var'], '\\'), $info['name'], $label);
92
93
            // RTE
94
            if ($info['rte']) {
95
                $field['config']['type'] = 'text';
96
                $field['config']['enableRichtext'] = '1';
97
                $field['config']['richtextConfiguration'] = 'default';
98
                $field['defaultExtras'] = 'richtext:rte_transform[flag=rte_enabled|mode=ts_css]';
99
            }
100
101
            $searchFields[] = $info['name'];
102
            $customFields[$info['name']] = $field;
103
        }
104
105
        return $customFields;
106
    }
107
108
    /**
109
     * Pre build TCA information for the given model.
110
     *
111
     * @param string $modelClassName
112
     *
113
     * @return array
114
     */
115
    public function getTcaInformation($modelClassName)
116
    {
117
        $modelInformation = ClassNamingUtility::explodeObjectModelName($modelClassName);
118
        $extensionName = GeneralUtility::camelCaseToLowerCaseUnderscored($modelInformation['extensionName']);
119
        $reflectionTableName = ModelUtility::getTableNameByModelReflectionAnnotation($modelClassName);
120
        $tableName = ModelUtility::getTableNameByModelName($modelClassName);
121
122
        $searchFields = [];
123
        $customFields = $this->getCustomModelFieldTca($modelClassName, $searchFields);
124
125
        if ('' !== $reflectionTableName) {
126
            $customConfiguration = [
127
                'columns' => $customFields,
128
            ];
129
            $base = \is_array($GLOBALS['TCA'][$reflectionTableName]) ? $GLOBALS['TCA'][$reflectionTableName] : [];
130
131
            return ArrayUtility::mergeRecursiveDistinct($base, $customConfiguration);
132
        }
133
134
        $excludes = ModelUtility::getSmartExcludesByModelName($modelClassName);
135
136
        $dataSet = $this->getDataSet();
137
        $dataImplementations = $dataSet->getAllAndExcludeList($excludes);
138
        $baseTca = $dataSet->getTcaInformation($dataImplementations, $tableName);
139
140
        // title
141
        $fields = \array_keys($customFields);
142
        $labelField = 'title';
143
        if (!\in_array($labelField, $fields, true)) {
144
            $labelField = $fields[0];
145
        }
146
        try {
147
            TranslateUtility::assureLabel($tableName, $extensionName, null, null, $tableName);
148
        } catch (\Exception $ex) {
149
            // Do not handle the error of the assureLabel method
150
        }
151
        if (!\is_array($baseTca['columns'])) {
152
            $baseTca['columns'] = [];
153
        }
154
        $baseTca['columns'] = ArrayUtility::mergeRecursiveDistinct($baseTca['columns'], $customFields);
155
156
        // items
157
        $showitem = $fields;
158
        if (!\in_array('language', $excludes, true)) {
159
            $showitem[] = '--div--;LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:language,--palette--;;language';
160
        }
161
162
        if (!\in_array('workspaces', $excludes, true)) {
163
            $baseTca['ctrl']['shadowColumnsForNewPlaceholders'] .= ',' . $labelField;
164
        }
165
166
        $languagePrefix = 'LLL:EXT:frontend/Resources/Private/Language/';
167
        if (!\in_array('enableFields', $excludes, true)) {
168
            $showitem[] = '--div--;' . $languagePrefix . 'locallang_ttc.xlf:tabs.access';
169
            $showitem[] = '--palette--;' . $languagePrefix . 'locallang_tca.xlf:pages.palettes.access;access';
170
        }
171
        $showitem[] = '--div--;' . $languagePrefix . 'locallang_ttc.xlf:tabs.extended';
172
173
        $overrideTca = [
174
            'ctrl'      => [
175
                'title'         => $this->getTcaTitle($tableName, $extensionName),
176
                'label'         => $labelField,
177
                'tstamp'        => 'tstamp',
178
                'crdate'        => 'crdate',
179
                'cruser_id'     => 'cruser_id',
180
                'dividers2tabs' => true,
181
                'sortby'        => 'sorting',
182
                'delete'        => 'deleted',
183
                'searchFields'  => \implode(',', $searchFields),
184
                'iconfile'      => IconUtility::getByModelName($modelClassName, true),
185
            ],
186
            'interface' => [
187
                'showRecordFieldList' => \implode(',', \array_keys($baseTca['columns'])),
188
            ],
189
            'types'     => [
190
                '1' => ['showitem' => \implode(',', $showitem)],
191
            ],
192
            'palettes'  => [
193
                'access' => ['showitem' => 'starttime, endtime, --linebreak--, hidden, editlock, --linebreak--, fe_group'],
194
            ],
195
        ];
196
197
        return ArrayUtility::mergeRecursiveDistinct($baseTca, $overrideTca);
198
    }
199
200
    /**
201
     * Check if table name file base is used.
202
     *
203
     * @return bool
204
     */
205
    protected function useTableNameFileBase()
206
    {
207
        $configuration = \unserialize((string)$GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['autoloader']);
208
209
        return isset($configuration['enableLanguageFileOnTableBase']) ? (bool)$configuration['enableLanguageFileOnTableBase'] : false;
210
    }
211
212
    /**
213
     * Get custom database information for the given model.
214
     *
215
     * @param string $modelClassName
216
     *
217
     * @return array
218
     */
219
    protected function getCustomDatabaseInformation($modelClassName)
220
    {
221
        $fieldInformation = $this->getCustomModelFields($modelClassName);
222
        $fields = [];
223
        foreach ($fieldInformation as $info) {
224
            if ('' === $info['db']) {
225
                $info['db'] = $this->getDatabaseMappingByVarType($info['var']);
226
            } else {
227
                try {
228
                    $info['db'] = $this->getDatabaseMappingByVarType($info['db']);
229
                } catch (\Exception $ex) {
230
                    // Do not handle the getDatabaseMappingByVarType by db, Fallback is the var call
231
                }
232
            }
233
            $fields[] = $info['name'] . ' ' . $info['db'];
234
        }
235
236
        return $fields;
237
    }
238
239
    /**
240
     * Get the right mapping.
241
     *
242
     * @param $var
243
     *
244
     * @throws \HDNET\Autoloader\Exception
245
     *
246
     * @return string
247
     */
248
    protected function getDatabaseMappingByVarType($var)
249
    {
250
        /** @var Mapper $mapper */
251
        $mapper = ExtendedUtility::create(Mapper::class);
252
253
        return $mapper->getDatabaseDefinition($var);
254
    }
255
256
    /**
257
     * Get custom database information for the given model.
258
     *
259
     * @param string $modelClassName
260
     *
261
     * @return array
262
     */
263
    protected function getCustomModelFields(string $modelClassName): array
264
    {
265
        $properties = ReflectionUtility::getPropertiesTaggedWith($modelClassName, 'db');
266
        $tableName = ModelUtility::getTableName($modelClassName);
267
        $nameMapperService = GeneralUtility::makeInstance(NameMapperService::class);
268
        $fields = [];
269
        foreach ($properties as $property) {
270
            /** @var \TYPO3\CMS\Extbase\Reflection\PropertyReflection $property */
271
            $var = '';
272
            if ($property->isTaggedWith('var')) {
273
                $var = $property->getTagValues('var');
274
                $var = $var[0];
275
            }
276
277
            $dbInformation = $property->getTagValues('db');
278
            $fields[] = [
279
                'property' => $property->getName(),
280
                'name'     => $nameMapperService->getDatabaseFieldName($tableName, $property->getName()),
281
                'db'       => \trim((string)$dbInformation[0]),
282
                'var'      => \trim((string)$var),
283
                'rte'      => (bool)$property->isTaggedWith('enableRichText'),
284
            ];
285
        }
286
287
        return $fields;
288
    }
289
290
    /**
291
     * Generate SQL Query.
292
     *
293
     * @param string $tableName
294
     * @param array  $fields
295
     *
296
     * @return string
297
     */
298
    protected function generateSqlQuery($tableName, array $fields)
299
    {
300
        if (empty($fields)) {
301
            return '';
302
        }
303
304
        return LF . 'CREATE TABLE ' . $tableName . ' (' . LF . \implode(',' . LF, $fields) . LF . ');' . LF;
305
    }
306
307
    /**
308
     * Generate complete SQL Query.
309
     *
310
     * @param string $modelClassName
311
     * @param string $tableName
312
     * @param array  $custom
313
     *
314
     * @return string
315
     */
316
    protected function generateCompleteSqlQuery($modelClassName, $tableName, array $custom)
317
    {
318
        $fields = [];
319
        $fields[] = 'uid int(11) NOT NULL auto_increment';
320
        $fields[] = 'pid int(11) DEFAULT \'0\' NOT NULL';
321
        $fields[] = 'tstamp int(11) unsigned DEFAULT \'0\' NOT NULL';
322
        $fields[] = 'crdate int(11) unsigned DEFAULT \'0\' NOT NULL';
323
        $fields[] = 'cruser_id int(11) unsigned DEFAULT \'0\' NOT NULL';
324
        $fields[] = 'deleted tinyint(4) unsigned DEFAULT \'0\' NOT NULL';
325
        $fields[] = 'sorting int(11) DEFAULT \'0\' NOT NULL';
326
327
        foreach ($custom as $field) {
328
            $fields[] = $field;
329
        }
330
331
        $excludes = ModelUtility::getSmartExcludesByModelName($modelClassName);
332
        $dataSet = $this->getDataSet();
333
        $dataImplementations = $dataSet->getAllAndExcludeList($excludes);
334
335
        // add data set fields
336
        $fields = \array_merge($fields, $dataSet->getDatabaseSqlInformation($dataImplementations, $tableName));
337
338
        // default keys
339
        $fields[] = 'PRIMARY KEY (uid)';
340
        $fields[] = 'KEY parent (pid)';
341
342
        // add custom keys set by @key annotations
343
        $classReflection = ReflectionUtility::createReflectionClass($modelClassName);
344
        if ($classReflection->isTaggedWith('key')) {
345
            $additionalKeys = $classReflection->getTagValues('key');
346
            \array_walk($additionalKeys, function (&$item) {
347
                $item = 'KEY ' . $item;
348
            });
349
            $fields = \array_merge($fields, $additionalKeys);
350
        }
351
352
        // add data set keys
353
        $fields = \array_merge($fields, $dataSet->getDatabaseSqlKeyInformation($dataImplementations, $tableName));
354
355
        return $this->generateSqlQuery($tableName, $fields);
356
    }
357
358
    /**
359
     * Get the data set object.
360
     *
361
     * @return \HDNET\Autoloader\DataSet
362
     */
363
    protected function getDataSet()
364
    {
365
        return GeneralUtility::makeInstance(DataSet::class);
366
    }
367
368
    /**
369
     * Get TCA title.
370
     *
371
     * @param string $tableName
372
     * @param string $extensionName
373
     *
374
     * @return string
375
     */
376
    protected function getTcaTitle($tableName, $extensionName)
377
    {
378
        return TranslateUtility::getLllOrHelpMessage($tableName, $extensionName, $tableName);
379
    }
380
}
381