TYPO3 8.7 TypoScript JOIN子查询失效,求多语言内容获取方案
解决TYPO3 8.7中TypoScript JOIN子查询解析异常的替代方案
在TYPO3 8.7里尝试用TypoScript编写包含JOIN的子查询时,大概率会碰到这个让人头疼的解析问题:原本写的子查询代码被解析器错误转换,直接导致SQL无法正常执行。
问题重现
你原本写的TypoScript子查询片段:
join = (SELECT * FROM tt_content Join (SELECT sys_language_uid FROM `tt_content` WHERE (pid=119)AND
经过TypoScript解析器处理后,SQL被错误转成了这样:
'SELECT * FROM `tt_content` INNER JOIN `(SELECT` * ON tt_content Join (SELECT sys_language_uid FROM `tt_content` WHERE (pid=119)AND
这个问题已经在官方问题追踪系统中登记,不过咱们不用等修复,直接用下面的替代方案就能实现需求:按UID获取当前语言的页面内容,要是当前语言没有内容,就自动取默认语言的内容。
推荐替代方案
方案1:用TYPO3原生语言回退机制(最省心)
TYPO3本身就自带了内容的语言回退功能,完全不用自己写复杂的JOIN查询,直接通过TypoScript配置就能搞定:
lib.content = CONTENT lib.content { table = tt_content select { uidInList = 你的内容UID # 替换成实际的内容UID languageField = sys_language_uid fallback = 1 # 开启语言回退,当前语言无内容时用默认语言 # 要是需要更精细的回退顺序,可以加这句,比如先默认语言再语言ID为1的内容 # fallbackOrder = 0,1 } }
这个方案是最推荐的,因为它完全贴合TYPO3的架构设计,不用自己折腾SQL,还能避免解析器的坑。
方案2:用LEFT JOIN手动实现回退(避开子查询)
如果一定要自己写查询逻辑,那可以避开子查询,改用LEFT JOIN来实现,这样就能绕开TypoScript解析器对子查询的错误处理:
lib.content = CONTENT lib.content { table = tt_content select { # 用COALESCE优先取当前语言的字段,没有就取默认语言的 selectFields = COALESCE(current.uid, default.uid) AS uid, COALESCE(current.header, default.header) AS header join = tt_content default ON default.uid = tt_content.uid AND default.sys_language_uid = 0 where = tt_content.sys_language_uid = {$sys_language_uid} OR tt_content.sys_language_uid = 0 groupBy = tt_content.uid # 确保每个UID只返回一条记录 } }
这里的{$sys_language_uid}是TypoScript常量,会自动获取当前页面的语言ID,不用手动硬编码。
方案3:自定义PHP类执行查询(最灵活)
要是上面的方案都满足不了你的需求,那可以写个自定义的PHP类来执行正确的SQL,然后在TypoScript里调用:
首先是TypoScript配置:
lib.content = USER_INT lib.content { userFunc = Vendor\YourExtension\Utility\ContentUtility::getFallbackContent # 传递需要的参数 contentUid = 你的内容UID currentLang = {$sys_language_uid} }
然后在你的扩展里创建对应的PHP类:
<?php namespace Vendor\YourExtension\Utility; use TYPO3\CMS\Core\Database\ConnectionPool; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer; class ContentUtility { public function getFallbackContent($content, $conf) { $contentUid = (int)$conf['contentUid']; $currentLang = (int)$conf['currentLang']; // 获取数据库连接 $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('tt_content'); $queryBuilder = $connection->createQueryBuilder(); // 优先取当前语言的内容,没有就取默认语言的 $result = $queryBuilder ->select('*') ->from('tt_content') ->where( $queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($contentUid, \PDO::PARAM_INT)), $queryBuilder->expr()->in('sys_language_uid', $queryBuilder->createNamedParameter([$currentLang, 0], \TYPO3\CMS\Core\Database\Connection::PARAM_INT_ARRAY)) ) ->orderBy('sys_language_uid', 'DESC') ->setMaxResults(1) ->execute() ->fetchAssociative(); // 渲染内容,这里示例渲染header字段,你可以根据需求调整 if ($result) { $cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class); $cObj->start($result, 'tt_content'); return $cObj->cObjGetSingle('TEXT', ['field' => 'header']); } return ''; } }
内容的提问来源于stack exchange,提问作者loon
相关产品推荐
相关产品推荐

