Doctrine - Как связать массив с SQL?

Мой SQL выглядит примерно так:

$sql = "select * from user where id in (:userId) and status = :status";

$em = $this->getEntityManager();
$stmt = $em->getConnection()->prepare($sql);
$stmt->bindValue(':userId', $accounts, \Doctrine\DBAL\Connection::PARAM_INT_ARRAY);
$stmt->bindValue(':status', 'declined');
$stmt->execute();

$result = $stmt->fetchAll();

Но он возвращает:

Исключение произошло при выполнении (...)

с параметрами [[1,2,3,4,5,6,7,8,11,12,13,14], "отклонено" ]

Примечание. Преобразование массива в строку

Я не могу пользователь queryBuilder, потому что мой реальный SQL более сложный (например, содержит объединенные select, union и т.д.)

Ответ 1

Вы не можете использовать подготовленные операторы с массивами просто потому, что сам sql не поддерживает массивы. Какой настоящий позор. Где-то вдоль линии вам действительно нужно определить, содержат ли ваши данные, скажем, три элемента и испускают IN (?,?,?). Менеджер сущностей Doctrine ORM сделает это автоматически.

К счастью, DBAL покрыл вас. Вы просто не используете связывание или подготовку. В руководстве есть пример: https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/data-retrieval-and-manipulation.html#list-of-parameters-conversion

В вашем случае это будет выглядеть примерно так:

$sql = "select * from user where id in (?) and status = ?";
$values = [$accounts,'declined'];
$types = [Connection::PARAM_INT_ARRAY, \PDO::PARAM_STR];
$stmt = $conn->executeQuery($sql,$values,$types);
$result = $stmt->fetchAll();

Приведенный выше код не проверен, но вы должны понять. (Убедитесь, что вы use Doctrine\DBAL\Connection; для Connection::PARAM_INT_ARRAY)

Примечание для людей, использующих именованные параметры:

Если вы используете именованные параметры (:param вместо ?), Вы должны соблюдать имена параметров при предоставлении типов. Например:

$sql = "select * from user where id in (:accounts) and status = :status";
$values = ['accounts' => $accounts, 'status' => 'declined'];
$types = ['accounts' => Connection::PARAM_INT_ARRAY, 'status' => \PDO::PARAM_STR];

Ответ 2

Если вы хотите придерживаться синтаксиса :param, где порядок не имеет значения, вам нужно сделать немного дополнительной работы, но я покажу вам более простой способ привязки параметров:

// store all your parameters in one array
$params = array(
    ':status' => 'declined'
);

// then, using your arbitrary array of id ...
$array_of_ids = array(5, 6, 12, 14);

// ... we're going to build an array of corresponding parameter names
$id_params = array();
foreach ($array_of_ids as $i => $id) {
    // generate a unique name for this parameter
    $name = ":id_$i"; // ":id_0", ":id_1", etc.

    // set the value
    $params[$name] = $id;

    // and keep track of the name
    $id_params[] = $name;
}

// next prepare the parameter names for placement in the query string
$id_params = implode(',', $id_params); // ":id_0,:id_1,..."
$sql = "select * from user where id in ($id_params) and status = :status";

В этом случае мы получим: "select * from user where id in (:id_0,:id_1,:id_2,:id_3) and status = :status"

// now prepare your statement like before...
$stmt = $em->getConnection()->prepare($sql);

// ...bind all the params in one go...
$stmt->execute($params);

// ...and get your results!
$result = $stmt->fetchAll();

Этот подход также будет работать с массивом строк.

Ответ 3

Вам нужно обернуть их в массив

$stmt->bindValue(':userId', array($accounts), array(\Doctrine\DBAL\Connection::PARAM_INT_ARRAY));

http://doctrine-dbal.readthedocs.io/en/latest/reference/data-retrieval-and-manipulation.html#list-of-parameters-conversion

изменить

Я должен был уточнить больше. Вы не можете связать такой массив, не создавайте sql-исполнение непосредственно в качестве примера в документах.

$stmt = $conn->executeQuery('SELECT * FROM articles WHERE id IN (?)',
array(array(1, 2, 3, 4, 5, 6)),
array(\Doctrine\DBAL\Connection::PARAM_INT_ARRAY));

Вы не можете привязать массив значений в один подготовленный параметр оператора