Я использую Symfony 3.4.6 + Doctrine - это мои основные «инструменты».
Два идентичных запроса, написанных в MySQL, дают разные результаты. Почему? Я не знаю. Надеюсь, кто-нибудь мне поможет.
Первый (рабочая версия):
$connection = $this->getEntityManager()->getConnection();
$result = $connection->fetchAll('
SELECT *
FROM payment_transaction
LEFT JOIN `user` ON `user`.`id` = payment_transaction.from_id
WHERE payment_transaction.to_id = :user
AND payment_transaction.type IN ("' . implode('", "', $type) . '")
AND payment_transaction.registered_at >= :from
AND payment_transaction.registered_at <= :to
', [
"user" => $user->getId(),
"from" => $from->format("Y-m-d H:i:s"),
"to" => $to->format("Y-m-d H:i:s"),
]);
Второй (дает неверные результаты):
$connection = $this->getEntityManager()->getConnection();
$result = $connection->fetchAll('
SELECT *
FROM payment_transaction
LEFT JOIN `user` ON `user`.`id` = payment_transaction.from_id
WHERE payment_transaction.to_id = :user
AND payment_transaction.type IN (:types)
AND payment_transaction.registered_at >= :from
AND payment_transaction.registered_at <= :to
', [
"user" => $user->getId(),
"from" => $from->format("Y-m-d H:i:s"),
"to" => $to->format("Y-m-d H:i:s"),
"types" => '"' . implode('", "', $type) . '"',
]);
Третий (дает неверные результаты):
$connection = $this->getEntityManager()->getConnection();
$result = $connection->fetchAll('
SELECT *
FROM payment_transaction
LEFT JOIN `user` ON `user`.`id` = payment_transaction.from_id
WHERE payment_transaction.to_id = :user
AND payment_transaction.type IN (:types)
AND payment_transaction.registered_at >= :from
AND payment_transaction.registered_at <= :to
', [
"user" => $user->getId(),
"from" => $from->format("Y-m-d H:i:s"),
"to" => $to->format("Y-m-d H:i:s"),
"types" => "\"" . implode("\", \"", $type) . "\"",
]);
Четвертый (выдает ошибку - Array to string conversion):
$connection = $this->getEntityManager()->getConnection();
$result = $connection->fetchAll('
SELECT *
FROM payment_transaction
LEFT JOIN `user` ON `user`.`id` = payment_transaction.from_id
WHERE payment_transaction.to_id = :user
AND payment_transaction.type IN (:types)
AND payment_transaction.registered_at >= :from
AND payment_transaction.registered_at <= :to
', [
"user" => $user->getId(),
"from" => $from->format("Y-m-d H:i:s"),
"to" => $to->format("Y-m-d H:i:s"),
"types" => $types,
]);
Если я заменяю :types результатами, сгенерированными функцией implode, второй и третий запросы работают нормально.
В чем проблема - IN? implode? Связывание?
Спасибо.
ОБНОВЛЕНИЕ (22:29)
Последний фрагмент кода:
public function history(User $user, \DateTime $from, \DateTime $to,
array $type = [PaymentTransaction::PAYMENT_TRANSACTION_TYPE_SYSTEM,
PaymentTransaction::PAYMENT_TRANSACTION_TYPE_PARTNERSHIP,
PaymentTransaction::PAYMENT_TRANSACTION_TYPE_PERSONAL]): array
{
$connection = $this->getEntityManager()->getConnection();
$result = $connection->fetchAll('
SELECT payment_transaction.*, `user`.`first_name` as `user_first_name`, `user`.`last_name` as `user_last_name`, `user`.`email` as `user_email`
FROM payment_transaction
LEFT JOIN `user` ON `user`.`id` = payment_transaction.from_id
WHERE payment_transaction.to_id = :user
AND payment_transaction.type IN (:types)
AND payment_transaction.registered_at >= :from
AND payment_transaction.registered_at <= :to
ORDER BY payment_transaction.id DESC
', [
"user" => $user->getId(),
"from" => $from->format("Y-m-d H:i:s"),
"to" => $to->format("Y-m-d H:i:s"),
"types" => $type,
], [
\PDO::PARAM_INT,
\PDO::PARAM_STR,
\PDO::PARAM_STR,
Connection::PARAM_STR_ARRAY,
]);
return $result;
}
И все равно выдает ошибку:
' with params [134, ["system"], "2018-02-28 21:24:47", "2018-03-30 21:24:47"]:
Notice: Array to string conversion
ОБНОВЛЕНИЕ (22:50)
Запрос работает после замены заполнителей знаками ?. Остается вопрос - ПОЧЕМУ не работает с :name-плейсхолдерами?
@MarkBaker, что, если я динамически создаю свой массив «типов» и мне нужно использовать его значения в предложении IN?






'... AND type IN (:types) ...' // sql query
Чтобы заархивировать его с помощью DBAL API, вам нужно привязать массив элементов как есть:
"types" => $types, // $types = ['A', 'B', 'C'] or [1, 2, 3]
передавая в качестве третьего аргумента тип этого:
Connection::PARAM_STR_ARRAY // or ::PARAM_INT_ARRAY for integer list
Пример:
use Doctrine\DBAL\Connection; // don't forget this
// ...
$connection = $this->getEntityManager()->getConnection();
$result = $connection->fetchAll('
SELECT *
FROM payment_transaction
LEFT JOIN `user` ON `user`.`id` = payment_transaction.from_id
WHERE payment_transaction.to_id = :user
AND payment_transaction.type IN (:types)
AND payment_transaction.registered_at >= :from
AND payment_transaction.registered_at <= :to
', [
"user" => $user->getId(),
"from" => $from->format("Y-m-d H:i:s"),
"to" => $to->format("Y-m-d H:i:s"),
"types" => $types,
], [
\PDO::PARAM_INT,
\PDO::PARAM_STR,
\PDO::PARAM_STR,
Connection::PARAM_STR_ARRAY,
]);
Я все еще получаю сообщение об ошибке: params [134, ["personal", "system"], "2018-02-28 21:16:55", "2018-03-30 21:16:55"]: уведомление : Преобразование массива в строку
$types - это многомерный массив?
заменил $types на "types" => ["system"] - та же ошибка.
Вы добавили Doctrine\DBAL\Connection?
Ага. все было добавлено.
пожалуйста, обновите свой вопрос последними изменениями, чтобы увидеть
Позвольте нам продолжить обсуждение в чате.
Решено заменой типов PDO на типы DBAL.
[
"userId" => $user->getId(),
"types" => $type,
"from" => $from->format("Y-m-d H:i:s"),
"to" => $to->format("Y-m-d H:i:s"),
], [
"userId" => Type::INTEGER,
"types" => Type::SIMPLE_ARRAY,
"from" => Type::STRING,
"to" => Type::STRING,
]
Спасибо Ocramius с GitHub: https://github.com/doctrine/doctrine2/issues/7166
Вам нужно связать отдельные значения в вашем списке IN; вы не можете просто связать весь массив как строку и ожидать, что он будет работать