Olivier Massot 1 год назад
Родитель
Сommit
9585692b95
27 измененных файлов с 237 добавлено и 179 удалено
  1. 37 37
      composer.json
  2. 5 3
      ot_admin/Classes/Command/AddRedirectionCommand.php
  3. 2 2
      ot_admin/Classes/Command/ClearObsoleteWebsitesSiteCommand.php
  4. 2 2
      ot_admin/Classes/Command/ClearSiteCacheCommand.php
  5. 2 2
      ot_admin/Classes/Command/CreateSiteCommand.php
  6. 2 2
      ot_admin/Classes/Command/DeleteSiteCommand.php
  7. 2 2
      ot_admin/Classes/Command/GetSiteStatusCommand.php
  8. 2 2
      ot_admin/Classes/Command/RegenConfigFilesCommand.php
  9. 2 2
      ot_admin/Classes/Command/RemoveRedirectionCommand.php
  10. 2 2
      ot_admin/Classes/Command/ResetBeUserPermsCommand.php
  11. 2 2
      ot_admin/Classes/Command/ScanCommand.php
  12. 2 2
      ot_admin/Classes/Command/SetSiteDomainCommand.php
  13. 1 1
      ot_admin/Classes/Command/UndeleteSiteCommand.php
  14. 2 2
      ot_admin/Classes/Command/UpdateSiteCommand.php
  15. 0 2
      ot_connect/Classes/Middleware/RequestHandler.php
  16. 9 7
      ot_core/Classes/Website/OtWebsiteRepository.php
  17. 4 8
      ot_core/composer.json
  18. 2 2
      ot_optimizer/Configuration/RequestMiddlewares.php
  19. 0 8
      ot_templating/Classes/Page/ErrorHandler.php
  20. 135 29
      ot_templating/Classes/ViewHelpers/CObjectViewHelper.php
  21. 0 49
      ot_templating/Classes/ViewHelpers/ImagePViewHelper.php
  22. 1 1
      ot_templating/Resources/Private/Partials/Classic/Carousel.html
  23. 2 1
      ot_templating/Resources/Private/Partials/Classic/UserToolbar.html
  24. 1 1
      ot_templating/Resources/Private/Partials/Modern/Carousel.html
  25. 9 3
      ot_templating/Resources/Private/Templates/Page/Error/403.html
  26. 6 4
      ot_templating/Resources/Private/Templates/Page/Error/404.html
  27. 3 1
      ot_templating/Resources/Private/Templates/Page/Error/500.html

+ 37 - 37
composer.json

