‪TYPO3CMS  ‪main
SysTemplateRepository.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
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 
19 
20 use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
21 use Psr\EventDispatcher\EventDispatcherInterface;
22 use Psr\Http\Message\ServerRequestInterface;
30 
39 {
40  public function ‪__construct(
41  private readonly EventDispatcherInterface $eventDispatcher,
42  private readonly ‪ConnectionPool $connectionPool,
43  private readonly ‪Context $context,
44  ) {}
45 
61  public function ‪getSysTemplateRowsByRootline(array $rootline, ?ServerRequestInterface $request = null): array
62  {
63  // Site-root node first!
64  $rootLinePageIds = array_reverse(array_column($rootline, 'uid'));
65  $sysTemplateRows = [];
66  $queryBuilder = $this->connectionPool->getQueryBuilderForTable('sys_template');
67  $queryBuilder->setRestrictions($this->‪getSysTemplateQueryRestrictionContainer());
68  $queryBuilder->select('sys_template.*')->from('sys_template');
69  // Build a value list as joined table to have sorting based on list sorting
70  $valueList = [];
71  // @todo: Use type/int cast from expression builder to handle this dbms aware
72  // when support for this has been extracted from CTE PoC patch (sbuerk).
73  $isPostgres = $queryBuilder->getConnection()->getDatabasePlatform() instanceof PostgreSQLPlatform;
74  $pattern = $isPostgres ? '%s::int as uid, %s::int as sorting' : '%s as uid, %s as sorting';
75  foreach ($rootLinePageIds as $sorting => $rootLinePageId) {
76  $valueList[] = sprintf(
77  $pattern,
78  $queryBuilder->createNamedParameter($rootLinePageId, ‪Connection::PARAM_INT),
79  $queryBuilder->createNamedParameter($sorting, ‪Connection::PARAM_INT)
80  );
81  }
82  $valueList = 'SELECT ' . implode(' UNION ALL SELECT ', $valueList);
83  $queryBuilder->getConcreteQueryBuilder()->innerJoin(
84  $queryBuilder->quoteIdentifier('sys_template'),
85  sprintf('(%s)', $valueList),
86  $queryBuilder->quoteIdentifier('pidlist'),
87  '(' . $queryBuilder->expr()->eq(
88  'sys_template.pid',
89  $queryBuilder->quoteIdentifier('pidlist.uid')
90  ) . ')'
91  );
92  // Sort by rootline determined depth as sort criteria
93  $queryBuilder->orderBy('pidlist.sorting', 'ASC')
94  ->addOrderBy('sys_template.root', 'DESC')
95  ->addOrderBy('sys_template.sorting', 'ASC');
96  $lastPid = null;
97  $queryResult = $queryBuilder->executeQuery();
98  while ($sysTemplateRow = $queryResult->fetchAssociative()) {
99  // We're retrieving *all* templates per pid, but need the first one only. The
100  // order restriction above at least takes care they're after-each-other per pid.
101  if ($lastPid === (int)$sysTemplateRow['pid']) {
102  continue;
103  }
104  $lastPid = (int)$sysTemplateRow['pid'];
105  $sysTemplateRows[] = $sysTemplateRow;
106  }
107  $event = new ‪AfterTemplatesHaveBeenDeterminedEvent($rootline, $request, $sysTemplateRows);
108  $this->eventDispatcher->dispatch($event);
109  return $event->getTemplateRows();
110  }
111 
124  public function ‪getSysTemplateRowsByRootlineWithUidOverride(array $rootline, ?ServerRequestInterface $request, int $templateUidOnDeepestRootline): array
125  {
126  // Site-root node first!
127  $rootLinePageIds = array_reverse(array_column($rootline, 'uid'));
128  $templatePidOnDeepestRootline = $rootline[array_key_first($rootline)]['uid'];
129  $sysTemplateRows = [];
130  $queryBuilder = $this->connectionPool->getQueryBuilderForTable('sys_template');
131  $queryBuilder->setRestrictions($this->‪getSysTemplateQueryRestrictionContainer());
132  $queryBuilder->select('sys_template.*')->from('sys_template');
133  if ($templateUidOnDeepestRootline && $templatePidOnDeepestRootline) {
134  $queryBuilder->andWhere(
135  $queryBuilder->expr()->or(
136  $queryBuilder->expr()->neq('sys_template.pid', $queryBuilder->createNamedParameter($templatePidOnDeepestRootline, ‪Connection::PARAM_INT)),
137  $queryBuilder->expr()->and(
138  $queryBuilder->expr()->eq('sys_template.pid', $queryBuilder->createNamedParameter($templatePidOnDeepestRootline, ‪Connection::PARAM_INT)),
139  $queryBuilder->expr()->eq('sys_template.uid', $queryBuilder->createNamedParameter($templateUidOnDeepestRootline, ‪Connection::PARAM_INT)),
140  ),
141  ),
142  );
143  }
144  // Build a value list as joined table to have sorting based on list sorting
145  $valueList = [];
146  // @todo: Use type/int cast from expression builder to handle this dbms aware
147  // when support for this has been extracted from CTE PoC patch (sbuerk).
148  $isPostgres = $queryBuilder->getConnection()->getDatabasePlatform() instanceof PostgreSQLPlatform;
149  $pattern = $isPostgres ? '%s::int as uid, %s::int as sorting' : '%s as uid, %s as sorting';
150  foreach ($rootLinePageIds as $sorting => $rootLinePageId) {
151  $valueList[] = sprintf(
152  $pattern,
153  $queryBuilder->createNamedParameter($rootLinePageId, ‪Connection::PARAM_INT),
154  $queryBuilder->createNamedParameter($sorting, ‪Connection::PARAM_INT)
155  );
156  }
157  $valueList = 'SELECT ' . implode(' UNION ALL SELECT ', $valueList);
158  $queryBuilder->getConcreteQueryBuilder()->innerJoin(
159  $queryBuilder->quoteIdentifier('sys_template'),
160  sprintf('(%s)', $valueList),
161  $queryBuilder->quoteIdentifier('pidlist'),
162  '(' . $queryBuilder->expr()->eq(
163  'sys_template.pid',
164  $queryBuilder->quoteIdentifier('pidlist.uid')
165  ) . ')'
166  );
167  // Sort by rootline determined depth as sort criteria
168  $queryBuilder->orderBy('pidlist.sorting', 'ASC')
169  ->addOrderBy('sys_template.root', 'DESC')
170  ->addOrderBy('sys_template.sorting', 'ASC');
171  $lastPid = null;
172  $queryResult = $queryBuilder->executeQuery();
173  while ($sysTemplateRow = $queryResult->fetchAssociative()) {
174  // We're retrieving *all* templates per pid, but need the first one only. The
175  // order restriction above at least takes care they're after-each-other per pid.
176  if ($lastPid === (int)$sysTemplateRow['pid']) {
177  continue;
178  }
179  $lastPid = (int)$sysTemplateRow['pid'];
180  $sysTemplateRows[] = $sysTemplateRow;
181  }
182  // @todo: This event should be able to be fired even if the sys_template resolving is
183  // merged into an early middleware like "SiteResolver" which could join / sub-select
184  // pages together with sys_template directly, which would be possible if we manage
185  // to switch away from RootlineUtility usage in SiteResolver by using a CTE instead.
186  $event = new ‪AfterTemplatesHaveBeenDeterminedEvent($rootline, $request, $sysTemplateRows);
187  $this->eventDispatcher->dispatch($event);
188  return $event->getTemplateRows();
189  }
190 
196  {
197  $restrictionContainer = GeneralUtility::makeInstance(DefaultRestrictionContainer::class);
198  if ($this->context->getPropertyFromAspect('visibility', 'includeHiddenContent', false)) {
199  $restrictionContainer->removeByType(HiddenRestriction::class);
200  }
201  return $restrictionContainer;
202  }
203 }
‪TYPO3\CMS\Core\TypoScript\IncludeTree\SysTemplateRepository
Definition: SysTemplateRepository.php:39
‪TYPO3\CMS\Core\Database\Query\Restriction\HiddenRestriction
Definition: HiddenRestriction.php:27
‪TYPO3\CMS\Core\Database\Connection\PARAM_INT
‪const PARAM_INT
Definition: Connection.php:52
‪TYPO3\CMS\Core\TypoScript\IncludeTree\SysTemplateRepository\getSysTemplateQueryRestrictionContainer
‪getSysTemplateQueryRestrictionContainer()
Definition: SysTemplateRepository.php:195
‪TYPO3\CMS\Core\TypoScript\IncludeTree
‪TYPO3\CMS\Core\TypoScript\IncludeTree\SysTemplateRepository\getSysTemplateRowsByRootline
‪getSysTemplateRowsByRootline(array $rootline, ?ServerRequestInterface $request=null)
Definition: SysTemplateRepository.php:61
‪TYPO3\CMS\Core\TypoScript\IncludeTree\SysTemplateRepository\__construct
‪__construct(private readonly EventDispatcherInterface $eventDispatcher, private readonly ConnectionPool $connectionPool, private readonly Context $context,)
Definition: SysTemplateRepository.php:40
‪TYPO3\CMS\Core\Context\Context
Definition: Context.php:54
‪TYPO3\CMS\Core\TypoScript\IncludeTree\Event\AfterTemplatesHaveBeenDeterminedEvent
Definition: AfterTemplatesHaveBeenDeterminedEvent.php:29
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:41
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Core\TypoScript\IncludeTree\SysTemplateRepository\getSysTemplateRowsByRootlineWithUidOverride
‪getSysTemplateRowsByRootlineWithUidOverride(array $rootline, ?ServerRequestInterface $request, int $templateUidOnDeepestRootline)
Definition: SysTemplateRepository.php:124
‪TYPO3\CMS\Core\Database\Query\Restriction\DefaultRestrictionContainer
Definition: DefaultRestrictionContainer.php:24