Breaking: #102875 - QueryBuilder changes
See forge#102875
Description
Doctrine DBAL 4 removed methods from the 
        Query which has been
adopted to the extended 
        \TYPO3\.
Removed methods:
Query: Use new reset methods and normal set methods instead.Builder:: add () Query: No replacement, internal state.Builder:: get Query Part ($part Name) Query: No replacement, internal state.Builder:: get Query Parts () Query: Replacement methods has been added, see list.Builder:: reset Query Part ($part Name) Query: Replacement methods has been added, see list.Builder:: reset Query Parts () Query: UseBuilder:: execute () QueryorBuilder:: execute Query () Querydirectly.Builder:: execute Statement () Query: UsingBuilder:: set Max Results () (int)0asmax resultwill no longer work and retrieve no records. UseNULLinstead to allow all results.
Signature changes:
Query: Second argument has been dropped and the value must now be of typeBuilder:: quote (string $value) string.
Impact
Calling any of the mentioned removed methods will result in a PHP error. Also signature changes introducing type hint will result in a PHP error if called with an invalid type.
Affected installations
Only those installations that use the mentioned methods.
Migration
Extension author need to replace the removed methods with the alternatives which
        QueryBuilder::add('query-part-name')      
            
    Use the direct set/select methods instead:
| before | after | 
|---|---|
        ->add |             
        ->select |     
        ->add |             
        ->where |     
        ->add |             
        ->having |     
        ->add |             
        ->order |     
        ->add |             
        ->group |     
Note
This can be done already in TYPO3 v12 with at least Doctrine DBAL 3.8.
        QueryBuilder::resetQueryParts()      and 
        QueryBuilder::resetQueryPart()      
            
    However, several replacements have been put in place depending on the
        $query parameter:
| before | after | 
|---|---|
| 'select' | Call 
        ->select with a new set of columns |     
| 'distinct' | 
        ->distinct |     
| 'where' | 
        ->reset |     
| 'having' | 
        ->reset |     
| 'groupBy' | 
        ->reset |     
| 'orderBy | 
        ->reset |     
| 'values' | Call 
        ->values with a new set of values. |     
Note
This can be done already in TYPO3 v12 with at least Doctrine DBAL 3.8.
        QueryBuilder::execute()    
            
    Doctrine DBAL 4 removed 
        Query in favour of the two
methods 
        Query for select/count and 
        Query
for insert, delete and update queries.
Before
use TYPO3\CMS\Core\Database\ConnectionPool;
// select query
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
  ->getQueryBuilderForTable('pages');
$rows = $queryBuilder
    ->select('*')
    ->from('pages')
    ->execute()
    ->fetchAllAssociative();
// delete query
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
  ->getQueryBuilderForTable('pages');
$deletedRows = (int)$queryBuilder
    ->delete('pages')
    ->where(
      $queryBuilder->expr()->eq('pid', $this->createNamedParameter(123),
    )
    ->execute();
    After
use TYPO3\CMS\Core\Database\ConnectionPool;
// select query
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
  ->getQueryBuilderForTable('pages');
$rows = $queryBuilder
    ->select('*')
    ->from('pages')
    ->executeQuery()
    ->fetchAllAssociative();
// delete query
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
  ->getQueryBuilderForTable('pages');
$deletedRows = (int)$queryBuilder
    ->delete('pages')
    ->where(
      $queryBuilder->expr()->eq('pid', $this->createNamedParameter(123),
    )
    ->executeStatement();
    
        QueryBuilder::quote(string $value)    
            
    
        quote uses 
        Connection:: and therefore adopts the changed
signature and behaviour.
Before
use TYPO3\CMS\Core\Database\Connection as Typo3Connection;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Utility\GeneralUtility;
// select query
$pageId = 123;
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
    ->getQueryBuilderForTable('pages');
$rows = $queryBuilder
    ->select('*')
    ->from('pages')
    ->where(
        $queryBuilder->expr()->eq(
            'uid',
            $queryBuilder->quote($pageId, Typo3Connection::PARAM_INT)
        ),
    )
    ->executeQuery()
    ->fetchAllAssociative();
    After
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Utility\GeneralUtility;
// select query
$pageId = 123;
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
    ->getQueryBuilderForTable('pages');
$rows = $queryBuilder
    ->select('*')
    ->from('pages')
    ->where(
        $queryBuilder->expr()->eq(
            'uid',
            $queryBuilder->quote((string)$pageId)
        ),
    )
    ->executeQuery()
    ->fetchAllAssociative();
    Tip
To provide TYPO3 v12 and v13 with one code base, 
        ->quote
can be used to ensure dual Core compatibility.
        QueryBuilder::setMaxResults()      
            
    Using (int)0 as max result will no longer work and retrieve no records.
Use NULL instead to allow all results.
Before
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Utility\GeneralUtility;
// select query
$pageId = 123;
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
    ->getQueryBuilderForTable('pages');
$rows = $queryBuilder
    ->select('*')
    ->from('pages')
    ->setFirstResult(0)
    ->setMaxResults(0)
    ->executeQuery()
    ->fetchAllAssociative();
    After
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Utility\GeneralUtility;
// select query
$pageId = 123;
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
    ->getQueryBuilderForTable('pages');
$rows = $queryBuilder
    ->select('*')
    ->from('pages')
    ->setFirstResult(0)
    ->setMaxResults(null)
    ->executeQuery()
    ->fetchAllAssociative();