1<?php
2declare(strict_types = 1);
3namespace TYPO3\CMS\Core\Preparations;
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
18use TYPO3\CMS\Core\Database\ConnectionPool;
19use TYPO3\CMS\Core\Database\Query\QueryHelper;
20use TYPO3\CMS\Core\Utility\GeneralUtility;
21
22/**
23 * Prepare TCA. Used in bootstrap and Flex Form Data Structures.
24 *
25 * @internal Class and API may change any time.
26 */
27class TcaPreparation
28{
29
30    /**
31     * Prepare TCA
32     *
33     * This class is typically called within bootstrap with empty caches after all TCA
34     * files from extensions have been loaded. The preparation is then applied and
35     * the prepared result is cached.
36     * For flex form TCA, this class is called dynamically if opening a record in the backend.
37     *
38     * See unit tests for details.
39     *
40     * @param array $tca
41     * @return array
42     */
43    public function prepare(array $tca): array
44    {
45        $tca = $this->prepareQuotingOfTableNamesAndColumnNames($tca);
46        return $tca;
47    }
48
49    /**
50     * Quote all table and field names in definitions known to possibly have quoted identifiers like '{#tablename}.{#columnname}='
51     *
52     * @param array $tca Incoming TCA
53     * @return array Prepared TCA
54     */
55    protected function prepareQuotingOfTableNamesAndColumnNames(array $tca): array
56    {
57        $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
58
59        $newTca = $tca;
60        $configToPrepareQuoting = [
61            'foreign_table_where',
62            'MM_table_where',
63            'search' => 'andWhere'
64        ];
65        foreach ($tca as $table => $tableDefinition) {
66            if (!isset($tableDefinition['columns']) || !is_array($tableDefinition['columns'])) {
67                continue;
68            }
69
70            foreach ($tableDefinition['columns'] as $columnName => $columnConfig) {
71                foreach ($configToPrepareQuoting as $level => $value) {
72                    if (is_string($level)) {
73                        $sqlQueryPartToPrepareQuotingIn = $columnConfig['config'][$level][$value] ?? '';
74                    } else {
75                        $sqlQueryPartToPrepareQuotingIn = $columnConfig['config'][$value] ?? '';
76                    }
77                    if (mb_strpos($sqlQueryPartToPrepareQuotingIn, '{#') !== false) {
78                        $quoted = QueryHelper::quoteDatabaseIdentifiers(
79                            $connectionPool->getConnectionForTable($table),
80                            $sqlQueryPartToPrepareQuotingIn
81                        );
82                        if (is_string($level)) {
83                            $newTca[$table]['columns'][$columnName]['config'][$level][$value] = $quoted;
84                        } else {
85                            $newTca[$table]['columns'][$columnName]['config'][$value] = $quoted;
86                        }
87                    }
88                }
89            }
90        }
91
92        return $newTca;
93    }
94}
95