Привязка значений не работает должным образом. Почему?

Я использую 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-плейсхолдерами?

Вам нужно связать отдельные значения в вашем списке IN; вы не можете просто связать весь массив как строку и ожидать, что он будет работать

Mark Baker 30.03.2018 20:58

@MarkBaker, что, если я динамически создаю свой массив «типов» и мне нужно использовать его значения в предложении IN?

AndrewShmig 30.03.2018 20:59
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
2
125
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

'... 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"]: уведомление : Преобразование массива в строку

AndrewShmig 30.03.2018 21:18

$types - это многомерный массив?

yceruto 30.03.2018 21:21

заменил $types на "types" => ["system"] - та же ошибка.

AndrewShmig 30.03.2018 21:24

Вы добавили Doctrine\DBAL\Connection?

yceruto 30.03.2018 21:25

Ага. все было добавлено.

AndrewShmig 30.03.2018 21:27

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

yceruto 30.03.2018 21:28

Позвольте нам продолжить обсуждение в чате.

yceruto 30.03.2018 21:37
Ответ принят как подходящий

Решено заменой типов 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

Другие вопросы по теме