Project

General

Profile

Actions

Bug #105418

open

QueryBuilder: no longer possible to build advanced orderings with orderBy

Added by Michael Stopp 8 days ago. Updated 2 days ago.

Status:
Needs Feedback
Priority:
Should have
Assignee:
Category:
Database API (Doctrine DBAL)
Target version:
-
Start date:
2024-10-23
Due date:
% Done:

0%

Estimated time:
TYPO3 Version:
13
PHP Version:
8.2
Tags:
queryBuilder
Complexity:
Is Regression:
Sprint Focus:

Description

I'm basically repeating myself from 6 years ago (#84814): with the current QueryBuilder it seems impossible to do orderings that go beyond simple field list, i.e. something like in these real-life examples:

ORDER BY FIELD(eventtype, 0, 4, 1, 2, 3), sorting

or

ORDER BY CAST(SUBSTRING_INDEX(c.IP, '.', -1) AS UNSIGNED)

Before moving to Doctrine DBAL version 4 it was possible to achieve this with something like:

$queryBuilder->add('orderBy', 'FIELD(eventtype, 0, 4, 1, 2, 3), sorting')

How can we do this now, after the add() method was dropped in DBAL v4?

Actions #1

Updated by Stefan Bürk 3 days ago

  • Status changed from New to Needs Feedback
  • Assignee set to Stefan Bürk

First of all, add() was a internal method of Doctrine DBAL and has been
removed by Doctrine DBAL. We decided to not restore that and following the
line Doctrine DBAL has drawn.

Since the very beginning, the TYPO3 QueryBuilder was an decorator around
the Doctrine QueryBuilder and accessibaly with getConcreteQueryBuilder()
which is still possible.

The argument for the dropped add() method was, that it is doable by the
generic methods, in case of order things by using oderBy() or addOrderBy().

The TYPO3 levele does automatic quoting and stuff, and in cases that is not
usefull, the underlying concrete builder instance needs to be used - and should
have be done so already earlier.

The raw doctrine QueryBuilder does not do any quoting, so you have to take care
completly on your own.

$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
  ->getQueryBuilderForTable('pages');
$queryBuilder
  ->select('uid', 'pid', /* ... */ )
  ->from('pages')
  ->where(
    $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter(123, Connection::PARAM_INT)),
  );

$concreteQueryBuilder = $queryBuilder->getConcreteQueryBuilder();
$concreteQueryBuilder
  // proper quoting must be done manually on the concrete query builder
  ->orderBy('FIELD(' .$queryBuilder->quoteIdentifier('eventtype') . ', 0, 4, 1, 2, 3)');

$queryBuilder->addOrderBy('sorting'); // use correct identifier quoting

$result = $queryBuilder->executeQuery();
while ($row = $result->fetchAssociative()) {
  // ..
}

Further, you can also revieve the Doctrine DBAL Expression Builder from the concrete QueryBuilder
instead of the advanced TYPO3 Expression Builder.

Note, since TYPO3 v13 the TYPO3 ExpressionBuilder has additional expression variants, not provided
by the underlying Doctrine DBAl ExpressionBuilder - see corresponding v13 ChangeLog for that.

In general, it is a good advice to build a helper class for custom expression which is tested against
all TYPO3 supported Database vendors (using the Platform class) etc. Can be done from the outside.

Or providing changes (FEATURE) to add missing expression (with full test coverage ) to the TYPO3
implementation or contribute directly to Doctrine DBAL.

From my point of view this is not a bug, just an oversight of the proper API to use. I hope I could
point out how to do the required stuff and going to close this issue in a couple of days if there is
not a real bug involved.

Please give feedback if the explanation helped you to build your needed query.

Actions #2

Updated by Michael Stopp 2 days ago

Thank you very much, this is extremely helpful! And I guess you're right, this isn't really a bug and the issue can be closed.

However, I still think the documentation could be more helpful here. I just checked, this option to use the concrete QueryBuilder as demonstrated in you example isn't mentioned anywhere. And the suggested migration for ->add() doesn't work for cases as described in my issue, so it isn't helping either. And the latest version of the docs for ->orderBy() still recommends to use ->add() for extended use cases (actually still based on my old issue...). I'll try to make a change request for that. Anyway, thanks again!

Actions

Also available in: Atom PDF