Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document a non-deprecated way to interact with prepared statements #4673

Merged
merged 3 commits into from Jun 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
67 changes: 39 additions & 28 deletions docs/en/reference/data-retrieval-and-manipulation.rst
Expand Up @@ -89,7 +89,7 @@ are then replaced by their actual values in a second step (execute).
$sql = "SELECT * FROM articles WHERE id = ?";
$stmt = $conn->prepare($sql);
$stmt->bindValue(1, $id);
$stmt->execute();
$resultSet = $stmt->executeQuery();

Placeholders in prepared statements are either simple positional question marks (``?``) or named labels starting with
a colon (e.g. ``:name1``). You cannot mix the positional and the named approach. You have to bind a parameter
Expand All @@ -108,7 +108,7 @@ position of the variable to bind into the ``bindValue()`` method:
$stmt = $conn->prepare($sql);
$stmt->bindValue(1, $id);
$stmt->bindValue(2, $status);
$stmt->execute();
$resultSet = $stmt->executeQuery();

Named parameters have the advantage that their labels can be re-used and only need to be bound once:

Expand All @@ -120,7 +120,7 @@ Named parameters have the advantage that their labels can be re-used and only ne
$sql = "SELECT * FROM users WHERE name = :name OR username = :name";
$stmt = $conn->prepare($sql);
$stmt->bindValue("name", $name);
$stmt->execute();
$resultSet = $stmt->executeQuery();

The following section describes the API of Doctrine DBAL with regard to prepared statements.

Expand Down Expand Up @@ -159,17 +159,28 @@ and methods to retrieve data from a statement.
- ``bindParam($pos, &$param, $type)`` - Bind a given reference to the positional or
named parameter in the prepared statement.

If you are finished with binding parameters you have to call ``execute()`` on the statement, which
will trigger a query to the database. After the query is finished you can access the results
of this query using the fetch API of a statement:
If you are finished with binding parameters you have to call ``executeQuery()`` on the statement,
which will trigger a query to the database. After the query is finished, a ``Doctrine\DBAL\Result``
instance is returned and you can access the results of this query using the fetch API of the result:

- ``fetch($fetchStyle)`` - Retrieves the next row from the statement or false if there are none.
- ``fetchNumeric()`` - Retrieves the next row from the statement or false if there are none.
The row is fetched as an array with numeric keys where the columns appear in the same order as
they were specified in the executed ``SELECT`` query.
Moves the pointer forward one row, so that consecutive calls will always return the next row.
- ``fetchColumn($column)`` - Retrieves only one column of the next row specified by column index.
- ``fetchAssociative()`` - Retrieves the next row from the statement or false if there are none.
The row is fetched as an associative array where the keys represent the column names as
specified in the executed ``SELECT`` query.
Moves the pointer forward one row, so that consecutive calls will always return the next row.
- ``fetchAll($fetchStyle)`` - Retrieves all rows from the statement.
- ``fetchOne()`` - Retrieves the value of the first column of the next row from the statement
or false if there are none.
Moves the pointer forward one row, so that consecutive calls will always return the next row.
- ``fetchAllNumeric()`` - Retrieves all rows from the statement as arrays with numeric keys.
- ``fetchAllAssociative()`` - Retrieves all rows from the statement as associative arrays.
- ``fetchFirstColumn()`` - Retrieves the value of the first column of all rows.

The fetch API of a prepared statement obviously works only for ``SELECT`` queries.
The fetch API of a prepared statement obviously works only for ``SELECT`` queries. If you want to
execute a statement that does not yield a result set, like ``INSERT``, ``UPDATE`` or ``DELETE``
for instance, you might want to call ``executeStatement()`` instead of ``executeQuery()``.

If you find it tedious to write all the prepared statement code you can alternatively use
the ``Doctrine\DBAL\Connection#executeQuery()`` and ``Doctrine\DBAL\Connection#executeStatement()``
Expand Down Expand Up @@ -201,7 +212,7 @@ to the appropriate vendors database format:
$date = new \DateTime("2011-03-05 14:00:21");
$stmt = $conn->prepare("SELECT * FROM articles WHERE publish_date > ?");
$stmt->bindValue(1, $date, "datetime");
$stmt->execute();
$resultSet = $stmt->executeQuery();

If you take a look at ``Doctrine\DBAL\Types\DateTimeType`` you will see that
parts of the conversion are delegated to a method on the current database platform,
Expand Down Expand Up @@ -238,7 +249,7 @@ Since you are using an ``IN`` expression you would really like to use it in the
$stmt = $conn->prepare('SELECT * FROM articles WHERE id IN (?)');
// THIS WILL NOT WORK:
$stmt->bindValue(1, array(1, 2, 3, 4, 5, 6));
$stmt->execute();
$resultSet = $stmt->executeQuery();

