iconFactory = $iconFactory; } public function injectUriBuilder(UriBuilder $uriBuilder) { $this->uriBuilder = $uriBuilder; } public function injectConnectionPool(ConnectionPool $connectionPool) { $this->connectionPool = $connectionPool; } public function injectDataHandler(DataHandler $dataHandler) { $this->dataHandler = $dataHandler; } public function injectSiteFinder(SiteFinder $siteFinder) { $this->siteFinder = $siteFinder; } public function injectTcaSchemaFactory(TcaSchemaFactory $tcaSchemaFactory) { $this->tcaSchemaFactory = $tcaSchemaFactory; } public function injectComponentFactory(ComponentFactory $componentFactory): void { $this->componentFactory = $componentFactory; } /** * Action shared by info/modify ond constant editor to create a new "extension template" */ protected function createExtensionTemplateAction(ServerRequestInterface $request, string $redirectTarget): ResponseInterface { $pageUid = (int)($request->getQueryParams()['id'] ?? 0); if ($pageUid === 0) { throw new \RuntimeException('No proper page uid given', 1661333864); } $recordData['sys_template']['NEW'] = [ 'pid' => $pageUid, 'title' => '+ext', ]; $this->dataHandler->start($recordData, []); $this->dataHandler->process_datamap(); return new RedirectResponse($this->uriBuilder->buildUriFromRoute($redirectTarget, ['id' => $pageUid])); } /** * Action shared by info/modify ond constant editor to create a new "site template" */ protected function createNewWebsiteTemplateAction(ServerRequestInterface $request, string $redirectTarget): ResponseInterface { $languageService = $this->getLanguageService(); $pageUid = (int)($request->getQueryParams()['id'] ?? 0); if ($pageUid === 0) { throw new \RuntimeException('No proper page uid given', 1661333863); } $recordData['sys_template']['NEW'] = [ 'pid' => $pageUid, 'title' => $languageService->sL('LLL:EXT:tstemplate/Resources/Private/Language/locallang.xlf:noRecordFound.createRootTypoScriptRecord.title.placeholder'), 'sorting' => 0, 'root' => 1, 'clear' => 3, 'config' => "\n" . "# Default PAGE object:\n" . "page = PAGE\n" . "page.10 = TEXT\n" . "page.10.value = HELLO WORLD!\n", ]; $this->dataHandler->start($recordData, []); $this->dataHandler->process_datamap(); return new RedirectResponse($this->uriBuilder->buildUriFromRoute($redirectTarget, ['id' => $pageUid])); } protected function addPreviewButtonToDocHeader(ModuleTemplate $view, array $pageRecord): void { $previewUriBuilder = PreviewUriBuilder::create($pageRecord); if ($previewUriBuilder->isPreviewable()) { $view->addButtonToButtonBar($this->componentFactory->createViewButton( $previewUriBuilder ->withRootLine(BackendUtility::BEgetRootLine($pageRecord['uid'])) ->buildDispatcherDataAttributes() ?? [] ), ButtonBar::BUTTON_POSITION_LEFT, 99); } } protected function addShortcutButtonToDocHeader(ModuleTemplate $view, string $moduleIdentifier, array $pageInfo, int $pageUid, string $moduleTitle): void { $shortcutTitle = sprintf( '%s: %s [%d]', $moduleTitle, BackendUtility::getRecordTitle('pages', $pageInfo), $pageUid ); $view->getDocHeaderComponent()->setShortcutContext( $moduleIdentifier, $shortcutTitle, ['id' => $pageUid] ); } /** * Get the closest page row that has a template up in rootline */ protected function getClosestAncestorPageWithTemplateRecord(int $pageId): array { $rootLine = BackendUtility::BEgetRootLine($pageId); foreach ($rootLine as $rootlineNode) { if ($this->getFirstTemplateRecordOnPage((int)$rootlineNode['uid'])) { return $rootlineNode; } } return []; } protected function getScopedRootline(SiteInterface $site, array $fullRootLine): array { if (!$site instanceof Site) { return $fullRootLine; } if (!$site->isTypoScriptRoot()) { return $fullRootLine; } $rootLineUntilSite = []; foreach ($fullRootLine as $index => $rootlinePage) { $rootlinePageId = (int)($rootlinePage['uid'] ?? 0); $rootLineUntilSite[$index] = $rootlinePage; if ($rootlinePageId === $site->getRootPageId()) { break; } } return $rootLineUntilSite; } /** * Get an array of all template records on a page. */ protected function getAllTemplateRecordsOnPage(int $pageId): array { if (!$pageId) { return []; } $templateRecords = []; try { $site = $this->siteFinder->getSiteByRootPageId($pageId); if ($site->isTypoScriptRoot()) { $typoScript = $site->getTypoScript(); $templateRecords[] = [ 'type' => 'site', 'pid' => $pageId, 'constants' => $typoScript->constants ?? '', 'config' => $typoScript->setup ?? '', 'root' => 1, 'clear' => 1, 'sorting' => -1, 'uid' => -1, 'site' => $site, 'title' => $site->getConfiguration()['websiteTitle'] ?? '', ]; } } catch (SiteNotFoundException) { // ignore } $result = $this->getTemplateQueryBuilder($pageId)->executeQuery(); while ($row = $result->fetchAssociative()) { $templateRecords[] = [...$row, 'type' => 'sys_template']; } return $templateRecords; } /** * Get a single sys_template record attached to a single page. * If multiple template records are on this page, the first (order by sorting) * record will be returned, unless a specific template uid is specified via $templateUid * * @param int $pageId The pid to select sys_template records from * @param int $templateUid Optional template uid * @return array|false Returns the template record or false if none was found */ protected function getFirstTemplateRecordOnPage(int $pageId, int $templateUid = 0): array|false { if (empty($pageId)) { return false; } $queryBuilder = $this->getTemplateQueryBuilder($pageId)->setMaxResults(1); if ($templateUid) { $queryBuilder->andWhere( $queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($templateUid, Connection::PARAM_INT)) ); } return $queryBuilder->executeQuery()->fetchAssociative(); } /** * Helper method to prepare the query builder for getting sys_template records from a given pid. */ protected function getTemplateQueryBuilder(int $pid): QueryBuilder { $queryBuilder = $this->connectionPool->getQueryBuilderForTable('sys_template'); $queryBuilder->getRestrictions() ->removeAll() ->add(GeneralUtility::makeInstance(DeletedRestriction::class)); $queryBuilder->select('*') ->from('sys_template') ->where( $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($pid, Connection::PARAM_INT)) ); $schema = $this->tcaSchemaFactory->has('sys_template') ? $this->tcaSchemaFactory->get('sys_template') : null; if ($schema && $schema->hasCapability(TcaSchemaCapability::SortByField)) { $queryBuilder ->orderBy($schema->getCapability(TcaSchemaCapability::SortByField)->getFieldName()); } return $queryBuilder; } /** * Create a VisibilityAspect that simulates frontend-like behavior: * hidden templates and templates outside their scheduled time window * are excluded, as they would be in the frontend. */ protected function createVisibilityAspect(): VisibilityAspect { // For the context of the TypoScript management backend, we want to // edit TypoScript records that are hidden. But in a backend submodule like // the ActiveTypoScriptController / TemplateAnalyzerController, only // non-hidden records with matching time constraints should be evaluated, // just like in the frontend. return new VisibilityAspect( includeHiddenPages: true, includeHiddenContent: false, includeDeletedRecords: false, includeScheduledRecords: false, ); } protected function getLanguageService(): LanguageService { return $GLOBALS['LANG']; } protected function getBackendUser(): BackendUserAuthentication { return $GLOBALS['BE_USER']; } }