DQL to Raw SQL

// Декабрь 3rd, 2010 // Doctrine, MySQL, PHP

Я довольно давно работаю с Doctrine ORM, и очень часто при отладке необходимо посмотреть, какой именно SQL запрос получается из DQL запроса. Для этого раньше я использовал $dql->getSqlQuery() вместе с $dql->getParams(). Первая команда отображает SQL-запрос плейсхолдерами («?») вместо переменных, а вторая собственно отображает массив переменных. Приходится смотреть туда-сюда, чтобы сопоставить их. Ладно если запрос маленький, а если большой — то это быстро утомляет.Немного покопавшись в коде, я нашел решение, которое хочу вам показать. Единственное требование, это наличие своего класса запроса. У нас он называется DoctrineExtra_Query, он является наследником Doctrine_Query. Также я сделал небольшие корректировки в других классах (которые тоже отнаследовал), чтобы DoctrineExtra_Query генерировался по умолчанию вместо встроенного в ответ на вызов $connection -> getQueryObject(). Пока писать не буду, но если ко-мунибудь будет интересно — спрашивайте в комментах — отвечу. Итак, собственно в классе DoctrineExtra_Query добавляем новую функцию getRawSql(). Вот её текст:

    /**
     * Возвращает сырой SQL-запрос на основе текущего DQL-запроса,
     * в контексте которого запускается
     */
    public function getRawSql()
    {
        $sql = $this->getSqlQuery();
        $flattenedParams = array_reverse($this->getFlattenedParams());
// переворачиваем массив, т.к. потом будем использовать array_pop()
        $value = array_pop($flattenedParams);
        while(!is_null($value)) {
            $sql = preg_replace("/\?/", $value, $sql, 1);
            $value = array_pop($flattenedParams);
        }
        return $sql;
    }

Как видите, ничего сложного нет, зато теперь отладка запрсоов будет на порядок удобнее.

Share

Спасибо!


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


10 Responses to “DQL to Raw SQL”

  1. neon:

    Случайно не знаете как можно посмотреть код который будет выполнен при save();

  2. neon:

    а как вызывать ваш метод?
    save()->getRawSql();

    • google.com Андрей Токарчук:

      Мой метод вызывается у класса DoctrineExtra_Query, который наследуется от Doctrine_Query. Вызов модели Doctrine_Record -> save() вызывает метод $conn->unitOfWork->saveGraph($this) затем вызывается один из следующих методов:

      $isValid = $this->replace($record);
      $isValid = $this->insert($record
      $isValid = $this->update($record);

      которые являются прокси-методами для объекта Connection.
      Внутри вы найдете такой код:

      $sql = ‘UPDATE ‘ . $this->quoteIdentifier($table->getTableName())
      . ‘ SET ‘ . implode(‘, ‘, $set)
      . ‘ WHERE ‘ . implode(‘ = ? AND ‘, $this->quoteMultipleIdentifier($table->getIdentifierColumnNames()))
      . ‘ = ?’;

      Это значит, что операция сохранения записи происходит без участия объекта Doctrine_Query, а значит мой метод неприменим.
      Но вы можете отнаследовать класс Doctrine_Connection и внедрить похожий метод туда.
      Тогда вы сможете смотреть, какие сырые запросы пойдут в базу при вызове $model->save().

  3. neon:

    подключить я так понял надо так:
    создаем класс и в нем метод getRawSql()
    class DoctrineExtra_Query extends Doctrine_Query
    {
    public function getRawSql()
    {…}
    }
    и вместо Doctrine_Query::create()->from(‘User’)->getSqlQuery();
    уже используем
    DoctrineExtra_Query::create()->from(‘User’)->getRawSql();

    • google.com Андрей Токарчук:

      Да можно так. И лучше ещё сразу переназначить DoctrineExtra_Query вместо встроенного класса Doctrine_Query вот так:

      $conn->setAttribute(Doctrine_Core::ATTR_QUERY_CLASS, ‘DoctrineExtra_Query’);
      где $conn — Doctrine_Connection

      • neon:

        Я в классе Doctrine_Query добавил ваш getRawSql() и теперь можно использовать оба на выбор :)

        • google.com Андрей Токарчук:

          Отлично! А Doctrine у вас случаем не через svn-externals подключен. А то при апдейте ваши изменения могут затареться. Да и вообще не рекомендуется изменять сторонние беблиотеки, а то и рпавда обновитесь, и не заметите, как перестанет работать.

Комментировать