265 lines
7.5 KiB
ReStructuredText
265 lines
7.5 KiB
ReStructuredText
.. include:: /Includes.rst.txt
|
|
|
|
.. _breaking-102875-1705944493:
|
|
|
|
========================================
|
|
Breaking: #102875 - QueryBuilder changes
|
|
========================================
|
|
|
|
See :issue:`102875`
|
|
|
|
Description
|
|
===========
|
|
|
|
Doctrine DBAL 4 removed methods from the :php:`QueryBuilder` which has been
|
|
adopted to the extended :php:`\TYPO3\CMS\Core\Database\Query\QueryBuilder`.
|
|
|
|
Removed methods:
|
|
|
|
* :php:`QueryBuilder::add()`: Use new reset methods and normal set methods
|
|
instead.
|
|
* :php:`QueryBuilder::getQueryPart($partName)`: No replacement, internal state.
|
|
* :php:`QueryBuilder::getQueryParts()`: No replacement, internal state.
|
|
* :php:`QueryBuilder::resetQueryPart($partName)`: Replacement methods has been added,
|
|
see list.
|
|
* :php:`QueryBuilder::resetQueryParts()`: Replacement methods has been added,
|
|
see list.
|
|
* :php:`QueryBuilder::execute()`: Use :php:`QueryBuilder::executeQuery()` or
|
|
:php:`QueryBuilder::executeStatement()` directly.
|
|
* :php:`QueryBuilder::setMaxResults()`: Using `(int)0` as `max result` will
|
|
no longer work and retrieve no records. Use `NULL` instead to allow all
|
|
results.
|
|
|
|
Signature changes:
|
|
|
|
* :php:`QueryBuilder::quote(string $value)`: Second argument has been dropped
|
|
and the value must now be of type :php:`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
|
|
|
|
|
|
:php:`QueryBuilder::add('query-part-name')`
|
|
-------------------------------------------
|
|
|
|
Use the direct set/select methods instead:
|
|
|
|
.. csv-table:: Replacements
|
|
:header: "before", "after"
|
|
|
|
":php:`->add('select', $array)`", ":php:`->select(...$array)`"
|
|
":php:`->add('where', $wheres)`", ":php:`->where(...$wheres)`"
|
|
":php:`->add('having', $havings)`", ":php:`->having(...$havings)`"
|
|
":php:`->add('orderBy', $orderBy)`", ":php:`->orderBy($orderByField, $orderByDirection)->addOrderBy($orderByField2)`"
|
|
":php:`->add('groupBy', $groupBy)`", ":php:`->groupBy($groupField)->addGroupBy($groupField2)`"
|
|
|
|
.. note::
|
|
This can be done already in TYPO3 v12 with at least Doctrine DBAL 3.8.
|
|
|
|
:php:`QueryBuilder::resetQueryParts()` and :php:`QueryBuilder::resetQueryPart()`
|
|
--------------------------------------------------------------------------------
|
|
|
|
However, several replacements have been put in place depending on the
|
|
:php:`$queryPartName` parameter:
|
|
|
|
.. csv-table:: Replacements
|
|
:header: "before", "after"
|
|
|
|
"'select'", "Call :php:`->select()` with a new set of columns"
|
|
"'distinct'", ":php:`->distinct(false)`"
|
|
"'where'", ":php:`->resetWhere()`"
|
|
"'having'", ":php:`->resetHaving()`"
|
|
"'groupBy'", ":php:`->resetGroupBy()`"
|
|
"'orderBy", ":php:`->resetOrderBy()`"
|
|
"'values'", "Call :php:`->values()` with a new set of values."
|
|
|
|
.. note::
|
|
This can be done already in TYPO3 v12 with at least Doctrine DBAL 3.8.
|
|
|
|
:php:`QueryBuilder::execute()`
|
|
------------------------------
|
|
|
|
Doctrine DBAL 4 removed :php:`QueryBuilder::execute()` in favour of the two
|
|
methods :php:`QueryBuilder::executeQuery()` for select/count and :php:`QueryBuilder::executeStatement()`
|
|
for insert, delete and update queries.
|
|
|
|
Before
|
|
~~~~~~
|
|
|
|
.. code-block:: php
|
|
:emphasize-lines: 9,20
|
|
|
|
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
|
|
~~~~~
|
|
|
|
.. code-block:: php
|
|
:emphasize-lines: 9,20
|
|
|
|
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();
|
|
|
|
:php:`QueryBuilder::quote(string $value)`
|
|
-----------------------------------------
|
|
|
|
:php:`quote()` uses :php:`Connection::quote()` and therefore adopts the changed
|
|
signature and behaviour.
|
|
|
|
Before
|
|
~~~~~~
|
|
|
|
.. code-block:: php
|
|
:emphasize-lines: 15
|
|
|
|
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
|
|
~~~~~
|
|
|
|
.. code-block:: php
|
|
:emphasize-lines: 14
|
|
|
|
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, :php:`->quote((string)$value)`
|
|
can be used to ensure dual Core compatibility.
|
|
|
|
:php:`QueryBuilder::setMaxResults()`
|
|
------------------------------------
|
|
|
|
Using `(int)0` as `max result` will no longer work and retrieve no records.
|
|
Use `NULL` instead to allow all results.
|
|
|
|
Before
|
|
~~~~~~
|
|
|
|
.. code-block:: php
|
|
:emphasize-lines: 12
|
|
|
|
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
|
|
~~~~~
|
|
|
|
.. code-block:: php
|
|
:emphasize-lines: 12
|
|
|
|
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();
|
|
|
|
|
|
.. index:: Database, PHP-API, NotScanned, ext:core
|