使用 routeEnhancers 处理 TYPO3 v9.5 Extbase 错误

TYPO3 v9.5 Extbase Error Handling with routeEnhancers

在我的 Extbase TYPO3 扩展中,我想在记录不再可用(隐藏或删除)时显示自定义流体模板。错误处理加载一个流体模板,其中路径在 setup.typoscript.

中定义

但是当我在站点 config.yaml 文件中为我的扩展添加 routEnhancers 时,错误处理不再起作用,它只显示默认的 TYPO3 错误页面:“请求的页面不存在”。

在站点配置的文档中,我没有找到任何方法来为我的 Ext 设置特殊的错误处理。

这是目前处理它的代码:

控制器:

class RecordController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController
{


    /**
     * Error handling if no entry is found
     *
     * @param string $configuration configuration what will be done
     * @throws \InvalidArgumentException
     * @return string
     */
    protected function handleNoRecordFoundError($configuration)
    {
        $statusCode = HttpUtility::HTTP_STATUS_404;
        HttpUtility::setResponseCode($statusCode);

        $this->getTypoScriptFrontendController()->set_no_cache('Record record not found');

        $standaloneTemplate = GeneralUtility::makeInstance(StandaloneView::class);
        $standaloneTemplate->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($configuration));
        return $standaloneTemplate->render();
    }

    /**
     * @return TypoScriptFrontendController
     */
    protected function getTypoScriptFrontendController()
    {
        return $GLOBALS['TSFE'];
    }
    /**
     * action show
     * @param \Digitalgizmo\Vehicles\Domain\Model\Vehicle $vehicle
     * @return void
     *
     *
     */
    public function showAction(\Vendor\MyExt\Domain\Model\Record $record = null)
    {

        if ($record !== null){

            $this->view->assign('record', $record);
        }
        else {
            $errorContent = $this->handleNoRecordFoundError($this->settings['show']['errorTemplate']);
            if ($errorContent) {
                return $errorContent;
            }
        }


    }
}

config.yaml;

routeEnhancers:
  MyExt:
    type: Extbase
    extension: MyExt
    plugin: MyExt
    routes:
      -
        routePath: '/staticName/{uid}/{slug}'
        _controller: 'ControllerName::show'
        _arguments:
          slug: record
          uid: id
    defaultController: 'ControllerName::show'
    aspects:
      slug:
        type: PersistedAliasMapper
        tableName: tx_myext_domain_model_record
        routeFieldName: slug
        routeValuePrefix: /
      uid:
        type: PersistedAliasMapper
        tableName: tx_myext_domain_model_record
        routeFieldName: uid

如果记录可用,RoutEnhancer 工作正常。

如何捕获该错误,以便处理它并显示我的流体模板?我的 showAction 甚至没有被加载(使用 XDebug 测试)。我猜这是因为 TYPO3 内核抛出了错误。

该代码似乎一切正常,问题是 RouteEnhancer 受到与您的 showAction 相同的约束的影响:删除记录后,routeEnhancer 中的 resolve 方法将不再能够找到它或它的鼻涕虫

作为参考,请参阅 API 中的 resolve 函数:https://api.typo3.org/9.5/_persisted_alias_mapper_8php_source.html。它实例化一个 queryBuilder,默认情况下,它构建一个 deleted=0 子句。

要通过他们的 slug 删除 redcords,您需要做的是构建一个自定义的 RouteEnhancer,也许通过扩展 PersistendAliasMapper class 的方式它也能找到已删除的记录,请参考 https://docs.typo3.org/m/typo3/reference-coreapi/master/en-us/ApiOverview/Routing/ExtendingRouting.html ,但请注意其含义:即使设置了 eval=uniqueInSite 选项,模型中的 slug 字段也将无法找到碰撞的 slug,因为它也只能看到未删除的记录。

感谢 j4k3

我已经为 routeEnhancers 创建了我自己的方面类型,它删除了已删除和隐藏的约束,因此不会引发错误。

我按照此文档创建了它:https://docs.typo3.org/m/typo3/reference-coreapi/master/en-us/ApiOverview/Routing/ExtendingRouting.html

这是我的 CustomMapper Class。

use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
use TYPO3\CMS\Core\Database\Query\Restriction\FrontendGroupRestriction;
use TYPO3\CMS\Core\Database\Query\Restriction\FrontendRestrictionContainer;
use TYPO3\CMS\Core\Database\Query\Restriction\HiddenRestriction;
use TYPO3\CMS\Core\Routing\Aspect\PersistedAliasMapper;
use TYPO3\CMS\Core\Utility\GeneralUtility;


class CustomMapper extends PersistedAliasMapper
{
    protected function createQueryBuilder(): QueryBuilder
    {
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
            ->getQueryBuilderForTable($this->tableName)
            ->from($this->tableName);
        $queryBuilder->setRestrictions(
            GeneralUtility::makeInstance(FrontendRestrictionContainer::class, $this->context)
        );
        // Frontend Groups are not available at this time (initialized via TSFE->determineId)
        // So this must be excluded to allow access restricted records
        $queryBuilder->getRestrictions()->removeByType(FrontendGroupRestriction::class);
        $queryBuilder->getRestrictions()->removeByType(DeletedRestriction::class);
        $queryBuilder->getRestrictions()->removeByType(HiddenRestriction::class);
        return $queryBuilder;
    }
}

基本上我唯一添加的是删除 DeletedRestriction 和 HiddenRestriction。

此外,我不得不更改 Slug 字段的构建方式。我将数据集的 uid 添加到 slug 并删除了单独的 uid GET 参数,因此现在 slug 在数据库中是唯一的。在我这样做之前,我遇到了一个问题,即查询发现了多个相同的 slug 值,并且它总是采用第一个。

现在由于 slug 在数据库中是唯一的 table 它将 return 对象并且不会抛出错误,所以我可以在控制器中处理“错误”。