@@ -1,45 +1,46 @@
 {
     "require": {
-        "typo3/cms-about": "^11.5",
-        "typo3/cms-adminpanel": "^11.5",
-        "typo3/cms-backend": "^11.5",
-        "typo3/cms-belog": "^11.5",
-        "typo3/cms-beuser": "^11.5",
-        "typo3/cms-core": "^11.5",
-        "typo3/cms-extbase": "^11.5",
-        "typo3/cms-extensionmanager": "^11.5",
-        "typo3/cms-felogin": "^11.5",
-        "typo3/cms-filelist": "^11.5",
-        "typo3/cms-filemetadata": "^11.5",
-        "typo3/cms-fluid": "^11.5",
-        "typo3/cms-fluid-styled-content": "^11.5",
-        "typo3/cms-form": "^11.5",
-        "typo3/cms-frontend": "^11.5",
-        "typo3/cms-impexp": "^11.5",
-        "typo3/cms-info": "^11.5",
-        "typo3/cms-install": "^11.5",
-        "typo3/cms-lowlevel": "^11.5",
-        "typo3/cms-recycler": "^11.5",
-        "typo3/cms-redirects": "^11.5",
-        "typo3/cms-reports": "^11.5",
-        "typo3/cms-rte-ckeditor": "^11.5",
-        "typo3/cms-scheduler": "^11.5",
-        "typo3/cms-seo": "^11.5",
-        "typo3/cms-setup": "^11.5",
-        "typo3/cms-t3editor": "^11.5",
-        "typo3/cms-tstemplate": "^11.5",
-        "typo3/cms-viewpage": "^11.5",
-        "typo3/cms-dashboard": "^11.5",
-        "typo3/cms-opendocs": "^11.5",
-        "typo3/cms-recordlist": "^11.5",
-        "helhum/typo3-console": "^7.1",
-        "sgalinski/lfeditor": "^7.1",
+        "typo3/cms-about": "^12.4",
+        "typo3/cms-adminpanel": "^12.4",
+        "typo3/cms-backend": "^12.4",
+        "typo3/cms-belog": "^12.4",
+        "typo3/cms-beuser": "^12.4",
+        "typo3/cms-core": "^12.4",
+        "typo3/cms-extbase": "^12.4",
+        "typo3/cms-extensionmanager": "^12.4",
+        "typo3/cms-felogin": "^12.4",
+        "typo3/cms-filelist": "^12.4",
+        "typo3/cms-filemetadata": "^12.4",
+        "typo3/cms-fluid": "^12.4",
+        "typo3/cms-fluid-styled-content": "^12.4",
+        "typo3/cms-form": "^12.4",
+        "typo3/cms-frontend": "^12.4",
+        "typo3/cms-impexp": "^12.4",
+        "typo3/cms-info": "^12.4",
+        "typo3/cms-install": "^12.4",
+        "typo3/cms-lowlevel": "^12.4",
+        "typo3/cms-recycler": "^12.4",
+        "typo3/cms-redirects": "^12.4",
+        "typo3/cms-reports": "^12.4",
+        "typo3/cms-rte-ckeditor": "^12.4",
+        "typo3/cms-scheduler": "^12.4",
+        "typo3/cms-seo": "^12.4",
+        "typo3/cms-setup": "^12.4",
+        "typo3/cms-tstemplate": "^12.4",
+        "typo3/cms-viewpage": "^12.4",
+        "typo3/cms-dashboard": "^12.4",
+        "typo3/cms-opendocs": "^12.4",
+        "typo3/cms-recordlist": "^12.4",
+        "helhum/typo3-console": "*",
+        "sgalinski/lfeditor": "^8.0",
         "opentalent/ot_core": "^1.0",
         "opentalent/ot_admin": "^1.0",
         "opentalent/ot_templating": "^1.0",
         "opentalent/ot_stats": "^1.0",
         "opentalent/ot_optimizer": "^1.0",
-        "opentalent/ot_connect": "^1.0"
+        "opentalent/ot_connect": "^1.0",
+        "typo3/cms-linkvalidator": "^12.4",
+        "typo3/cms-t3editor": "^12.4"
     },
     "repositories": [
         {
@@ -53,7 +54,7 @@
     ],
     "scripts": {
         "typo3-cms-scripts": [
-            "typo3cms install:fixfolderstructure"
+            "typo3 install:fixfolderstructure"
         ],
         "post-autoload-dump": [
             "@typo3-cms-scripts"
@@ -66,7 +67,6 @@
         }
     },
     "require-dev": {
-        "ssch/typo3-rector": "^1.3",
         "phpspec/prophecy": "^1.19"
     }
 }

+ 5 - 3
ot_admin/Classes/Command/AddRedirectionCommand.php

@@ -3,6 +3,7 @@
 namespace Opentalent\OtAdmin\Command;
 
 
+use Doctrine\DBAL\Driver\Exception;
 use Opentalent\OtAdmin\Controller\SiteController;
 use Symfony\Component\Console\Command\Command;
 use Symfony\Component\Console\Input\InputArgument;
@@ -33,7 +34,7 @@ class AddRedirectionCommand extends Command
      * Allows to add a description, a help text, and / or define arguments.
      *
      */
-    protected function configure()
+    protected function configure(): void
     {
         $this
             ->setName("ot:redirection:add")
@@ -55,9 +56,10 @@ class AddRedirectionCommand extends Command
      *
      * @param InputInterface $input
      * @param OutputInterface $output
-     * @throws \Exception
+     * @return int
+     * @throws Exception
      */
-    protected function execute(InputInterface $input, OutputInterface $output)
+    protected function execute(InputInterface $input, OutputInterface $output): int
     {
         $fromDomain = $input->getArgument('from-domain');
         $toDomain = $input->getArgument('to-domain');

+ 2 - 2
ot_admin/Classes/Command/ClearObsoleteWebsitesSiteCommand.php

@@ -36,7 +36,7 @@ class ClearObsoleteWebsitesSiteCommand extends Command
      * Allows to add a description, a help text, and / or define arguments.
      *
      */
-    protected function configure()
+    protected function configure(): void
     {
         $this
             ->setName("ot:clear-obsoletes-websites")
@@ -66,7 +66,7 @@ class ClearObsoleteWebsitesSiteCommand extends Command
      * @throws \TYPO3\CMS\Extbase\Object\Exception
      * @throws \Throwable
      */
-    protected function execute(InputInterface $input, OutputInterface $output)
+    protected function execute(InputInterface $input, OutputInterface $output): int
     {
         $preview = $input->getOption('preview');
 

+ 2 - 2
ot_admin/Classes/Command/ClearSiteCacheCommand.php

@@ -34,7 +34,7 @@ class ClearSiteCacheCommand extends Command
      * Allows to add a description, a help text, and / or define arguments.
      *
      */
-    protected function configure()
+    protected function configure(): void
     {
         $this
             ->setName("ot:site:clear-cache")
@@ -59,7 +59,7 @@ class ClearSiteCacheCommand extends Command
      * @param OutputInterface $output
      * @throws \Exception
      */
-    protected function execute(InputInterface $input, OutputInterface $output)
+    protected function execute(InputInterface $input, OutputInterface $output): int
     {
         $org_id = $input->getArgument('organization-id');
         $clearAll = $input->getOption('all');

+ 2 - 2
ot_admin/Classes/Command/CreateSiteCommand.php

@@ -34,7 +34,7 @@ class CreateSiteCommand extends Command
      * Allows to add a description, a help text, and / or define arguments.
      *
      */
-    protected function configure()
+    protected function configure(): void
     {
         $this
             ->setName("ot:site:create")
@@ -63,7 +63,7 @@ class CreateSiteCommand extends Command
      * @return int
      * @throws \Exception
      */
-    protected function execute(InputInterface $input, OutputInterface $output)
+    protected function execute(InputInterface $input, OutputInterface $output): int
     {
         $org_id = $input->getArgument('organization-id');
 

+ 2 - 2
ot_admin/Classes/Command/DeleteSiteCommand.php

@@ -33,7 +33,7 @@ class DeleteSiteCommand extends Command
      * Allows to add a description, a help text, and / or define arguments.
      *
      */
-    protected function configure()
+    protected function configure(): void
     {
         $this
             ->setName("ot:site:delete")
@@ -77,7 +77,7 @@ class DeleteSiteCommand extends Command
      * @return int
      * @throws \Exception
      */
-    protected function execute(InputInterface $input, OutputInterface $output)
+    protected function execute(InputInterface $input, OutputInterface $output): int
     {
         $org_id = $input->getArgument('organization-id');
         $hard = $input->getOption('hard');

+ 2 - 2
ot_admin/Classes/Command/GetSiteStatusCommand.php

@@ -34,7 +34,7 @@ class GetSiteStatusCommand extends Command
      * Allows to add a description, a help text, and / or define arguments.
      *
      */
-    protected function configure()
+    protected function configure(): void
     {
         $this
             ->setName("ot:site:status")
@@ -62,7 +62,7 @@ class GetSiteStatusCommand extends Command
      * @throws \Opentalent\OtCore\Exception\NoSuchWebsiteException
      * @throws \TYPO3\CMS\Extbase\Object\Exception
      */
-    protected function execute(InputInterface $input, OutputInterface $output)
+    protected function execute(InputInterface $input, OutputInterface $output): int
     {
         $org_id = $input->getArgument('organization-id');
         $full = $input->getOption('full');

+ 2 - 2
ot_admin/Classes/Command/RegenConfigFilesCommand.php

@@ -37,7 +37,7 @@ class RegenConfigFilesCommand extends Command
      * Allows to add a description, a help text, and / or define arguments.
      *
      */
-    protected function configure()
+    protected function configure(): void
     {
         $this
             ->setName("ot:regen-config-files")
@@ -52,7 +52,7 @@ class RegenConfigFilesCommand extends Command
      * @return int
      * @throws \Exception
      */
-    protected function execute(InputInterface $input, OutputInterface $output)
+    protected function execute(InputInterface $input, OutputInterface $output): int
     {
         $io = new SymfonyStyle($input, $output);
         $this->siteController->regenConfigFilesAction();

+ 2 - 2
ot_admin/Classes/Command/RemoveRedirectionCommand.php

@@ -33,7 +33,7 @@ class RemoveRedirectionCommand extends Command
      * Allows to add a description, a help text, and / or define arguments.
      *
      */
-    protected function configure()
+    protected function configure(): void
     {
         $this
             ->setName("ot:redirection:remove")
@@ -59,7 +59,7 @@ class RemoveRedirectionCommand extends Command
      * @return int
      * @throws \Exception
      */
-    protected function execute(InputInterface $input, OutputInterface $output)
+    protected function execute(InputInterface $input, OutputInterface $output): int
     {
         $fromDomain = $input->getArgument('from-domain');
         $hard = $input->getOption('hard');

+ 2 - 2
ot_admin/Classes/Command/ResetBeUserPermsCommand.php

@@ -36,7 +36,7 @@ class ResetBeUserPermsCommand extends Command
      * Allows to add a description, a help text, and / or define arguments.
      *
      */
-    protected function configure()
+    protected function configure(): void
     {
         $this
             ->setName("ot:site:reset-perms")
@@ -70,7 +70,7 @@ class ResetBeUserPermsCommand extends Command
      * @return int
      * @throws \Exception
      */
-    protected function execute(InputInterface $input, OutputInterface $output)
+    protected function execute(InputInterface $input, OutputInterface $output): int
     {
         $org_id = $input->getArgument('organization-id');
         $all = $input->getOption('all');

+ 2 - 2
ot_admin/Classes/Command/ScanCommand.php

@@ -34,7 +34,7 @@ class ScanCommand extends Command
      * Allows to add a description, a help text, and / or define arguments.
      *
      */
-    protected function configure()
+    protected function configure(): void
     {
         $this
             ->setName("ot:site:scan")
@@ -61,7 +61,7 @@ class ScanCommand extends Command
      * @return int
      * @throws \Exception
      */
-    protected function execute(InputInterface $input, OutputInterface $output)
+    protected function execute(InputInterface $input, OutputInterface $output): int
     {
         $deep = $input->getOption('deep');
 

+ 2 - 2
ot_admin/Classes/Command/SetSiteDomainCommand.php

@@ -33,7 +33,7 @@ class SetSiteDomainCommand extends Command
      * Allows to add a description, a help text, and / or define arguments.
      *
      */
-    protected function configure()
+    protected function configure(): void
     {
         $this
             ->setName("ot:site:setdomain")
@@ -69,7 +69,7 @@ class SetSiteDomainCommand extends Command
      * @return int
      * @throws \Exception
      */
-    protected function execute(InputInterface $input, OutputInterface $output)
+    protected function execute(InputInterface $input, OutputInterface $output): int
     {
         $org_id = $input->getArgument('organization-id');
         $domain = $input->getArgument('domain');

+ 1 - 1
ot_admin/Classes/Command/UndeleteSiteCommand.php

@@ -33,7 +33,7 @@ class UndeleteSiteCommand extends Command
      * Allows to add a description, a help text, and / or define arguments.
      *
      */
-    protected function configure()
+    protected function configure(): void
     {
         $this
             ->setName("ot:site:undelete")

+ 2 - 2
ot_admin/Classes/Command/UpdateSiteCommand.php

@@ -37,7 +37,7 @@ class UpdateSiteCommand extends Command
      * Allows to add a description, a help text, and / or define arguments.
      *
      */
-    protected function configure()
+    protected function configure(): void
     {
         $this
             ->setName("ot:site:update")
@@ -79,7 +79,7 @@ class UpdateSiteCommand extends Command
      * @throws \TYPO3\CMS\Extbase\Object\Exception
      * @throws \Throwable
      */
-    protected function execute(InputInterface $input, OutputInterface $output)
+    protected function execute(InputInterface $input, OutputInterface $output): int
     {
         $org_id = $input->getArgument('organization-id');
         $all = $input->getOption('all');

+ 0 - 2
ot_connect/Classes/Middleware/RequestHandler.php

@@ -10,8 +10,6 @@ use TYPO3\CMS\Core\Http\RedirectResponse;
 /**
  * Hooks into the frontend request and process the request in order to
  * rewrite the uri and remove the 'logintype=logout' part after it was processed.
- *
- * @internal
  */
 class RequestHandler implements MiddlewareInterface
 {

+ 9 - 7
ot_core/Classes/Website/OtWebsiteRepository.php

@@ -3,6 +3,7 @@
 namespace Opentalent\OtCore\Website;
 
 use Doctrine\DBAL\DBALException;
+use Doctrine\DBAL\Driver\Exception;
 use Opentalent\OtCore\Exception\InvalidWebsiteConfigurationException;
 use Opentalent\OtCore\Exception\NoSuchRecordException;
 use Opentalent\OtCore\Exception\NoSuchWebsiteException;
@@ -163,7 +164,7 @@ class OtWebsiteRepository
         if ($withRestrictions) {
             $q->andWhere($q->expr()->eq('deleted', 0));
         }
-        $rootUid = $q->execute()->fetchColumn(0);
+        $rootUid = $q->executeQuery()->fetchFirstColumn()[0];
         if (!($rootUid > 0)) {
             throw new NoSuchRecordException('No root page found for website ' . $websiteUid);
         }
@@ -365,8 +366,7 @@ class OtWebsiteRepository
             $q = $q->andWhere($queryBuilder->expr()->eq('deleted', 0));
         }
 
-        $website = $q->execute()
-                    ->fetch();
+        $website = $q->executeQuery()->fetchAssociative();
 
         if (!isset($website['uid'])) {
             throw new NoSuchWebsiteException('No website found for this URI: ' . $uri);
@@ -376,11 +376,13 @@ class OtWebsiteRepository
     }
 
     /**
+     * @param array $otWebsite
      * @param UriInterface $uri
      * @param bool $devMode
-     * @param array|null $website
+     * @param bool $withRestrictions
      * @return int
-     * @throws NoSuchWebsiteException
+     * @throws Exception
+     * @throws \Doctrine\DBAL\Exception
      */
     public function matchUriToPage(array $otWebsite, UriInterface $uri, bool $devMode=false, bool $withRestrictions = true): int
     {
@@ -401,8 +403,8 @@ class OtWebsiteRepository
             ->from('pages')
             ->where($q->expr()->eq('ot_website_uid', $otWebsite['uid']))
             ->andWhere($q->expr()->eq('slug', $q->expr()->literal($tail)))
-            ->execute()
-            ->fetchColumn(0);
+            ->executeQuery()
+            ->fetchFirstColumn()[0];
     }
 
     /**

+ 4 - 8
ot_core/composer.json

@@ -10,17 +10,16 @@
         }
     ],
     "require": {
-        "typo3/cms-core": "^11.5 | ^12.4",
+        "typo3/cms-core": "^12.4",
         "fluidtypo3/flux": "^10.0",
         "fluidtypo3/vhs": "^7.0",
         "georgringer/news": "^11.4",
         "causal/image_autoresize": "^2.4",
         "guzzlehttp/guzzle": "^7.7",
         "twig/twig": "^3.3",
-        "phpunit/phpunit": "^9.5",
-        "waldhacker/hcaptcha": "^2.1",
-        "nimut/typo3-complete": "11.5",
-        "nimut/testing-framework": "^6.0",
+        "phpunit/phpunit": "^10.1.3",
+        "dreistromland/typo3-hcaptcha": "^2.2",
+        "typo3/testing-framework": "^8.2",
         "ext-json": "*",
         "co-stack/logs": "*"
     },
@@ -49,9 +48,6 @@
     "scripts": {
         "post-autoload-dump": [
             "@prepare-extension-test-structure"
-        ],
-        "prepare-extension-test-structure": [
-            "Nimut\\TestingFramework\\Composer\\ExtensionTestEnvironment::prepare"
         ]
     },
     "extra": {

+ 2 - 2
ot_optimizer/Configuration/RequestMiddlewares.php

@@ -8,10 +8,10 @@ return [
         'typo3/cms-frontend/page-resolver' => [
             'target' => Opentalent\OtOptimizer\Middleware\Frontend\OtPageResolver::class,
             'before' => [
-                'typo3/frontendediting/initiator'
+                'typo3/cms-frontend/preview-simulator'
             ],
             'after' => [
-                'typo3/cms-frontend/preview-simulator'
+                'typo3/cms-frontend/base-redirect-resolver'
             ],
         ],
     ],

+ 0 - 8
ot_templating/Classes/Page/ErrorHandler.php

@@ -69,10 +69,6 @@ class ErrorHandler implements PageErrorHandlerInterface
         $pageRepository = GeneralUtility::makeInstance(PageRepository::class);
         $this->otPageRepository->injectPageRepository($pageRepository);
         $this->otPageRepository->injectConnectionPool($connectionPool);
-
-        $this->request = GeneralUtility::makeInstance(Request::class);
-
-        $this->renderingContext = GeneralUtility::makeInstance(RenderingContext::class);
     }
 
     /**
@@ -118,10 +114,6 @@ class ErrorHandler implements PageErrorHandlerInterface
         string $message,
         array $reasons = []
     ): ResponseInterface {
-        $this->request->setControllerExtensionName('ot_templating');
-        $this->renderingContext->setRequest($this->request);
-
-        $this->view->setRenderingContext($this->renderingContext);
         $this->view->setTemplateRootPaths([self::TEMPLATES_ROOT_PATHS]);
         $this->view->setLayoutRootPaths([self::LAYOUTS_ROOT_PATHS]);
         $this->view->setPartialRootPaths([self::PARTIALS_ROOT_PATHS]);

+ 135 - 29
ot_templating/Classes/ViewHelpers/CObjectViewHelper.php

@@ -1,43 +1,70 @@
 <?php
+declare(strict_types=1);
 
 namespace Opentalent\OtTemplating\ViewHelpers;
 
+use Psr\Http\Message\ServerRequestInterface;
+use TYPO3\CMS\Core\Context\Context;
+use TYPO3\CMS\Core\Routing\PageArguments;
+use TYPO3\CMS\Core\Site\Entity\SiteInterface;
+use TYPO3\CMS\Core\Site\SiteFinder;
+use TYPO3\CMS\Core\TimeTracker\TimeTracker;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
 use TYPO3\CMS\Extbase\Reflection\ObjectAccess;
+use TYPO3\CMS\Fluid\Core\Rendering\RenderingContext;
+use TYPO3\CMS\Frontend\Authentication\FrontendUserAuthentication;
+use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
 use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
 use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
+use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
 use TYPO3Fluid\Fluid\Core\ViewHelper\Exception;
+use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithContentArgumentAndRenderStatic;
 
 /**
- *   This view helper is a wrapper for the Fluid/CObjectViewhelper class
- *   that allow to override the TS setup of the object by given variables
+ * This view helper is a modified version of the TYPO3\CMS\Fluid\ViewHelpers\CObjectViewHelper class
+ * that allow to override the TS setup of the object by given variables
  *
- *   It accepts the same arguments as \TYPO3\CMS\Fluid\ViewHelpers\CObjectViewHelper,
- *   and an additional argument 'settings'
+ * It accepts the same arguments as \TYPO3\CMS\Fluid\ViewHelpers\CObjectViewHelper,
+ * and an additional argument 'settings'
  *
- *   @see https://docs.typo3.org/p/georgringer/news/master/en-us/Introduction/Index.html
+ * @see https://docs.typo3.org/p/georgringer/news/master/en-us/Introduction/Index.html
  *
- *   example:
+ * example:
  *
- *     {namespace ot=Opentalent\OtTemplating\ViewHelpers}
- *
- *     <ot:cObject typoscriptObjectPath="lib.tx_ottemplating.widgets.news_list"
- *                 settings="{'settings.defaultPageUid': 1}" />
+ *   {namespace ot=Opentalent\OtTemplating\ViewHelpers}
  *
+ *   <ot:cObject typoscriptObjectPath="lib.tx_ottemplating.widgets.news_list"
+ *               settings="{'settings.defaultPageUid': 1}" />
  *
  * @package Opentalent\OtTemplating\ViewHelpers
  */
-class CObjectViewHelper extends \TYPO3\CMS\Fluid\ViewHelpers\CObjectViewHelper {
+final class CObjectViewHelper extends AbstractViewHelper
+{
+    use CompileWithContentArgumentAndRenderStatic;
 
     /**
-     * Initialize arguments.
+     * Disable escaping of child nodes' output
      *
-     * @throws Exception
+     * @var bool
+     */
+    protected $escapeChildren = false;
+
+    /**
+     * Disable escaping of this node's output
+     *
+     * @var bool
      */
-    public function initializeArguments()
+    protected $escapeOutput = false;
+
+    public function initializeArguments(): void
     {
-        parent::initializeArguments();
+        $this->registerArgument('data', 'mixed', 'the data to be used for rendering the cObject. Can be an object, array or string. If this argument is not set, child nodes will be used');
+        $this->registerArgument('typoscriptObjectPath', 'string', 'the TypoScript setup path of the TypoScript object to render', true);
+        $this->registerArgument('currentValueKey', 'string', 'currentValueKey');
+        $this->registerArgument('table', 'string', 'the table name associated with "data" argument. Typically tt_content or one of your custom tables. This argument should be set if rendering a FILES cObject where file references are used, or if the data argument is a database record.', false, '');
+
+        // <-- Additional paramter
         $this->registerArgument(
             'settings',
             'array',
@@ -48,26 +75,23 @@ class CObjectViewHelper extends \TYPO3\CMS\Fluid\ViewHelpers\CObjectViewHelper {
     }
 
     /**
-     * <!> This is a copy/paste of the parent method, slighly modified
-     * to override the $setup variable with the 'settings' argument
-     *
      * Renders the TypoScript object in the given TypoScript setup path.
      *
-     * @param array $arguments
-     * @param \Closure $renderChildrenClosure
-     * @param RenderingContextInterface $renderingContext
-     * @return mixed
      * @throws Exception
      */
-    public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
+    public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext): string
     {
         $data = $renderChildrenClosure();
-        $typoscriptObjectPath = $arguments['typoscriptObjectPath'];
+        $typoscriptObjectPath = (string)$arguments['typoscriptObjectPath'];
         $currentValueKey = $arguments['currentValueKey'];
         $table = $arguments['table'];
-        $contentObjectRenderer = static::getContentObjectRenderer($renderingContext->getRequest());
+        /** @var RenderingContext $renderingContext */
+        $request = $renderingContext->getRequest();
+        $contentObjectRenderer = self::getContentObjectRenderer($request);
+        $contentObjectRenderer->setRequest($request);
+        $tsfeBackup = null;
         if (!isset($GLOBALS['TSFE']) || !($GLOBALS['TSFE'] instanceof TypoScriptFrontendController)) {
-            static::simulateFrontendEnvironment();
+            $tsfeBackup = self::simulateFrontendEnvironment();
         }
         $currentValue = null;
         if (is_object($data)) {
@@ -83,8 +107,8 @@ class CObjectViewHelper extends \TYPO3\CMS\Fluid\ViewHelpers\CObjectViewHelper {
             $contentObjectRenderer->setCurrentVal($data[$currentValueKey]);
         }
         $pathSegments = GeneralUtility::trimExplode('.', $typoscriptObjectPath);
-        $lastSegment = array_pop($pathSegments);
-        $setup = static::getConfigurationManager()->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT);
+        $lastSegment = (string)array_pop($pathSegments);
+        $setup = self::getConfigurationManager()->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT);
         foreach ($pathSegments as $segment) {
             if (!array_key_exists($segment . '.', $setup)) {
                 throw new Exception(
@@ -107,12 +131,93 @@ class CObjectViewHelper extends \TYPO3\CMS\Fluid\ViewHelpers\CObjectViewHelper {
 
         $content = self::renderContentObject($contentObjectRenderer, $setup, $typoscriptObjectPath, $lastSegment);
         if (!isset($GLOBALS['TSFE']) || !($GLOBALS['TSFE'] instanceof TypoScriptFrontendController)) {
-            static::resetFrontendEnvironment();
+            self::resetFrontendEnvironment($tsfeBackup);
+        }
+        return $content;
+    }
+
+    /**
+     * Renders single content object and increases time tracker stack pointer
+     */
+    protected static function renderContentObject(ContentObjectRenderer $contentObjectRenderer, array $setup, string $typoscriptObjectPath, string $lastSegment): string
+    {
+        $timeTracker = GeneralUtility::makeInstance(TimeTracker::class);
+        if ($timeTracker->LR) {
+            $timeTracker->push('/f:cObject/', '<' . $typoscriptObjectPath);
+        }
+        $timeTracker->incStackPointer();
+        $content = $contentObjectRenderer->cObjGetSingle($setup[$lastSegment], $setup[$lastSegment . '.'] ?? [], $typoscriptObjectPath);
+        $timeTracker->decStackPointer();
+        if ($timeTracker->LR) {
+            $timeTracker->pull($content);
         }
         return $content;
     }
 
+    protected static function getConfigurationManager(): ConfigurationManagerInterface
+    {
+        // @todo: this should be replaced by DI once Fluid can handle DI properly
+        return GeneralUtility::getContainer()->get(ConfigurationManagerInterface::class);
+    }
+
+    protected static function getContentObjectRenderer(ServerRequestInterface $request): ContentObjectRenderer
+    {
+        if (($GLOBALS['TSFE'] ?? null) instanceof TypoScriptFrontendController) {
+            $tsfe = $GLOBALS['TSFE'];
+        } else {
+            $site = $request->getAttribute('site');
+            if (!($site instanceof SiteInterface)) {
+                $sites = GeneralUtility::makeInstance(SiteFinder::class)->getAllSites();
+                $site = reset($sites);
+            }
+            $language = $request->getAttribute('language') ?? $site->getDefaultLanguage();
+            $pageArguments = $request->getAttribute('routing') ?? new PageArguments(0, '0', []);
+            $tsfe = GeneralUtility::makeInstance(
+                TypoScriptFrontendController::class,
+                GeneralUtility::makeInstance(Context::class),
+                $site,
+                $language,
+                $pageArguments,
+                GeneralUtility::makeInstance(FrontendUserAuthentication::class)
+            );
+        }
+        $contentObjectRenderer = GeneralUtility::makeInstance(ContentObjectRenderer::class, $tsfe);
+        $parent = $request->getAttribute('currentContentObject');
+        if ($parent instanceof ContentObjectRenderer) {
+            $contentObjectRenderer->setParent($parent->data, $parent->currentRecord);
+        }
+        return $contentObjectRenderer;
+    }
+
+    /**
+     * \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer->cObjGetSingle() relies on $GLOBALS['TSFE']
+     */
+    protected static function simulateFrontendEnvironment(): ?TypoScriptFrontendController
+    {
+        $tsfeBackup = $GLOBALS['TSFE'] ?? null;
+        $GLOBALS['TSFE'] = new \stdClass();
+        $GLOBALS['TSFE']->cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class);
+        return $tsfeBackup;
+    }
+
+    /**
+     * Resets $GLOBALS['TSFE'] if it was previously changed by simulateFrontendEnvironment()
+     */
+    protected static function resetFrontendEnvironment(?TypoScriptFrontendController $tsfeBackup): void
+    {
+        $GLOBALS['TSFE'] = $tsfeBackup;
+    }
+
+    /**
+     * Explicitly set argument name to be used as content.
+     */
+    public function resolveContentArgumentName(): string
+    {
+        return 'data';
+    }
+
     /**
+     * -- Additional method --
      * Recursively replace any {$var} value in the given configuration
      * if 'var' is a key in the 'overrideSetup' array
      *
@@ -143,6 +248,7 @@ class CObjectViewHelper extends \TYPO3\CMS\Fluid\ViewHelpers\CObjectViewHelper {
     }
 
     /**
+     * -- Additional method --
      * Similar to array_merge_recursive, except that the end nodes of the
      * base array is replaced and not merged.
      *

+ 0 - 49
ot_templating/Classes/ViewHelpers/ImagePViewHelper.php

@@ -1,49 +0,0 @@
-<?php
-
-namespace Opentalent\OtTemplating\ViewHelpers;
-
-use TYPO3\CMS\Core\Resource\Exception\ResourceDoesNotExistException;
-use TYPO3\CMS\Fluid\ViewHelpers\ImageViewHelper;
-
-/**
- * -- Wrapper for the TYPO3\CMS\Fluid\ViewHelpers\ImageViewHelper --
- * Display the image like the original viewhelper does, but does not
- * throw an error if the file is not an image or if the
- * image can not be displayed.
- *
- *     {namespace ot=Opentalent\OtTemplating\ViewHelpers}
- *
- *     {ot:imageP()}
- *
- * @package Opentalent\OtTemplating\ViewHelpers
- */
-class ImagePViewHelper extends ImageViewHelper
-{
-    /**
-     * -- This method is expected by Fluid --
-     * Declares the viewhelper's parameters
-     */
-    public function initializeArguments()
-    {
-        parent::initializeArguments();
-    }
-
-    /**
-     * -- This method is expected by Fluid --
-     * Renders the content as html
-     *
-     * @return string Rendered tag
-     */
-    public function render() {
-        try {
-            return parent::render();
-        } catch (ResourceDoesNotExistException |
-                \UnexpectedValueException |
-                \RuntimeException |
-                \InvalidArgumentException
-                $e) {
-            return "";
-        }
-    }
-
-}

+ 1 - 1
ot_templating/Resources/Private/Partials/Classic/Carousel.html

@@ -13,7 +13,7 @@
         <div class="carousel">
             <f:for each="{images}" as="image">
                 <div>
-                    <ot:imageP src="{image.url}"
+                    <f:image src="{image.url}"
                              alt="{image.alternative}"
                              title="{image.title}"
                              class="carousel-img"

+ 2 - 1
ot_templating/Resources/Private/Partials/Classic/UserToolbar.html

@@ -79,7 +79,8 @@
                 </f:then>
                 <f:else>
                     <a href="{ot:request.getOtEnvVar(argument: 'LOGIN_PAGE_URL')}" target="_blank">
-                        <i class="fas fa-power-off"></i> <f:translate key="login"/>
+                        <i class="fas fa-power-off"></i>
+                        <f:translate key="LLL:EXT:ot_templating/Resources/Private/Language/locallang.xlf:login"/>
                     </a>
                 </f:else>
             </f:if>

+ 1 - 1
ot_templating/Resources/Private/Partials/Modern/Carousel.html

@@ -58,7 +58,7 @@
                                 data-param10=""
                                 data-description="">
 
-                                <ot:imageP src="{image.url}"
+                                <f:image src="{image.url}"
                                      alt="{image.alternative}"
                                      class="rev-slidebg"
                                      height="500c"

+ 9 - 3
ot_templating/Resources/Private/Templates/Page/Error/403.html

@@ -8,7 +8,13 @@
 </f:section>
 
 <f:section name="Message">
-    <p><f:translate key="youre_not_allowed_to_view_this_page"/></p>
-    <p><f:translate key="did_you_login"/></p>
-    <a href="{homeUri}"><f:translate key="back_to_homepage"/></a>
+    <p>
+        <f:translate key="LLL:EXT:ot_templating/Resources/Private/Language/locallang.xlf:youre_not_allowed_to_view_this_page"/>
+    </p>
+    <p>
+        <f:translate key="LLL:EXT:ot_templating/Resources/Private/Language/locallang.xlf:did_you_login"/>
+    </p>
+    <a href="{homeUri}">
+        <f:translate key="LLL:EXT:ot_templating/Resources/Private/Language/locallang.xlf:back_to_homepage"/>
+    </a>
 </f:section>

+ 6 - 4
ot_templating/Resources/Private/Templates/Page/Error/404.html

@@ -3,14 +3,16 @@
 <f:layout name="ErrorPage" />
 
 <f:section name="Configuration">
-    <flux:form id="err404"  label="LLL:template_err404" extensionName="Opentalent.OtTemplating">
+    <flux:form id="err404" label="LLL:template_err404" extensionName="Opentalent.OtTemplating">
     </flux:form>
 </f:section>
 
 <f:section name="Message">
-    <p><f:translate key="page_not_available"/></p>
+    <p><f:translate key="LLL:EXT:ot_templating/Resources/Private/Language/locallang.xlf:page_not_available"/></p>
     <p>
-        <f:translate key="control_url_or"/>
-        <a href="{homeUri}"><f:translate key="click_here_to_go_back_home"/>.</a>
+        <f:translate key="LLL:EXT:ot_templating/Resources/Private/Language/locallang.xlf:control_url_or"/>
+        <a href="{homeUri}">
+            <f:translate key="LLL:EXT:ot_templating/Resources/Private/Language/locallang.xlf:click_here_to_go_back_home"/>.
+        </a>
     </p>
 </f:section>

+ 3 - 1
ot_templating/Resources/Private/Templates/Page/Error/500.html

@@ -8,5 +8,7 @@
 </f:section>
 
 <f:section name="Message">
-    <p><f:translate key="an_error_occured"/></p>
+    <p>
+        <f:translate key="LLL:EXT:ot_templating/Resources/Private/Language/locallang.xlf:an_error_occured"/>
+    </p>
 </f:section>