Commit 37ac299f authored by Christian Kuhn's avatar Christian Kuhn
Browse files

[TASK] Simplify Templating Bootstrap in BE Controllers

This patch introduces a new EXT:fluid view class
"BackendTemplateView" to be used as main view for
backend-related non-Extbase views.

This class is the base of a new non-Extbase and
non-request dependent backend view. The class is for
now marked @internal and experimental since we'll
probably add a factory to configure backend template
overrides for any backend view later-on.

A few ViewHelpers are changed to work without
accessing the request if enough VH arguments are provided.

This is the first patch in a series of patches that will
switch from StandaloneView usages in backend
controllers to this new BackendTemplateView.

Basic strategy:
* $view->getRequest()->setControllerExtensionName('SysNote')
  is removed. This is Extbase-specific and not needed nor
  wanted for common non-Extbase controllers.
* Instantiate the View (for now with makeInstance, will be
  replaced with a factory later-on)
* Set the needed paths via ->setTemplateRootPaths() etc.
  For these, we *always* use the main extension's entry
  templating paths, for instance
  'EXT:sys_note/Resources/Private/Templates' or
  'EXT:sys_note/Resources/Private/Partials'.
  We do *not* use sub directories here to clear up path
  logic.
* ->assign() / ->assignMultiple() whatever is needed.
* ->render('SubDirectory/TemplateName') the actual
  action / template, no '.html' suffix.

As a demo, EXT:sys_note is adapted accordingly which hands
over arguments to the above mentioned VH's in a way so
these don't access the request object anymore. The sys_note
code gets a couple of additional changes so the hooks can
prepare request dependent arguments and set them as
template variables (here: returnUrl).

This patch triggers a hidden gem: Since ViewHelpers no
longer receive an Extbase request, they also don't trigger
Extbase magic anymore. The casual victim here is
f:translate, which has already been prepared to not trigger
Extbase's frontend TypoScript parsing if there is no
Extbase request. This often improves backend view performance
by 25% or more, depending on the amount of frontend
TypoScript to parse.

Further patches will adapt other core backend routes and will
relate to this patch for reference.

Change-Id: I4fec3ad690452a00e731c9f6928273048397dd89
Resolves: #96513
Related: #96473
Releases: main
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/72966


