Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typo3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Doctrine 如何在TYPO3中将复杂查询重写为原则DBAL?_Doctrine_Typo3_Extbase_Typo3 10.x - Fatal编程技术网

Doctrine 如何在TYPO3中将复杂查询重写为原则DBAL?

Doctrine 如何在TYPO3中将复杂查询重写为原则DBAL?,doctrine,typo3,extbase,typo3-10.x,Doctrine,Typo3,Extbase,Typo3 10.x,我正在努力将复杂的SQL查询迁移到TYPO3中的原则DBAL。我的旧存储库查询如下所示: $enableFields = $GLOBALS['TSFE']->sys_page->enableFields('tx_test'); // calculate distance between geo coordinates $distance = ''; if ($geoData) { $distance = ', 3956 * 2 * ASIN( SQRT (POWER ( S

我正在努力将复杂的SQL查询迁移到TYPO3中的原则DBAL。我的旧存储库查询如下所示:

$enableFields = $GLOBALS['TSFE']->sys_page->enableFields('tx_test');

// calculate distance between geo coordinates
$distance = '';
if ($geoData) {
    $distance = ', 3956 * 2 * ASIN( SQRT (POWER ( SIN((' . $geoData['latitude'] . ' - abs(tx_test.latitude)) * pi() / 180 / 2), 2) + COS(' . $geoData['latitude'] . ' * pi() / 180) * ' . 'COS(abs(tx_test.latitude)' .
        ' * pi() / 180) * POWER (SIN((' . $geoData['longitude'] .
        ' - tx_test.longitude)' .
        ' * pi() / 180 / 2), 2))) AS distance';
}

// General query
$sql = 'SELECT * ' . $distance .
       ' FROM tx_test ' .
       ' WHERE DATE_FORMAT(FROM_UNIXTIME(start), "%Y") = '.(int)$settings['flexformYear'].' AND published = 1 ' . $enableFields;

if($headline) {
    $sql .= ' AND headline like '.$GLOBALS['TYPO3_DB']->quoteStr($headline).'%';
}

// ... and some more ...

$query = $this->createQuery();
$results = $query->statement($sql)->execute();
转为教条

现在,我可以轻松地删除
$GLOBALS['TYPO3'u DB']->quoteStr()
,并用以下代码替换上面的最后两行代码:

$connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('tx_test');
$results = $connection->executeQuery($sql)->fetchAll();
但这将返回一个结果数组,而不是带有附加子对象的对象,例如
FileReference
对象或另一个附加模型


有没有其他方法可以达到预期的效果?如果没有,我如何保护/清理
$headline
的用户输入?我需要自己为联接表编写SQL吗?

这里是一些距离计算的一部分,应该适合您关于使用原则和引用的用例

使用Doctrine,您也可以将记录作为数组。如果需要Extbase对象,请参见下文

获得DBAL QueryBuilder的TYPO3风格:

$q = GeneralUtility::makeInstance(ConnectionPool::class)
  ->getQueryBuilderForTable($table = 'tx_....');
$q->select(
  ...
  'a.lat',
  'a.lng'
)
  ->from($table /*, 'alias if you want' */);
在进行类似的计算时,我很少使用fluent接口(当然,通过使用任何带有
$q->selectLiteral()
的MySQL函数都可以做到这一点)

参数

$dataMapper = $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper::class);
$objects = $dataMapper->map(YourExtbaseModel::class, $aRes);            
为了防止SQL注入,您应该使用
$q->quote()
/
$q->quoteIdentifier()
引用所有可能的用户输入,或者使用参数
$q->createNamedParameter()

约束示例

这只是约束的一部分。它包含一个示例,说明如何根据搜索函数中常见的条件将它们组合起来

if ((float)$searchObject->radiusKm > .5) {
    $_radiusOrs = [
        'IF (
            ' . $q->quoteIdentifier('lat') . ' = 0,
            100000,
            12742 * ASIN(
                SQRT(
                    POWER(
                        SIN(
                            ( ' . $q->quote((float)$searchObject->lat) . ' 
                                - ABS( ' . $q->quoteIdentifier('lat') . ' ) 
                            ) * 0.0087266
                        ), 
                        2
                    )
                    +
                    COS( ' . $q->quote((float)$searchObject->lng) . ' * 0.01745329 ) * COS(
                        ABS( ' . $q->quoteIdentifier('lat') . ' ) * 0.01745329
                    ) * POWER(
                        SIN( 
                            ( ' . $q->quote((float)$searchObject->lng) . ' 
                                - ' . $q->quoteIdentifier('lng') . ' 
                            ) * 0.0087266 
                        ), 
                        2
                    )
                 )
            )
        ) < ' . $q->quote((float)$searchObject->radiusKm),
    ];

    $q->andWhere(
        $q->expr()->orX(...$_radiusOrs)
    );
}
...
$aRes = $q->execute()->fetchAll();

我建议:只有在对象很少或内存足够且不关心性能的情况下才使用Extbase对象。通常情况下,您应该使用同样好的普通数组


Extbase查询生成器允许在输出到流体模板时进行一些优化:传递
\TYPO3\CMS\Extbase\Persistence\Generic\QueryResult
允许在其上使用
f:paginate
ViewHelper,它不必实例化所有对象,只实例化当前页面上显示的对象。在使用条令QueryBuilder时,这种可能性还不存在。因此,现在使用Extbase模型应该是最后的选择,而不是默认的选择。这似乎是“最佳实践”-这已不再是事实

非常感谢你的详细回答,它把我推向了正确的方向。但我并没有考虑这个问题,即如何按距离排序,因为这是我想要实现的目标。如果用户提供地理坐标,我的查询将选择所有内容并按距离排序结果。。。。以及如何使用where子句中的
DATE\u格式(FROM\u UNIXTIME(start),“%Y”)
。将
$\u radiusOrs=…
行替换为
$q->addSelectLiteral(
..
作为dist
并按其排序:
$q->orderBy('dist','ASC');
对于另一个问题,您可以像编写一样编写它,或者使用
$q->quoteIdentifier()
如果你想说得非常正确……你真的应该现在就开始编码。如果答案对你有帮助,请竖起大拇指。