Implementing a generic way to handle this kind of query is tedious work. This is why most
developers fallback to inserting the parameters directly into the query, which can open
Expand Down Expand Up @@ -309,14 +320,14 @@ Prepare a given SQL statement and return the

<?php
$statement = $conn->prepare('SELECT * FROM user');
$statement->execute();
$users = $statement->fetchAllAssociative();
$resultSet = $statement->executeQuery();
$users = $resultSet->fetchAllAssociative();

/*
array(
0 => array(
'username' => 'jwage',
'password' => 'changeme'
'email' => 'j.wage@example.com'
)
)
*/
Expand All @@ -342,18 +353,18 @@ executeQuery()
~~~~~~~~~~~~~~

Creates a prepared statement for the given SQL and passes the
parameters to the execute method, then returning the statement:
parameters to the executeQuery method, then returning the result set:

.. code-block:: php

<?php
$statement = $conn->executeQuery('SELECT * FROM user WHERE username = ?', array('jwage'));
$user = $statement->fetchAssociative();
$resultSet = $conn->executeQuery('SELECT * FROM user WHERE username = ?', array('jwage'));
$user = $resultSet->fetchAssociative();

/*
array(
0 => 'jwage',
1 => 'changeme'
1 => 'j.wage@example.com'
)
*/

Expand All @@ -376,7 +387,7 @@ Execute the query and fetch all results into an array:
array(
0 => array(
'username' => 'jwage',
'password' => 'changeme'
'email' => 'j.wage@example.com'
)
)
*/
Expand All @@ -389,11 +400,11 @@ Execute the query and fetch the first two columns into an associative array as k
.. code-block:: php

<?php
$users = $conn->fetchAllKeyValue('SELECT username, password FROM user');
$users = $conn->fetchAllKeyValue('SELECT username, email FROM user');

/*
array(
'jwage' => 'changeme',
'jwage' => 'j.wage@example.com',
)
*/

Expand All @@ -409,13 +420,13 @@ an associative array of the rest of the columns and their values:
.. code-block:: php

<?php
$users = $conn->fetchAllAssociativeIndexed('SELECT id, username, password FROM user');
$users = $conn->fetchAllAssociativeIndexed('SELECT id, username, email FROM user');

/*
array(
1 => array(
'username' => 'jwage',
'password' => 'changeme',
'email' => 'j.wage@example.com'
)
)
*/
Expand All @@ -433,7 +444,7 @@ Numeric index retrieval of first result row of the given query:
/*
array(
0 => 'jwage',
1 => 'changeme'
1 => 'j.wage@example.com'
)
*/

Expand All @@ -460,7 +471,7 @@ Retrieve associative array of the first result row.
/*
array(
'username' => 'jwage',
'password' => 'changeme'
'email' => 'j.wage@example.com'
)
*/

Expand All @@ -474,7 +485,7 @@ Execute the query and iterate over the first two columns as keys and values resp
.. code-block:: php

<?php
foreach ($conn->iterateKeyValue('SELECT username, password FROM user') as $username => $password) {
foreach ($conn->iterateKeyValue('SELECT username, email FROM user') as $username => $email) {
// ...
}

Expand All @@ -490,7 +501,7 @@ an associative array of the rest of the columns and their values:
.. code-block:: php

<?php
foreach ($conn->iterateAssociativeIndexed('SELECT id, username, password FROM user') as $id => $data) {
foreach ($conn->iterateAssociativeIndexed('SELECT id, username, email FROM user') as $id => $data) {
// ...
}

Expand Down
6 changes: 3 additions & 3 deletions docs/en/reference/security.rst
Expand Up @@ -105,13 +105,13 @@ Following are examples of using prepared statements with SQL and DQL:
$sql = "SELECT * FROM users WHERE username = ?";
$stmt = $connection->prepare($sql);
$stmt->bindValue(1, $_GET['username']);
$stmt->execute();
$resultSet = $stmt->executeQuery();

// SQL Prepared Statements: Named
$sql = "SELECT * FROM users WHERE username = :user";
$stmt = $connection->prepare($sql);
$stmt->bindValue("user", $_GET['username']);
$stmt->execute();
$resultSet = $stmt->executeQuery();

// DQL Prepared Statements: Positional
$dql = "SELECT u FROM User u WHERE u.username = ?1";
Expand All @@ -133,7 +133,7 @@ are using just the DBAL there are also helper methods which simplify the usage q
<?php
// bind parameters and execute query at once.
$sql = "SELECT * FROM users WHERE username = ?";
$stmt = $connection->executeQuery($sql, array($_GET['username']));
$resultSet = $connection->executeQuery($sql, array($_GET['username']));

There is also ``executeStatement`` which does not return a statement but the number of affected rows.

Expand Down