Commit 784729b8 authored by Christian Kuhn's avatar Christian Kuhn Committed by Benni Mack
Browse files

[!!!][TASK] Remove QueryView and QueryGenerator in ext:core

Change-Id: I417f0f896e07b05d4577c865195724955fa7bc45
Resolves: #96113
Related: #92080
Releases: master
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/72334


Tested-by: core-ci's avatarcore-ci <typo3@b13.com>
Tested-by: Stefan Bürk's avatarStefan Bürk <stefan@buerk.tech>
Tested-by: Benni Mack's avatarBenni Mack <benni@typo3.org>
Reviewed-by: Stefan Bürk's avatarStefan Bürk <stefan@buerk.tech>
Reviewed-by: Benni Mack's avatarBenni Mack <benni@typo3.org>
parent 7fecd98c
......@@ -162,10 +162,6 @@ parameters:
path: typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php
# Ignored errors for level 5
-
message: "#^Parameter \\#1 \\$constraint of static method TYPO3\\\\CMS\\\\Core\\\\Database\\\\Query\\\\QueryHelper\\:\\:stripLogicalOperatorPrefix\\(\\) expects string, string\\|null given\\.$#"
count: 1
path: typo3/sysext/core/Classes/Database/QueryView.php
-
message: "#^Parameter \\#2 \\$id of method TYPO3\\\\CMS\\\\Core\\\\DataHandling\\\\DataHandler\\:\\:getRecordProperties\\(\\) expects int, int\\|string given\\.$#"
count: 2
......
<?php
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
namespace TYPO3\CMS\Core\Database;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
use TYPO3\CMS\Core\Database\Query\QueryHelper;
use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
use TYPO3\CMS\Core\Localization\LanguageService;
use TYPO3\CMS\Core\Type\Bitmask\Permission;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\MathUtility;
use TYPO3\CMS\Core\Utility\StringUtility;
/**
* Class for generating front end for building queries
*
* @deprecated since v11, will be removed in v12
*/
class QueryGenerator
{
/**
* @var array
*/
public $lang = [
'OR' => 'or',
'AND' => 'and',
'comparison' => [
// Type = text offset = 0
'0_' => 'contains',
'1_' => 'does not contain',
'2_' => 'starts with',
'3_' => 'does not start with',
'4_' => 'ends with',
'5_' => 'does not end with',
'6_' => 'equals',
'7_' => 'does not equal',
// Type = number , offset = 32
'32_' => 'equals',
'33_' => 'does not equal',
'34_' => 'is greater than',
'35_' => 'is less than',
'36_' => 'is between',
'37_' => 'is not between',
'38_' => 'is in list',
'39_' => 'is not in list',
'40_' => 'binary AND equals',
'41_' => 'binary AND does not equal',
'42_' => 'binary OR equals',
'43_' => 'binary OR does not equal',
// Type = multiple, relation, offset = 64
'64_' => 'equals',
'65_' => 'does not equal',
'66_' => 'contains',
'67_' => 'does not contain',
'68_' => 'is in list',
'69_' => 'is not in list',
'70_' => 'binary AND equals',
'71_' => 'binary AND does not equal',
'72_' => 'binary OR equals',
'73_' => 'binary OR does not equal',
// Type = date,time offset = 96
'96_' => 'equals',
'97_' => 'does not equal',
'98_' => 'is greater than',
'99_' => 'is less than',
'100_' => 'is between',
'101_' => 'is not between',
'102_' => 'binary AND equals',
'103_' => 'binary AND does not equal',
'104_' => 'binary OR equals',
'105_' => 'binary OR does not equal',
// Type = boolean, offset = 128
'128_' => 'is True',
'129_' => 'is False',
// Type = binary , offset = 160
'160_' => 'equals',
'161_' => 'does not equal',
'162_' => 'contains',
'163_' => 'does not contain',
],
];
/**
* @var array
*/
public $compSQL = [
// Type = text offset = 0
'0' => '#FIELD# LIKE \'%#VALUE#%\'',
'1' => '#FIELD# NOT LIKE \'%#VALUE#%\'',
'2' => '#FIELD# LIKE \'#VALUE#%\'',
'3' => '#FIELD# NOT LIKE \'#VALUE#%\'',
'4' => '#FIELD# LIKE \'%#VALUE#\'',
'5' => '#FIELD# NOT LIKE \'%#VALUE#\'',
'6' => '#FIELD# = \'#VALUE#\'',
'7' => '#FIELD# != \'#VALUE#\'',
// Type = number, offset = 32
'32' => '#FIELD# = \'#VALUE#\'',
'33' => '#FIELD# != \'#VALUE#\'',
'34' => '#FIELD# > #VALUE#',
'35' => '#FIELD# < #VALUE#',
'36' => '#FIELD# >= #VALUE# AND #FIELD# <= #VALUE1#',
'37' => 'NOT (#FIELD# >= #VALUE# AND #FIELD# <= #VALUE1#)',
'38' => '#FIELD# IN (#VALUE#)',
'39' => '#FIELD# NOT IN (#VALUE#)',
'40' => '(#FIELD# & #VALUE#)=#VALUE#',
'41' => '(#FIELD# & #VALUE#)!=#VALUE#',
'42' => '(#FIELD# | #VALUE#)=#VALUE#',
'43' => '(#FIELD# | #VALUE#)!=#VALUE#',
// Type = multiple, relation, offset = 64
'64' => '#FIELD# = \'#VALUE#\'',
'65' => '#FIELD# != \'#VALUE#\'',
'66' => '#FIELD# LIKE \'%#VALUE#%\' AND #FIELD# LIKE \'%#VALUE1#%\'',
'67' => '(#FIELD# NOT LIKE \'%#VALUE#%\' OR #FIELD# NOT LIKE \'%#VALUE1#%\')',
'68' => '#FIELD# IN (#VALUE#)',
'69' => '#FIELD# NOT IN (#VALUE#)',
'70' => '(#FIELD# & #VALUE#)=#VALUE#',
'71' => '(#FIELD# & #VALUE#)!=#VALUE#',
'72' => '(#FIELD# | #VALUE#)=#VALUE#',
'73' => '(#FIELD# | #VALUE#)!=#VALUE#',
// Type = date, offset = 32
'96' => '#FIELD# = \'#VALUE#\'',
'97' => '#FIELD# != \'#VALUE#\'',
'98' => '#FIELD# > #VALUE#',
'99' => '#FIELD# < #VALUE#',
'100' => '#FIELD# >= #VALUE# AND #FIELD# <= #VALUE1#',
'101' => 'NOT (#FIELD# >= #VALUE# AND #FIELD# <= #VALUE1#)',
'102' => '(#FIELD# & #VALUE#)=#VALUE#',
'103' => '(#FIELD# & #VALUE#)!=#VALUE#',
'104' => '(#FIELD# | #VALUE#)=#VALUE#',
'105' => '(#FIELD# | #VALUE#)!=#VALUE#',
// Type = boolean, offset = 128
'128' => '#FIELD# = \'1\'',
'129' => '#FIELD# != \'1\'',
// Type = binary = 160
'160' => '#FIELD# = \'#VALUE#\'',
'161' => '#FIELD# != \'#VALUE#\'',
'162' => '(#FIELD# & #VALUE#)=#VALUE#',
'163' => '(#FIELD# & #VALUE#)=0',
];
/**
* @var array
*/
public $comp_offsets = [
'text' => 0,
'number' => 1,
'multiple' => 2,
'relation' => 2,
'date' => 3,
'time' => 3,
'boolean' => 4,
'binary' => 5,
];
/**
* @var string
*/
public $noWrap = ' nowrap';
/**
* Form data name prefix
*
* @var string
*/
public $name;
/**
* Table for the query
*
* @var string
*/
public $table;
/**
* @var array
*/
public $tableArray;
/**
* Field list
*
* @var string
*/
public $fieldList;
/**
* Array of the fields possible
*
* @var array
*/
public $fields = [];
/**
* @var array
*/
public $extFieldLists = [];
/**
* The query config
*
* @var array
*/
public $queryConfig = [];
/**
* @var bool
*/
public $enablePrefix = false;
/**
* @var bool
*/
public $enableQueryParts = false;
/**
* @var string
*/
protected $formName = '';
/**
* @var string
*/
protected $fieldName;
/**
* @var array Settings, usually from the controller, previously known as MOD_SETTINGS
*/
protected $settings = [];
public function __construct()
{
trigger_error(__CLASS__ . ' will be removed in TYPO3 v12.', E_USER_DEPRECATED);
}
/**
* Make a list of fields for current table
*
* @return string Separated list of fields
*/
public function makeFieldList()
{
$fieldListArr = [];
if (is_array($GLOBALS['TCA'][$this->table])) {
$fieldListArr = array_keys($GLOBALS['TCA'][$this->table]['columns'] ?? []);
$fieldListArr[] = 'uid';
$fieldListArr[] = 'pid';
$fieldListArr[] = 'deleted';
if ($GLOBALS['TCA'][$this->table]['ctrl']['tstamp'] ?? false) {
$fieldListArr[] = $GLOBALS['TCA'][$this->table]['ctrl']['tstamp'];
}
if ($GLOBALS['TCA'][$this->table]['ctrl']['crdate'] ?? false) {
$fieldListArr[] = $GLOBALS['TCA'][$this->table]['ctrl']['crdate'];
}
if ($GLOBALS['TCA'][$this->table]['ctrl']['cruser_id'] ?? false) {
$fieldListArr[] = $GLOBALS['TCA'][$this->table]['ctrl']['cruser_id'];
}
if ($GLOBALS['TCA'][$this->table]['ctrl']['sortby'] ?? false) {
$fieldListArr[] = $GLOBALS['TCA'][$this->table]['ctrl']['sortby'];
}
}
return implode(',', $fieldListArr);
}
/**
* Init function
*
* @param string $name The name
* @param string $table The table name
* @param string $fieldList The field list
* @param array $settings Module settings like checkboxes in the interface
*/
public function init($name, $table, $fieldList = '', array $settings = [])
{
// Analysing the fields in the table.
if (is_array($GLOBALS['TCA'][$table])) {
$this->name = $name;
$this->table = $table;
$this->fieldList = $fieldList ?: $this->makeFieldList();
$this->settings = $settings;
$fieldArr = GeneralUtility::trimExplode(',', $this->fieldList, true);
foreach ($fieldArr as $fieldName) {
$fC = $GLOBALS['TCA'][$this->table]['columns'][$fieldName];
$this->fields[$fieldName] = $fC['config'];
$this->fields[$fieldName]['exclude'] = $fC['exclude'];
if ($this->fields[$fieldName]['type'] === 'user' && !isset($this->fields[$fieldName]['type']['userFunc'])
|| $this->fields[$fieldName]['type'] === 'none'
) {
// Do not list type=none "virtual" fields or query them from db,
// and if type is user without defined userFunc
unset($this->fields[$fieldName]);
continue;
}
if (is_array($fC) && $fC['label']) {
$this->fields[$fieldName]['label'] = rtrim(trim($this->getLanguageService()->sL($fC['label'])), ':');
switch ($this->fields[$fieldName]['type']) {
case 'input':
if (preg_match('/int|year/i', $this->fields[$fieldName]['eval'])) {
$this->fields[$fieldName]['type'] = 'number';
} elseif (preg_match('/time/i', $this->fields[$fieldName]['eval'])) {
$this->fields[$fieldName]['type'] = 'time';
} elseif (preg_match('/date/i', $this->fields[$fieldName]['eval'])) {
$this->fields[$fieldName]['type'] = 'date';
} else {
$this->fields[$fieldName]['type'] = 'text';
}
break;
case 'check':
if (!$this->fields[$fieldName]['items'] || count($this->fields[$fieldName]['items']) <= 1) {
$this->fields[$fieldName]['type'] = 'boolean';
} else {
$this->fields[$fieldName]['type'] = 'binary';
}
break;
case 'radio':
$this->fields[$fieldName]['type'] = 'multiple';
break;
case 'select':
case 'category':
$this->fields[$fieldName]['type'] = 'multiple';
if ($this->fields[$fieldName]['foreign_table']) {
$this->fields[$fieldName]['type'] = 'relation';
}
if ($this->fields[$fieldName]['special']) {
$this->fields[$fieldName]['type'] = 'text';
}
break;
case 'group':
if (($this->fields[$fieldName]['internal_type'] ?? '') !== 'folder') {
$this->fields[$fieldName]['type'] = 'relation';
}
break;
case 'user':
case 'flex':
case 'passthrough':
case 'none':
case 'text':
default:
$this->fields[$fieldName]['type'] = 'text';
}
} else {
$this->fields[$fieldName]['label'] = '[FIELD: ' . $fieldName . ']';
switch ($fieldName) {
case 'pid':
$this->fields[$fieldName]['type'] = 'relation';
$this->fields[$fieldName]['allowed'] = 'pages';
break;
case 'cruser_id':
$this->fields[$fieldName]['type'] = 'relation';
$this->fields[$fieldName]['allowed'] = 'be_users';
break;
case 'tstamp':
case 'crdate':
$this->fields[$fieldName]['type'] = 'time';
break;
case 'deleted':
$this->fields[$fieldName]['type'] = 'boolean';
break;
default:
$this->fields[$fieldName]['type'] = 'number';
}
}
}
}
/* // EXAMPLE:
$this->queryConfig = array(
array(
'operator' => 'AND',
'type' => 'FIELD_space_before_class',
),
array(
'operator' => 'AND',
'type' => 'FIELD_records',
'negate' => 1,
'inputValue' => 'foo foo'
),
array(
'type' => 'newlevel',
'nl' => array(
array(
'operator' => 'AND',
'type' => 'FIELD_space_before_class',
'negate' => 1,
'inputValue' => 'foo foo'
),
array(
'operator' => 'AND',
'type' => 'FIELD_records',
'negate' => 1,
'inputValue' => 'foo foo'
)
)
),
array(
'operator' => 'OR',
'type' => 'FIELD_maillist',
)
);
*/
$this->initUserDef();
}
/**
* Set and clean up external lists
*
* @param string $name The name
* @param string $list The list
* @param string $force
*/
public function setAndCleanUpExternalLists($name, $list, $force = '')
{
$fields = array_unique(GeneralUtility::trimExplode(',', $list . ',' . $force, true));
$reList = [];
foreach ($fields as $fieldName) {
if ($this->fields[$fieldName]) {
$reList[] = $fieldName;
}
}
$this->extFieldLists[$name] = implode(',', $reList);
}
/**
* Process data
*
* @param array $qC Query config
*/
public function procesData($qC = [])
{
$this->queryConfig = $qC;
$POST = GeneralUtility::_POST();
// If delete...
if ($POST['qG_del']) {
// Initialize array to work on, save special parameters
$ssArr = $this->getSubscript($POST['qG_del']);
$workArr = &$this->queryConfig;
$ssArrSize = count($ssArr) - 1;
$i = 0;
for (; $i < $ssArrSize; $i++) {
$workArr = &$workArr[$ssArr[$i]];
}
// Delete the entry and move the other entries
unset($workArr[$ssArr[$i]]);
$workArrSize = count($workArr);
for ($j = $ssArr[$i]; $j < $workArrSize; $j++) {
$workArr[$j] = $workArr[$j + 1];
unset($workArr[$j + 1]);
}
}
// If insert...
if ($POST['qG_ins']) {
// Initialize array to work on, save special parameters
$ssArr = $this->getSubscript($POST['qG_ins']);
$workArr = &$this->queryConfig;
$ssArrSize = count($ssArr) - 1;
$i = 0;
for (; $i < $ssArrSize; $i++) {
$workArr = &$workArr[$ssArr[$i]];
}
// Move all entries above position where new entry is to be inserted
$workArrSize = count($workArr);
for ($j = $workArrSize; $j > $ssArr[$i]; $j--) {
$workArr[$j] = $workArr[$j - 1];
}
// Clear new entry position
unset($workArr[$ssArr[$i] + 1]);
$workArr[$ssArr[$i] + 1]['type'] = 'FIELD_';
}
// If move up...
if ($POST['qG_up']) {
// Initialize array to work on
$ssArr = $this->getSubscript($POST['qG_up']);
$workArr = &$this->queryConfig;
$ssArrSize = count($ssArr) - 1;
$i = 0;
for (; $i < $ssArrSize; $i++) {
$workArr = &$workArr[$ssArr[$i]];
}
// Swap entries
$qG_tmp = $workArr[$ssArr[$i]];
$workArr[$ssArr[$i]] = $workArr[$ssArr[$i] - 1];
$workArr[$ssArr[$i] - 1] = $qG_tmp;
}
// If new level...
if ($POST['qG_nl']) {
// Initialize array to work on
$ssArr = $this->getSubscript($POST['qG_nl']);
$workArr = &$this->queryConfig;
$ssArraySize = count($ssArr) - 1;
$i = 0;
for (; $i < $ssArraySize; $i++) {
$workArr = &$workArr[$ssArr[$i]];
}
// Do stuff:
$tempEl = $workArr[$ssArr[$i]];
if (is_array($tempEl)) {
if ($tempEl['type'] !== 'newlevel') {
$workArr[$ssArr[$i]] = [
'type' => 'newlevel',
'operator' => $tempEl['operator'],
'nl' => [$tempEl],
];
}
}
}
// If collapse level...
if ($POST['qG_remnl']) {
// Initialize array to work on
$ssArr = $this->getSubscript($POST['qG_remnl']);
$workArr = &$this->queryConfig;
$ssArrSize = count($ssArr) - 1;
$i = 0;
for (; $i < $ssArrSize; $i++) {
$workArr = &$workArr[$ssArr[$i]];
}
// Do stuff:
$tempEl = $workArr[$ssArr[$i]];
if (is_array($tempEl)) {
if ($tempEl['type'] === 'newlevel') {
$a1 = array_slice($workArr, 0, $ssArr[$i]);
$a2 = array_slice($workArr, $ssArr[$i]);
array_shift($a2);
$a3 = $tempEl['nl'];
$a3[0]['operator'] = $tempEl['operator'];
$workArr = array_merge($a1, $a3, $a2);
}
}
}
}
/**
* Clean up query config
*
* @param array $queryConfig Query config
* @return array
*/
public function cleanUpQueryConfig($queryConfig)
{
// Since we don't traverse the array using numeric keys in the upcoming while-loop make sure it's fresh and clean before displaying
if (is_array($queryConfig)) {
ksort($queryConfig);
} else {
// queryConfig should never be empty!
if (!isset($queryConfig[0]) || empty($queryConfig[0]['type'])) {
// Make sure queryConfig is an array
$queryConfig = [];
$queryConfig[0] = ['type' => 'FIELD_'];
}
}
// Traverse:
foreach ($queryConfig as $key => $conf) {
$fieldName = '';
if (strpos($conf['type'], 'FIELD_') === 0) {
$fieldName = substr($conf['type'], 6);
$fieldType = $this->fields[$fieldName]['type'];
} elseif ($conf['type'] === 'newlevel') {
$fieldType = $conf['type'];
} else {
$fieldType = 'ignore';
}
switch ($fieldType) {
case 'newlevel':
if (!$queryConfig[$key]['nl']) {
$queryConfig[$key]['nl'][0]['type'] = 'FIELD_';
}
$queryConfig[$key]['nl'] = $this->cleanUpQueryConfig($queryConfig[$key]['nl']);
break;
case 'userdef':
$queryConfig[$key] = $this->userDefCleanUp($queryConfig[$key]);
break;
case 'ignore':