Reviewed-by: Benni Mack's avatarBenni Mack <benni@typo3.org>
Reviewed-by: Oliver Bartsch's avatarOliver Bartsch <bo@cedev.de>
Reviewed-by: Christian Kuhn's avatarChristian Kuhn <lolli@schwarzbu.ch>
Tested-by: core-ci's avatarcore-ci <typo3@b13.com>
Tested-by: Benni Mack's avatarBenni Mack <benni@typo3.org>
Tested-by: Oliver Bartsch's avatarOliver Bartsch <bo@cedev.de>
Tested-by: Christian Kuhn's avatarChristian Kuhn <lolli@schwarzbu.ch>
parent 3c76b9e0
...@@ -614,7 +614,7 @@ class PageLayoutController ...@@ -614,7 +614,7 @@ class PageLayoutController
// Page title // Page title
$content .= '<h1 class="' . ($this->isPageEditable($this->current_sys_language) ? 't3js-title-inlineedit' : '') . '">' . htmlspecialchars($this->getLocalizedPageTitle()) . '</h1>'; $content .= '<h1 class="' . ($this->isPageEditable($this->current_sys_language) ? 't3js-title-inlineedit' : '') . '">' . htmlspecialchars($this->getLocalizedPageTitle()) . '</h1>';
// All other listings // All other listings
$content .= $this->renderContent(); $content .= $this->renderContent($request);
$content .= '</form>'; $content .= '</form>';
// Setting up the buttons for the docheader // Setting up the buttons for the docheader
$this->makeButtons($request); $this->makeButtons($request);
...@@ -664,7 +664,7 @@ class PageLayoutController ...@@ -664,7 +664,7 @@ class PageLayoutController
* *
* @return string * @return string
*/ */
protected function renderContent(): string protected function renderContent(ServerRequestInterface $request): string
{ {
$this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ContextMenu'); $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ContextMenu');
$this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Tooltip'); $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Tooltip');
...@@ -727,14 +727,14 @@ class PageLayoutController ...@@ -727,14 +727,14 @@ class PageLayoutController
$content = ''; $content = '';
// Additional header content // Additional header content
foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/db_layout.php']['drawHeaderHook'] ?? [] as $hook) { foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/db_layout.php']['drawHeaderHook'] ?? [] as $hook) {
$params = []; $params = ['request' => $request];
$content .= GeneralUtility::callUserFunction($hook, $params, $this); $content .= GeneralUtility::callUserFunction($hook, $params, $this);
} }
$content .= $tableOutput; $content .= $tableOutput;
// Additional footer content // Additional footer content
foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/db_layout.php']['drawFooterHook'] ?? [] as $hook) { foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/db_layout.php']['drawFooterHook'] ?? [] as $hook) {
$params = []; $params = ['request' => $request];
$content .= GeneralUtility::callUserFunction($hook, $params, $this); $content .= GeneralUtility::callUserFunction($hook, $params, $this);
} }
return $content; return $content;
......
...@@ -17,6 +17,7 @@ declare(strict_types=1); ...@@ -17,6 +17,7 @@ declare(strict_types=1);
namespace TYPO3\CMS\Backend\ViewHelpers\Link; namespace TYPO3\CMS\Backend\ViewHelpers\Link;
use Psr\Http\Message\ServerRequestInterface;
use TYPO3\CMS\Backend\Routing\Exception\RouteNotFoundException; use TYPO3\CMS\Backend\Routing\Exception\RouteNotFoundException;
use TYPO3\CMS\Backend\Routing\UriBuilder; use TYPO3\CMS\Backend\Routing\UriBuilder;
use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Utility\GeneralUtility;
...@@ -84,8 +85,12 @@ final class EditRecordViewHelper extends AbstractTagBasedViewHelper ...@@ -84,8 +85,12 @@ final class EditRecordViewHelper extends AbstractTagBasedViewHelper
if ($this->arguments['uid'] < 1) { if ($this->arguments['uid'] < 1) {
throw new \InvalidArgumentException('Uid must be a positive integer, ' . $this->arguments['uid'] . ' given.', 1526127158); throw new \InvalidArgumentException('Uid must be a positive integer, ' . $this->arguments['uid'] . ' given.', 1526127158);
} }
if (empty($this->arguments['returnUrl'])) { $request = $this->renderingContext->getRequest();
$this->arguments['returnUrl'] = $this->renderingContext->getRequest()->getAttribute('normalizedParams')->getRequestUri(); if (empty($this->arguments['returnUrl'])
&& $request instanceof ServerRequestInterface
) {
// @todo: We may want to deprecate fetching returnUrl from request
$this->arguments['returnUrl'] = $request->getAttribute('normalizedParams')->getRequestUri();
} }
$params = [ $params = [
......
...@@ -17,6 +17,7 @@ declare(strict_types=1); ...@@ -17,6 +17,7 @@ declare(strict_types=1);
namespace TYPO3\CMS\Backend\ViewHelpers; namespace TYPO3\CMS\Backend\ViewHelpers;
use Psr\Http\Message\ServerRequestInterface;
use TYPO3\CMS\Backend\Routing\UriBuilder; use TYPO3\CMS\Backend\Routing\UriBuilder;
use TYPO3\CMS\Core\Utility\ArrayUtility; use TYPO3\CMS\Core\Utility\ArrayUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Utility\GeneralUtility;
...@@ -64,8 +65,14 @@ final class ModuleLinkViewHelper extends AbstractViewHelper ...@@ -64,8 +65,14 @@ final class ModuleLinkViewHelper extends AbstractViewHelper
if ($arguments['query'] !== null) { if ($arguments['query'] !== null) {
ArrayUtility::mergeRecursiveWithOverrule($parameters, GeneralUtility::explodeUrl2Array($arguments['query'])); ArrayUtility::mergeRecursiveWithOverrule($parameters, GeneralUtility::explodeUrl2Array($arguments['query']));
} }
if ($arguments['currentUrlParameterName'] !== null) { $request = $renderingContext->getRequest();
$parameters[$arguments['currentUrlParameterName']] = $renderingContext->getRequest()->getAttribute('normalizedParams')->getRequestUri(); if (!empty($arguments['currentUrlParameterName'])
&& empty($arguments['arguments'][$arguments['currentUrlParameterName']])
&& $request instanceof ServerRequestInterface
) {
// If currentUrlParameterName is given and if that argument is not hand over yet, and if there is a request, fetch it from request
// @todo: We may want to deprecate fetching stuff from request and advise handing over a proper value as 'arguments' argument.
$parameters[$arguments['currentUrlParameterName']] = $request->getAttribute('normalizedParams')->getRequestUri();
} }
return (string)$uriBuilder->buildUriFromRoute($arguments['route'], $parameters); return (string)$uriBuilder->buildUriFromRoute($arguments['route'], $parameters);
} }
......
<?php
declare(strict_types=1);
/*
* 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\Fluid\View;
/**
* A view dedicated for backend non-extbase usage.
*
* @internal Do not use in extensions at the moment.
* This view will most likely receive a configuration system and a factory in further v12 progress.
*/
class BackendTemplateView extends AbstractTemplateView
{
}
...@@ -39,7 +39,7 @@ use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic; ...@@ -39,7 +39,7 @@ use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
* includeCssFiles="{0: 'EXT:my_ext/Resources/Public/Css/Stylesheet.css'}" * includeCssFiles="{0: 'EXT:my_ext/Resources/Public/Css/Stylesheet.css'}"
* includeJsFiles="{0: 'EXT:my_ext/Resources/Public/JavaScript/Library1.js', 1: 'EXT:my_ext/Resources/Public/JavaScript/Library2.js'}" * includeJsFiles="{0: 'EXT:my_ext/Resources/Public/JavaScript/Library1.js', 1: 'EXT:my_ext/Resources/Public/JavaScript/Library2.js'}"
* addJsInlineLabels="{'my_ext.label1': 'LLL:EXT:my_ext/Resources/Private/Language/locallang.xlf:label1'}" * addJsInlineLabels="{'my_ext.label1': 'LLL:EXT:my_ext/Resources/Private/Language/locallang.xlf:label1'}"
* includesRequireJsModules="{0: 'EXT:my_ext/Resources/Public/JavaScript/RequireJsModule.js'}" * includeRequireJsModules="{0: 'EXT:my_ext/Resources/Public/JavaScript/RequireJsModule.js'}"
* addInlineSettings="{'some.setting.key': 'some.setting.value'}" * addInlineSettings="{'some.setting.key': 'some.setting.value'}"
* /> * />
* *
......
...@@ -17,6 +17,7 @@ declare(strict_types=1); ...@@ -17,6 +17,7 @@ declare(strict_types=1);
namespace TYPO3\CMS\Fluid\ViewHelpers\Link; namespace TYPO3\CMS\Fluid\ViewHelpers\Link;
use Psr\Http\Message\ServerRequestInterface;
use TYPO3\CMS\Core\Http\ApplicationType; use TYPO3\CMS\Core\Http\ApplicationType;
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController; use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper; use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper;
...@@ -81,7 +82,11 @@ final class EmailViewHelper extends AbstractTagBasedViewHelper ...@@ -81,7 +82,11 @@ final class EmailViewHelper extends AbstractTagBasedViewHelper
$attributes = []; $attributes = [];
$linkText = htmlspecialchars($email); $linkText = htmlspecialchars($email);
$escapeSpecialCharacters = true; $escapeSpecialCharacters = true;
if (ApplicationType::fromRequest($this->renderingContext->getRequest())->isFrontend()) { $request = $this->renderingContext->getRequest();
if ($request instanceof ServerRequestInterface
&& ApplicationType::fromRequest($this->renderingContext->getRequest())->isFrontend()
) {
// If there is no request, backend is assumed.
/** @var TypoScriptFrontendController $frontend */ /** @var TypoScriptFrontendController $frontend */
$frontend = $GLOBALS['TSFE']; $frontend = $GLOBALS['TSFE'];
$frontend->cObj->typoLink($email, ['parameter' => $linkHref]); $frontend->cObj->typoLink($email, ['parameter' => $linkHref]);
......
...@@ -17,9 +17,7 @@ declare(strict_types=1); ...@@ -17,9 +17,7 @@ declare(strict_types=1);
namespace TYPO3\CMS\Fluid\Tests\Functional\ViewHelpers\Link; namespace TYPO3\CMS\Fluid\Tests\Functional\ViewHelpers\Link;
use TYPO3\CMS\Core\Core\SystemEnvironmentBuilder;
use TYPO3\CMS\Core\Database\ConnectionPool; use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Http\ServerRequest;
use TYPO3\CMS\Core\Tests\Functional\SiteHandling\SiteBasedTestTrait; use TYPO3\CMS\Core\Tests\Functional\SiteHandling\SiteBasedTestTrait;
use TYPO3\CMS\Fluid\View\StandaloneView; use TYPO3\CMS\Fluid\View\StandaloneView;
use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\InternalRequest; use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\InternalRequest;
...@@ -34,9 +32,8 @@ class EmailViewHelperTest extends FunctionalTestCase ...@@ -34,9 +32,8 @@ class EmailViewHelperTest extends FunctionalTestCase
*/ */
public function renderCreatesProperMarkupInBackend(): void public function renderCreatesProperMarkupInBackend(): void
{ {
$GLOBALS['TYPO3_REQUEST'] = (new ServerRequest())
->withAttribute('applicationType', SystemEnvironmentBuilder::REQUESTTYPE_BE);
$view = new StandaloneView(); $view = new StandaloneView();
$view->setRequest();
$view->setTemplateSource('<f:link.email email="foo@example.com">send mail</f:link.email>'); $view->setTemplateSource('<f:link.email email="foo@example.com">send mail</f:link.email>');
self::assertEquals('<a href="mailto:foo@example.com">send mail</a>', $view->render()); self::assertEquals('<a href="mailto:foo@example.com">send mail</a>', $view->render());
} }
...@@ -46,9 +43,8 @@ class EmailViewHelperTest extends FunctionalTestCase ...@@ -46,9 +43,8 @@ class EmailViewHelperTest extends FunctionalTestCase
*/ */
public function renderCreatesProperMarkupInBackendWithEmptyChild(): void public function renderCreatesProperMarkupInBackendWithEmptyChild(): void
{ {
$GLOBALS['TYPO3_REQUEST'] = (new ServerRequest())
->withAttribute('applicationType', SystemEnvironmentBuilder::REQUESTTYPE_BE);
$view = new StandaloneView(); $view = new StandaloneView();
$view->setRequest();
$view->setTemplateSource('<f:link.email email="foo@example.com" />'); $view->setTemplateSource('<f:link.email email="foo@example.com" />');
self::assertEquals('<a href="mailto:foo@example.com">foo@example.com</a>', $view->render()); self::assertEquals('<a href="mailto:foo@example.com">foo@example.com</a>', $view->render());
} }
......
...@@ -21,7 +21,7 @@ use TYPO3\CMS\Backend\Utility\BackendUtility; ...@@ -21,7 +21,7 @@ use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication; use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
use TYPO3\CMS\Core\Type\Bitmask\Permission; use TYPO3\CMS\Core\Type\Bitmask\Permission;
use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Fluid\View\StandaloneView; use TYPO3\CMS\Fluid\View\BackendTemplateView;
use TYPO3\CMS\SysNote\Domain\Repository\SysNoteRepository; use TYPO3\CMS\SysNote\Domain\Repository\SysNoteRepository;
/** /**
...@@ -31,11 +31,7 @@ use TYPO3\CMS\SysNote\Domain\Repository\SysNoteRepository; ...@@ -31,11 +31,7 @@ use TYPO3\CMS\SysNote\Domain\Repository\SysNoteRepository;
*/ */
class NoteController class NoteController
{ {
/** protected SysNoteRepository $notesRepository;
* @var SysNoteRepository
*/
protected $notesRepository;
protected array $pagePermissionCache = []; protected array $pagePermissionCache = [];
public function __construct() public function __construct()
...@@ -44,34 +40,34 @@ class NoteController ...@@ -44,34 +40,34 @@ class NoteController
} }
/** /**
* Render notes by single PID or PID list * Render notes by single PID
* *
* @param string $pids Single PID or comma separated list of PIDs * @param int $pid The page id notes should be rendered for
* @param int|null $position null for no restriction, integer for defined position * @param int|null $position null for no restriction, integer for defined position
* @param string $returnUrl Url to return to when editing and closing a notes record again
* @return string * @return string
*/ */
public function listAction($pids, int $position = null): string public function listAction(int $pid, int $position = null, string $returnUrl = ''): string
{ {
$backendUser = $this->getBackendUser(); $backendUser = $this->getBackendUser();
if (empty($pids) if ($pid <= 0
|| empty($backendUser->user[$backendUser->userid_column]) || empty($backendUser->user[$backendUser->userid_column])
|| !$backendUser->check('tables_select', 'sys_note') || !$backendUser->check('tables_select', 'sys_note')
) { ) {
return ''; return '';
} }
$notes = $this->notesRepository->findByPidsAndAuthorId($pids, (int)$backendUser->user[$backendUser->userid_column], $position); $notes = $this->notesRepository->findByPidsAndAuthorId($pid, (int)$backendUser->user[$backendUser->userid_column], $position);
if (!$notes) { if (!$notes) {
return ''; return '';
} }
$view = GeneralUtility::makeInstance(StandaloneView::class); $view = GeneralUtility::makeInstance(BackendTemplateView::class);
$view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName( $view->setTemplateRootPaths(['EXT:sys_note/Resources/Private/Templates']);
'EXT:sys_note/Resources/Private/Templates/Note/List.html' $view->assignMultiple([
)); 'notes' => $this->enrichWithEditPermissions($notes),
$view->setLayoutRootPaths(['EXT:sys_note/Resources/Private/Layouts']); 'returnUrl' => $returnUrl,
$view->getRequest()->setControllerExtensionName('SysNote'); ]);
$view->assign('notes', $this->enrichWithEditPermissions($notes)); return $view->render('List');
return $view->render();
} }
protected function enrichWithEditPermissions(array $notes): array protected function enrichWithEditPermissions(array $notes): array
......
...@@ -17,24 +17,27 @@ declare(strict_types=1); ...@@ -17,24 +17,27 @@ declare(strict_types=1);
namespace TYPO3\CMS\SysNote\Hook; namespace TYPO3\CMS\SysNote\Hook;
use Psr\Http\Message\ServerRequestInterface;
use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\SysNote\Controller\NoteController; use TYPO3\CMS\SysNote\Controller\NoteController;
/** /**
* Hook for the info module * Hook for the info module.
*
* @internal This is a specific hook implementation and is not considered part of the Public TYPO3 API. * @internal This is a specific hook implementation and is not considered part of the Public TYPO3 API.
*/ */
class InfoModuleHook class InfoModuleHook
{ {
/** /**
* Add sys_notes as additional content to the footer of the info module * Add sys_notes as additional content to the footer of the info module
*
* @return string
*/ */
public function render() public function render(array $params): string
{ {
/** @var ServerRequestInterface $request */
$request = $params['request'];
$controller = GeneralUtility::makeInstance(NoteController::class); $controller = GeneralUtility::makeInstance(NoteController::class);
$id = (int)GeneralUtility::_GP('id'); $id = (int)($request->getQueryParams()['id'] ?? 0);
return $controller->listAction($id); $returnUrl = $request->getAttribute('normalizedParams')->getRequestUri();
return $controller->listAction($id, null, $returnUrl);
} }
} }
...@@ -17,13 +17,14 @@ declare(strict_types=1); ...@@ -17,13 +17,14 @@ declare(strict_types=1);
namespace TYPO3\CMS\SysNote\Hook; namespace TYPO3\CMS\SysNote\Hook;
use TYPO3\CMS\Backend\Controller\PageLayoutController; use Psr\Http\Message\ServerRequestInterface;
use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\SysNote\Controller\NoteController; use TYPO3\CMS\SysNote\Controller\NoteController;
use TYPO3\CMS\SysNote\Domain\Repository\SysNoteRepository; use TYPO3\CMS\SysNote\Domain\Repository\SysNoteRepository;
/** /**
* Hook for the page module * Hook to render notes in the page module.
*
* @internal This is a specific hook implementation and is not considered part of the Public TYPO3 API. * @internal This is a specific hook implementation and is not considered part of the Public TYPO3 API.
*/ */
class PageHook class PageHook
...@@ -31,27 +32,27 @@ class PageHook ...@@ -31,27 +32,27 @@ class PageHook
/** /**
* Add sys_notes as additional content to the header of the page module * Add sys_notes as additional content to the header of the page module
*
* @param array $params
* @param \TYPO3\CMS\Backend\Controller\PageLayoutController $parentObject
* @return string
*/ */
public function renderInHeader(array $params, PageLayoutController $parentObject) public function renderInHeader(array $params)
{ {
/** @var ServerRequestInterface $request */
$request = $params['request'];
$id = (int)($request->getQueryParams()['id'] ?? 0);
$returnUrl = $request->getAttribute('normalizedParams')->getRequestUri();
$controller = GeneralUtility::makeInstance(NoteController::class); $controller = GeneralUtility::makeInstance(NoteController::class);
return $controller->listAction($parentObject->id, SysNoteRepository::SYS_NOTE_POSITION_TOP); return $controller->listAction($id, SysNoteRepository::SYS_NOTE_POSITION_TOP, $returnUrl);
} }
/** /**
* Add sys_notes as additional content to the footer of the page module * Add sys_notes as additional content to the footer of the page module
*
* @param array $params
* @param \TYPO3\CMS\Backend\Controller\PageLayoutController $parentObject
* @return string
*/ */
public function renderInFooter(array $params, PageLayoutController $parentObject) public function renderInFooter(array $params): string
{ {
/** @var ServerRequestInterface $request */
$request = $params['request'];
$id = (int)($request->getQueryParams()['id'] ?? 0);
$returnUrl = $request->getAttribute('normalizedParams')->getRequestUri();
$controller = GeneralUtility::makeInstance(NoteController::class); $controller = GeneralUtility::makeInstance(NoteController::class);
return $controller->listAction($parentObject->id, SysNoteRepository::SYS_NOTE_POSITION_BOTTOM); return $controller->listAction($id, SysNoteRepository::SYS_NOTE_POSITION_BOTTOM, $returnUrl);
} }
} }
...@@ -22,12 +22,13 @@ use TYPO3\CMS\SysNote\Controller\NoteController; ...@@ -22,12 +22,13 @@ use TYPO3\CMS\SysNote\Controller\NoteController;
use TYPO3\CMS\SysNote\Domain\Repository\SysNoteRepository; use TYPO3\CMS\SysNote\Domain\Repository\SysNoteRepository;
/** /**
* Class RecordListProvider * Render existing notes within list module.
*
* @internal * @internal
*/ */
class RecordListProvider class RecordListProvider
{ {
protected $noteController; protected NoteController $noteController;
public function __construct(NoteController $noteController) public function __construct(NoteController $noteController)
{ {
...@@ -36,8 +37,10 @@ class RecordListProvider ...@@ -36,8 +37,10 @@ class RecordListProvider
public function __invoke(RenderAdditionalContentToRecordListEvent $event): void public function __invoke(RenderAdditionalContentToRecordListEvent $event): void
{ {
$id = (int)($event->getRequest()->getParsedBody()['id'] ?? $event->getRequest()->getQueryParams()['id'] ?? 0); $request = $event->getRequest();
$event->addContentAbove($this->noteController->listAction($id, SysNoteRepository::SYS_NOTE_POSITION_TOP)); $pid = (int)($event->getRequest()->getParsedBody()['id'] ?? $event->getRequest()->getQueryParams()['id'] ?? 0);
$event->addContentBelow($this->noteController->listAction($id, SysNoteRepository::SYS_NOTE_POSITION_BOTTOM)); $returnUrl = $request->getAttribute('normalizedParams')->getRequestUri();
$event->addContentAbove($this->noteController->listAction($pid, SysNoteRepository::SYS_NOTE_POSITION_TOP, $returnUrl));
$event->addContentBelow($this->noteController->listAction($pid, SysNoteRepository::SYS_NOTE_POSITION_BOTTOM, $returnUrl));
} }
} }
<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
xmlns:core="http://typo3.org/ns/TYPO3/CMS/Core/ViewHelpers"
xmlns:be="http://typo3.org/ns/TYPO3/CMS/Backend/ViewHelpers"
>
<f:if condition="{notes}">
<div class="note-list">
<h2><f:translate key="LLL:EXT:sys_note/Resources/Private/Language/locallang.xlf:internal_note" /></h2>
<f:for each="{notes}" as="note">
<div class="note note-category-{note.category}">
<div class="note-header">
<div class="note-header-bar">
<span class="note-icon t3js-contextmenutrigger" data-table="sys_note" data-uid="{note.uid}">
<core:icon identifier="sysnote-type-{note.category}" />
</span>
<span class="note-author">
<f:translate key="LLL:EXT:sys_note/Resources/Private/Language/locallang.xlf:author" />:
<f:if condition="{note.authorDisabled} || {note.authorDeleted} || !{note.authorUsername}">
<f:then>[{f:translate(key: 'LLL:EXT:sys_note/Resources/Private/Language/locallang.xlf:author_deleted')}]</f:then>
<f:else if="{note.authorRealName}">{note.authorRealName}</f:else>
<f:else>{note.authorUsername}</f:else>
</f:if>
</span>
<span class="note-date">
<f:translate key="LLL:EXT:sys_note/Resources/Private/Language/locallang.xlf:date" />:
<f:format.date>@{note.tstamp}</f:format.date>
</span>
<f:if condition="{note.personal}">
<span class="note-badge">
<span class="badge badge-info"><f:translate key="LLL:EXT:sys_note/Resources/Private/Language/locallang.xlf:personal" /></span>
</span>
</f:if>
<span class="note-actions">
<span class="btn-group">
<f:if condition="{note.canBeEdited}">
<be:link.editRecord uid="{note.uid}" table="sys_note" class="btn btn-default btn-sm" returnUrl="{returnUrl}">
<core:icon identifier="actions-open" />
</be:link.editRecord>
</f:if>
<f:if condition="{note.canBeDeleted}">
<a href="{be:moduleLink(route:'tce_db', query:'cmd[sys_note][{note.uid}][delete]=1', arguments:'{redirect: returnUrl}')}"
class="btn btn-default btn-sm t3js-modal-trigger"
data-severity="warning"
data-title="{f:translate(key: 'LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:delete')}"
data-bs-content="{f:translate(key: 'LLL:EXT:backend/Resources/Private/Language/locallang_alt_doc.xlf:deleteWarning')}"
data-button-close-text="{f:translate(key: 'LLL:EXT:core/Resources/Private/Language/locallang_common.xlf:cancel')}"
>
<core:icon identifier="actions-edit-delete" />
</a>
</f:if>
</span>
</span>
</div>
</div>
<div class="note-body">
<h4><span>
<f:if condition="{note.category}">
<f:translate key="LLL:EXT:sys_note/Resources/Private/Language/locallang.xlf:category.{note.category}" />:
</f:if>
</span>{note.subject}</h4>
<f:format.nl2br>{note.message}</f:format.nl2br>
</div>
</div>
</f:for>
</div>
</f:if>
</html>
<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" xmlns:core="http://typo3.org/ns/TYPO3/CMS/Core/ViewHelpers" xmlns:be="http://typo3.org/ns/TYPO3/CMS/Backend/ViewHelpers" xmlns:notes="http://typo3.org/ns/TYPO3/CMS/SysNote/ViewHelpers">
<f:layout name="Default" />
<f:section name="main">
<f:if condition="{notes}">
<div