TYPO3 8.7使用Flexform uid进行查询排序

时间:2017-09-28 14:21:11

标签: php doctrine typo3 extbase

我遇到了许多TYPO3扩展的问题,Uid的订购查询结果来自后端的flexform插件设置。我尝试创建一个查询,它以相同的顺序给出了结果uid,就像flexform来自插件设置一样。就像我选择data.uid 5 7和3,我的查询结果按顺序给我这些。

例如:

SITEINFO:

  • PHP 7.0
  • TYPO3 8.7
  • MariaDB的:10.1
  • Debian服务器

从Controller调用此函数。

$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列表排序queryresult的方法适用于TYPO3 6.2 7.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

我在我的DBMS上试过这个但是失败了。原因是最后3个陈述。

`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

如果我们这样做这样的调用没有这些``arround the 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,我通过findByUid查询他自己的每个uid,但这在我看来并不像是一种“最佳实践”方式。对于这种从数据库获取数据的情况,有没有人更清楚?或者这可能是一个Bug?

我希望有人可以帮助我。

最好的问候

Fanor

3 个答案:

答案 0 :(得分:1)

我认为问题出在\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;
}

答案 1 :(得分:1)

不覆盖:

清除默认订单:

$query->setOrderings(array());

将您的QueryBuilder转换为新的教义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());

答案 2 :(得分:0)

控制器的替代方案:

Base::vf

这是一种肮脏的方式,因为这个逻辑位于错误的地方,但它有效:)

此外,它也不像您的解决方案那样高效。 您的解决方案在7.6原因中运行良好。但我不知道为什么它在版本8中有所突破。也许在这个TYPO3的订购系统中“修复安全问题”。