TYPO3 8.7中的Flexform uid的查询排序

5
我有一个关于许多TYPO3扩展的问题,即使用来自后端flexform插件设置的Uid对查询结果进行排序。我尝试创建一个查询,以使结果Uid按与Plugin设置的flexform相同的顺序排列。就像我选择数据.uid为5、7和3一样,我的查询结果会按照这个顺序给我这些Uid。
例如:
站点信息:
- PHP 7.0 - TYPO3 8.7 - mariadb:10.1 - Debian服务器
此功能从控制器中调用。
$partners = $this->partnerRepository->findByUids($this->settings['showMainSponsor']);

$this->settings['showMainSponsor']中的值为"3, 4, 1"。

这些是TYPO3插件设置中所选区域的Uid。

存储库函数"findByUids"如下所示。

public function findByUids($uids){

    if(!isset($uids) || empty($uids)){
        return NULL;
    }

    $uidListString = $uids;
    if(!is_array($uids)){
        $uidListString = explode(',', $uids);
    }

    $query = $this->createQuery();
    $query->getQuerySettings()->setRespectStoragePage(FALSE);

    //here i set the orderings
    $orderings = $this->orderByField('uid', $uidListString);
    $query->setOrderings($orderings);

    $query->matching(
        $query->logicalAnd(
            $query->in('uid', $uidListString)
        )
    );



    return $query->execute();
}

在这里调用了一个名为"orderByField"的函数,它设置了所有排序方式。
/**
 * @param string $field
 * @param array $values
 *
 * @return array
 */
protected function orderByField($field, $values) {
    $orderings = array();
    foreach ($values as $value) {
        $orderings["$field={$value}"] =  \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING;
    }
    return $orderings;
}

这种通过Flexform给定的uid列表对查询结果进行排序的方法适用于TYPO3 6.27.6。现在我尝试将此扩展附加到TYPO3 8.6项目中,但此方法不再起作用。我尝试调试它并查看查询。我发现了破坏此查询的原因。不起作用的查询如下:

SELECT `tx_partner_domain_model_partner`.* FROM `tx_partner_domain_model_partner` `tx_partner_domain_model_partner` WHERE (`tx_partner_domain_model_partner`.`uid` IN (3, 4, 1)) AND (`tx_partner_domain_model_partner`.`sys_language_uid` IN (0, -1)) AND ((`tx_partner_domain_model_partner`.`deleted` = 0) AND (`tx_partner_domain_model_partner`.`t3ver_state` <= 0) AND (`tx_partner_domain_model_partner`.`pid` <> -1) AND (`tx_partner_domain_model_partner`.`hidden` = 0) AND (`tx_partner_domain_model_partner`.`starttime` <= 1506603780) AND ((`tx_partner_domain_model_partner`.`endtime` = 0) OR (`tx_partner_domain_model_partner`.`endtime` > 1506603780))) ORDER BY `tx_partner_domain_model_partner`.`uid=3` DESC, `tx_partner_domain_model_partner`.`uid=4` DESC, `tx_partner_domain_model_partner`.`uid=1` DESC

我在我的数据库管理系统上尝试了这个操作,但失败了。原因是最后三个语句。

`tx_partner_domain_model_partner`.`uid=3` DESC, `tx_partner_domain_model_partner`.`uid=4` DESC, `tx_partner_domain_model_partner`.`uid=1` DESC

TYPO3使用``来转义uid,例如:
 `tx_partner_domain_model_partner`.`uid=4` DESC

如果我们在uid=3周围没有使用这些“`”符号进行调用,则会出现以下情况。
`tx_partner_domain_model_partner`.uid=3 DESC, `tx_partner_domain_model_partner`.uid=4 DESC, `tx_brapartner_domain_model_partner`.uid=1 DESC

它运行良好。也许安全原因是TYPO3在其最新版本上执行此操作的原因,但我找不到其他好的解决方案来处理这种基本情况。目前,我使用foreach遍历每个uid,并通过findByUid进行查询,但这似乎不是一种“最佳实践”的方式。是否有更干净的方式来获取数据库中的数据?或者这可能是一个错误吗?

希望有人能帮助我。

最好的问候

Fanor

3个回答

3

不覆盖原有内容:

清除默认排序:

$query->setOrderings(array());

将您的QueryBuilder转换为新的Doctrine QB:

/** @var Typo3DbQueryParser $queryParser */
$queryParser = $this->objectManager->get(Typo3DbQueryParser::class);
/** @var QueryBuilder $doctrineQueryBuilder */
$doctrineQueryBuilder = $queryParser->convertQueryToDoctrineQueryBuilder($query);

通过concreteQb添加UID。
$concreteQb = $doctrineQueryBuilder->getConcreteQueryBuilder();
foreach ($uidList as $uid) {
  $concreteQb->addOrderBy("$key={$uid}", QueryInterface::ORDER_DESCENDING);
}

获取映射结果:
/** @var DataMapper $dataMapper */
$dataMapper = $this->objectManager->get(DataMapper::class);
return $dataMapper->map(YourDataClass::class, $$doctrineQueryBuilder->execute()->fetchAll());

这是最好的答案,因为您可以使用通用查询对象(执行所有约束操作)“准备”查询,并在存储库查询的末尾将其传递给Doctrine执行排序操作。 - JKB

2

我认为问题出在\TYPO3\CMS\Core\Database\Query\QueryBuilder::orderBy中,因为fieldName被引用了。你可以重写这个类,通过=拆分fieldName并构建一个带有引号的字符串,然后对剩余的字符串进行intval()操作,如下所示:

public function orderBy(string $fieldName, string $order = null): QueryBuilder
{
    if (strpos($fieldName, '=') !== false) {
        list($field, $value) = GeneralUtility::trimExplode('=', $fieldName);
        $field = $this->connection->quoteIdentifier($field);
        $value = intval($value);
        $fieldName = $field . $value;
    }
    else {
        $fieldName = $this->connection->quoteIdentifier($fieldName);
    }
    $this->concreteQueryBuilder->orderBy($fieldName, $order);

    return $this;
}

2
public function findByUidList($uidList)
{
    $uids = GeneralUtility::intExplode(',', $uidList, true);
    if ($uidList === '' || count($uids) === 0) {
        return [];
    }

    $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->getTableName());
    $queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class));

    $records = $queryBuilder
        ->select('*')
        ->from($this->getTableName())
        ->where($queryBuilder->expr()->in('uid', $uids))
        ->add('orderBy', 'FIELD('.$this->getTableName().'.uid,' . implode(',', $uids) . ')')
        ->execute()
        ->fetchAll();

    $objectManager = GeneralUtility::makeInstance(ObjectManager::class);
    $dataMapper = $objectManager->get(DataMapper::class);
    $result = $dataMapper->map($this->objectType, $records);

    return $result;
}

/**
 * Return the current table name
 *
 * @return string
 */
protected function getTableName()
{
    $objectManager = GeneralUtility::makeInstance(ObjectManager::class);
    $dataMapper = $objectManager->get(DataMapper::class);
    $tableName = $dataMapper->getDataMap($this->objectType)->getTableName();
    return $tableName;
}

这在TYPO3 v10.4中运行得非常好! :)

将以下内容添加到您的存储库顶部:use TYPO3\CMS\Core\Database\ConnectionPool; use TYPO3\CMS\Core\Database\Query\Restriction\FrontendRestrictionContainer; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\Object\ObjectManager; use TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException; use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper; - D2k
1
另外,您能否更详细地解释一下您所做的更改以及为什么这样做可以解决问题? - Elikill58
你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心找到有关如何编写良好答案的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接