|
3 | 3 |
|
4 | 4 | namespace Lemming\PageTreeFilter\Domain\Repository; |
5 | 5 |
|
6 | | -use Lemming\PageTreeFilter\Utility\ConfigurationUtility; |
7 | | -use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; |
8 | | -use TYPO3\CMS\Core\Database\ConnectionPool; |
9 | | -use TYPO3\CMS\Core\Database\Query\QueryBuilder; |
10 | | -use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction; |
11 | | -use TYPO3\CMS\Core\Database\Query\Restriction\WorkspaceRestriction; |
12 | | -use TYPO3\CMS\Core\Utility\GeneralUtility; |
| 6 | +use Lemming\PageTreeFilter\Domain\Dto\Result; |
| 7 | +use Lemming\PageTreeFilter\Middleware\PageTreeFilterMiddleware; |
| 8 | +use Psr\Http\Message\ServerRequestInterface; |
13 | 9 |
|
14 | 10 | class PageTreeRepository extends \TYPO3\CMS\Backend\Tree\Repository\PageTreeRepository |
15 | 11 | { |
16 | | - public static array $filteredPageUids = []; |
17 | | - |
18 | | - public static bool $filterErrorneous = false; |
19 | | - |
20 | | - protected ?string $filterTable; |
21 | | - |
22 | | - protected array $filterConstraints = []; |
23 | | - |
24 | | - protected const ALLOWED_TABLE_FIELDS = [ |
25 | | - 'tt_content:CType', |
26 | | - 'tt_content:list_type', |
27 | | - ]; |
28 | | - // allowed fields, regardless of table |
29 | | - protected const ALLOWED_FIELDS = [ |
30 | | - 'uid', |
31 | | - ]; |
32 | | - |
33 | | - public function fetchFilteredTree(string $searchFilter, array $allowedMountPointPageIds, string $additionalWhereClause): array |
34 | | - { |
35 | | - if (ConfigurationUtility::isWizardEnabled()) { |
36 | | - $newSearchFilter = $this->extractConstraints($searchFilter); |
37 | | - if (!empty($this->filterTable)) { |
38 | | - $this->validate(); |
39 | | - |
40 | | - if (!self::$filterErrorneous) { |
41 | | - self::$filteredPageUids = $this->getFilteredPageUids(); |
42 | | - |
43 | | - if (self::$filteredPageUids !== []) { |
44 | | - $additionalWhereClause = sprintf('%s AND uid IN (%s)', $additionalWhereClause, |
45 | | - implode(',', self::$filteredPageUids)); |
46 | | - $searchFilter = $newSearchFilter; |
47 | | - } |
48 | | - } |
49 | | - } |
| 12 | + public function fetchFilteredTree( |
| 13 | + string $searchFilter, |
| 14 | + array $allowedMountPointPageIds, |
| 15 | + string $additionalWhereClause |
| 16 | + ): array { |
| 17 | + $result = $this->getResult(); |
| 18 | + if ($result) { |
| 19 | + $searchFilter = $result->getFilter()->getRemainingSearchQuery(); |
| 20 | + $whereClause = $result->getRecordUids() === [] ? ' AND 1=0' : sprintf(' AND uid IN (%s)', implode(',', $result->getRecordUids())); |
| 21 | + $additionalWhereClause .= $whereClause; |
50 | 22 | } |
51 | 23 |
|
52 | 24 | return parent::fetchFilteredTree($searchFilter, $allowedMountPointPageIds, $additionalWhereClause); |
53 | 25 | } |
54 | 26 |
|
55 | | - protected function getFilteredPageUids(): array |
56 | | - { |
57 | | - $pageUids = []; |
58 | | - |
59 | | - /** @var QueryBuilder $queryBuilder */ |
60 | | - $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->filterTable); |
61 | | - $queryBuilder |
62 | | - ->getRestrictions() |
63 | | - ->removeAll() |
64 | | - ->add(GeneralUtility::makeInstance(DeletedRestriction::class)) |
65 | | - ->add(GeneralUtility::makeInstance(WorkspaceRestriction::class)); |
66 | | - |
67 | | - $field = $this->filterTable === 'pages' ? 'uid' : 'pid'; |
68 | | - $query = $queryBuilder |
69 | | - ->select($field) |
70 | | - ->from($this->filterTable) |
71 | | - ->groupBy($field); |
72 | | - if ($this->filterTable === 'pages') { |
73 | | - $query->addSelect('l10n_parent'); |
74 | | - } |
75 | | - |
76 | | - foreach($this->filterConstraints as $constraint) { |
77 | | - if (strpos($constraint['value'], '*') !== false) { |
78 | | - $like = str_replace('*', '', $constraint['value']); |
79 | | - $parts = explode('*', $constraint['value']); |
80 | | - $leftLike = empty($parts[0]) ? '%' : ''; |
81 | | - $rightLike = empty(array_pop($parts)) ? '%' : ''; |
82 | | - $query->andWhere( |
83 | | - $queryBuilder->expr()->like( |
84 | | - $constraint['field'], |
85 | | - $queryBuilder->createNamedParameter($leftLike . $queryBuilder->escapeLikeWildcards($like) . $rightLike) |
86 | | - ) |
87 | | - ); |
88 | | - } else { |
89 | | - if (empty($constraint['value']) && $this->isNullableColumn($queryBuilder, $constraint['field'])) { |
90 | | - $query->andWhere( |
91 | | - $queryBuilder->expr()->or( |
92 | | - $queryBuilder->expr()->isNull($constraint['field']), |
93 | | - $queryBuilder->expr()->eq($constraint['field'], $queryBuilder->createNamedParameter('')) |
94 | | - ) |
95 | | - ); |
96 | | - } else { |
97 | | - $query->andWhere( |
98 | | - $queryBuilder->expr()->eq($constraint['field'], $queryBuilder->createNamedParameter($constraint['value'])) |
99 | | - ); |
100 | | - } |
101 | | - } |
102 | | - } |
103 | | - |
104 | | - $rows = $query->executeQuery()->fetchAllAssociative(); |
105 | | - foreach ($rows as $row) { |
106 | | - if ($this->filterTable === 'pages' && $row['l10n_parent'] > 0) { |
107 | | - $pageUids[] = $row['l10n_parent']; |
108 | | - } else { |
109 | | - $pageUids[] = $row[$field]; |
110 | | - } |
111 | | - } |
112 | | - foreach ($rows as $row) { |
113 | | - $pageUids[] = $row[$field]; |
114 | | - } |
115 | | - |
116 | | - return $pageUids; |
117 | | - } |
118 | | - |
119 | | - protected function extractConstraints(string $searchFilter): string |
120 | | - { |
121 | | - $remainingSearchFilterParts = []; |
122 | | - foreach(GeneralUtility::trimExplode(' ', $searchFilter, true) as $queryPart) { |
123 | | - $filter = GeneralUtility::trimExplode('=', $queryPart); |
124 | | - if (count($filter) == 2) { |
125 | | - switch ($filter[0]) { |
126 | | - case 'table': |
127 | | - $this->filterTable = $filter[1]; |
128 | | - break; |
129 | | - default: |
130 | | - $this->filterConstraints[] = [ |
131 | | - 'field' => $filter[0], |
132 | | - 'value' => $filter[1] |
133 | | - ]; |
134 | | - } |
135 | | - } else { |
136 | | - $remainingSearchFilterParts[] = $queryPart; |
137 | | - } |
138 | | - } |
139 | | - |
140 | | - return implode(' ', $remainingSearchFilterParts); |
141 | | - } |
142 | | - |
143 | | - protected function validate() |
144 | | - { |
145 | | - $backendUser = $this->getBackendUser(); |
146 | | - if (!isset($GLOBALS['TCA'][$this->filterTable])) { |
147 | | - self::$filterErrorneous = true; |
148 | | - } |
149 | | - if (!$backendUser->isAdmin() && !$backendUser->check('tables_select', $this->filterTable)) { |
150 | | - self::$filterErrorneous = true; |
151 | | - } |
152 | | - /** @var \TYPO3\CMS\Core\Database\Connection $connection */ |
153 | | - $connection = GeneralUtility::makeInstance(ConnectionPool::class) |
154 | | - ->getConnectionForTable($this->filterTable); |
155 | | - foreach($this->filterConstraints as $constraint) { |
156 | | - if (!isset($GLOBALS['TCA'][$this->filterTable]['columns'][$constraint['field']])) { |
157 | | - // only if admin or field in ALLOWED_FIELDS: field can also be used if not in TCA, but exists in table |
158 | | - if (($backendUser->isAdmin() || in_array($constraint['field'], self::ALLOWED_FIELDS)) |
159 | | - && in_array($constraint['field'], array_keys($connection->createSchemaManager()->listTableColumns($this->filterTable))) |
160 | | - ) { |
161 | | - // all good for this constraint, keep going |
162 | | - continue; |
163 | | - } else { |
164 | | - self::$filterErrorneous = true; |
165 | | - // filter error - no need to check further |
166 | | - return; |
167 | | - } |
168 | | - } |
169 | | - $tableField = $this->filterTable . ':' . $constraint['field']; |
170 | | - if ( |
171 | | - !$backendUser->isAdmin() && |
172 | | - !in_array($tableField, self::ALLOWED_TABLE_FIELDS) && |
173 | | - !$backendUser->check('non_exclude_fields', $tableField) |
174 | | - ) { |
175 | | - self::$filterErrorneous = true; |
176 | | - return; |
177 | | - } |
178 | | - } |
179 | | - } |
180 | | - |
181 | | - protected function isNullableColumn(QueryBuilder $queryBuilder, string $column): bool |
| 27 | + protected function getResult(): ?Result |
182 | 28 | { |
183 | | - $schemaManager = $queryBuilder->getConnection()->createSchemaManager(); |
184 | | - return !$schemaManager->introspectTable($this->filterTable)->getColumn($column)->getNotnull(); |
| 29 | + return $this->getServerRequest()->getAttribute(PageTreeFilterMiddleware::ATTRIBUTE); |
185 | 30 | } |
186 | 31 |
|
187 | | - protected function getBackendUser(): BackendUserAuthentication |
| 32 | + protected function getServerRequest(): ServerRequestInterface |
188 | 33 | { |
189 | | - return $GLOBALS['BE_USER']; |
| 34 | + return $GLOBALS['TYPO3_REQUEST']; |
190 | 35 | } |
191 | 36 | } |
0 commit comments