Доктрина - Как распечатать настоящий sql, а не только подготовленное заявление? - PullRequest
148 голосов
/ 19 января 2010

Мы используем Doctrine, PHP ORM. Я создаю запрос как этот:

$q = Doctrine_Query::create()->select('id')->from('MyTable');

, а затем в функцию, которую я добавляю, в различных выражениях where и прочем, в зависимости от ситуации, например,

$q->where('normalisedname = ? OR name = ?', array($string, $originalString));

Позже, перед тем, как execute() -изложить этот объект запроса, я хочу распечатать необработанный SQL, чтобы изучить его, и сделать это:

$q->getSQLQuery();

Однако это выводит только подготовленный оператор, а не полный запрос. Я хочу посмотреть, что он отправляет в MySQL, но вместо этого он печатает подготовленный оператор, включая ?. Есть ли способ увидеть «полный» запрос?

Ответы [ 15 ]

147 голосов
/ 19 января 2010

Doctrine не отправляет «реальный запрос SQL» на сервер базы данных: оно фактически использует подготовленные операторы, что означает:

  • Отправка заявления, для его подготовки (вот что возвращает $query->getSql())
  • А затем отправка параметров (возвращается $query->getParameters())
  • и выполнение подготовленных заявлений

Это означает, что на стороне PHP никогда не существует «реального» SQL-запроса, поэтому Doctrine не может его отобразить.

84 голосов
/ 05 ноября 2012

Пример ..

$qb = $this->createQueryBuilder('a');
$query=$qb->getQuery();

Показать SQL: $sql=$query->getSQL();

Показать параметры: $parameters=$query->getParameters();

34 голосов
/ 27 октября 2011

Вы можете проверить запрос, выполняемый вашим приложением, если вы зарегистрируете все запросы в mysql:

http://dev.mysql.com/doc/refman/5.1/en/query-log.html

будет больше запросов, не только тот, который вы ищете, но вы можете grep для него.

но обычно ->getSql(); работает

Edit:

для просмотра всех запросов mysql, которые я использую

sudo vim /etc/mysql/my.cnf 

и добавьте эти 2 строки:

general_log = on
general_log_file = /tmp/mysql.log

и перезапустите mysql

16 голосов
/ 05 сентября 2013

Я создал Doctrine2 Logger, который делает именно это.Он «гидратирует» параметризованный SQL-запрос со значениями, используя собственные типы данных Doctrine 2.

<?php


namespace Drsm\Doctrine\DBAL\Logging;
use Doctrine\DBAL\Logging\SQLLogger,
    Doctrine\DBAL\Types\Type,
    Doctrine\DBAL\Platforms\AbstractPlatform;
/**
 * A SQL logger that logs to the standard output and
 * subtitutes params to get a ready to execute SQL sentence

 * @author  dsamblas@gmail.com
 */
class EchoWriteSQLWithoutParamsLogger implements SQLLogger

{
    const QUERY_TYPE_SELECT="SELECT";
    const QUERY_TYPE_UPDATE="UPDATE";
    const QUERY_TYPE_INSERT="INSERT";
    const QUERY_TYPE_DELETE="DELETE";
    const QUERY_TYPE_CREATE="CREATE";
    const QUERY_TYPE_ALTER="ALTER";

    private $dbPlatform;
    private $loggedQueryTypes;
    public function __construct(AbstractPlatform $dbPlatform, array $loggedQueryTypes=array()){
        $this->dbPlatform=$dbPlatform;
        $this->loggedQueryTypes=$loggedQueryTypes;
    }
    /**
     * {@inheritdoc}
     */
    public function startQuery($sql, array $params = null, array $types = null)

    {
        if($this->isLoggable($sql)){
            if(!empty($params)){
                foreach ($params as $key=>$param) {
                    $type=Type::getType($types[$key]);
                    $value=$type->convertToDatabaseValue($param,$this->dbPlatform);
                    $sql = join(var_export($value, true), explode('?', $sql, 2));
                }

            }
            echo $sql . " ;".PHP_EOL;
        }
    }

    /**
     * {@inheritdoc}
     */
    public function stopQuery()
    {

    }
    private function isLoggable($sql){
        if (empty($this->loggedQueryTypes)) return true;
        foreach($this->loggedQueryTypes as $validType){
            if (strpos($sql, $validType) === 0) return true;
        }
        return false;
    }
}

Пример использования :;Следующий фрагмент кода будет отображаться при стандартном выводе любых предложений SQL INSERT, UPDATE, DELETE SQL, сгенерированных с помощью $ em Entity Manager,

/**@var  \Doctrine\ORM\EntityManager $em */
$em->getConnection()
                ->getConfiguration()
                ->setSQLLogger(
                    new EchoWriteSQLWithoutParamsLogger(
                        $em->getConnection()->getDatabasePlatform(),
                        array(
                            EchoWriteSQLWithoutParamsLogger::QUERY_TYPE_UPDATE,
                            EchoWriteSQLWithoutParamsLogger::QUERY_TYPE_INSERT,
                            EchoWriteSQLWithoutParamsLogger::QUERY_TYPE_DELETE
                        )
                    )
                );
13 голосов
/ 14 мая 2012

getSqlQuery() технически показывает всю команду SQL, но гораздо полезнее, когда вы также можете видеть параметры.

echo $q->getSqlQuery();
foreach ($q->getFlattenedParams() as $index => $param)
  echo "$index => $param";

Чтобы сделать этот шаблон более пригодным для повторного использования, есть хороший подход, описанный в комментариях в Raw SQL из Doctrine Query Object .

13 голосов
/ 19 января 2010

Других реальных запросов не существует, так работают подготовленные операторы.Значения связаны на сервере базы данных, а не на уровне приложений.

См. Мой ответ на этот вопрос: Как проверить окончательный параметризованный запрос SQL в PHP с помощью PDO?

(повторяется здесь для удобства:)

Использование подготовленных операторов с параметризованными значениями - это не просто еще один способ динамического создания строки SQL.Вы создаете подготовленный оператор в базе данных, а затем отправляете только значения параметров.

Так что, вероятно, в базу данных будут отправлены PREPARE ..., затем SET ... и, наконец, EXECUTE ....

Вы не сможете получить некоторую строку SQL, такую ​​как SELECT * FROM ..., даже если она выдаст эквивалентные результаты, поскольку такой запрос фактически никогда не отправлялся в базу данных.

8 голосов
/ 23 декабря 2014

Мое решение:

 /**
 * Get SQL from query
 * 
 * @author Yosef Kaminskyi 
 * @param QueryBilderDql $query
 * @return int
 */
public function getFullSQL($query)
{
    $sql = $query->getSql();
    $paramsList = $this->getListParamsByDql($query->getDql());
    $paramsArr =$this->getParamsArray($query->getParameters());
    $fullSql='';
    for($i=0;$i<strlen($sql);$i++){
        if($sql[$i]=='?'){
            $nameParam=array_shift($paramsList);

            if(is_string ($paramsArr[$nameParam])){
                $fullSql.= '"'.addslashes($paramsArr[$nameParam]).'"';
             }
            elseif(is_array($paramsArr[$nameParam])){
                $sqlArr='';
                foreach ($paramsArr[$nameParam] as $var){
                    if(!empty($sqlArr))
                        $sqlArr.=',';

                    if(is_string($var)){
                        $sqlArr.='"'.addslashes($var).'"';
                    }else
                        $sqlArr.=$var;
                }
                $fullSql.=$sqlArr;
            }elseif(is_object($paramsArr[$nameParam])){
                switch(get_class($paramsArr[$nameParam])){
                    case 'DateTime':
                             $fullSql.= "'".$paramsArr[$nameParam]->format('Y-m-d H:i:s')."'";
                          break;
                    default:
                        $fullSql.= $paramsArr[$nameParam]->getId();
                }

            }
            else                     
                $fullSql.= $paramsArr[$nameParam];

        }  else {
            $fullSql.=$sql[$i];
        }
    }
    return $fullSql;
}

 /**
 * Get query params list
 * 
 * @author Yosef Kaminskyi <yosefk@spotoption.com>
 * @param  Doctrine\ORM\Query\Parameter $paramObj
 * @return int
 */
protected function getParamsArray($paramObj)
{
    $parameters=array();
    foreach ($paramObj as $val){
        /* @var $val Doctrine\ORM\Query\Parameter */
        $parameters[$val->getName()]=$val->getValue();
    }

    return $parameters;
}
 public function getListParamsByDql($dql)
{
    $parsedDql = preg_split("/:/", $dql);
    $length = count($parsedDql);
    $parmeters = array();
    for($i=1;$i<$length;$i++){
        if(ctype_alpha($parsedDql[$i][0])){
            $param = (preg_split("/[' ' )]/", $parsedDql[$i]));
            $parmeters[] = $param[0];
        }
    }

    return $parmeters;}

Пример использования:

$query = $this->_entityRepository->createQueryBuilder('item');
$query->leftJoin('item.receptionUser','users');
$query->where('item.customerid = :customer')->setParameter('customer',$customer)
->andWhere('item.paymentmethod = :paymethod')->setParameter('paymethod',"Bonus");
echo $this->getFullSQL($query->getQuery());
7 голосов
/ 03 февраля 2015

Вы можете легко получить доступ к параметрам SQL, используя следующий подход.

   $result = $qb->getQuery()->getSQL();

   $param_values = '';  
   $col_names = '';   

   foreach ($result->getParameters() as $index => $param){              
            $param_values .= $param->getValue().',';
            $col_names .= $param->getName().',';
   } 

   //echo rtrim($param_values,',');
   //echo rtrim($col_names,',');    

Таким образом, если вы распечатали $param_values и $col_names, вы можете получить значения параметров, проходящие через sql и соответствующие имена столбцов.

Примечание: если $param возвращает массив, вам нужно повторить, так как параметры внутри IN (:?) обычно появляются как вложенный массив.

А пока, если вы нашли другой подход, будьте любезны поделиться с нами:)

Спасибо!

6 голосов
/ 08 октября 2013

Более понятное решение:

 /**
 * Get string query 
 * 
 * @param Doctrine_Query $query
 * @return string
 */
public function getDqlWithParams(Doctrine_Query $query){
    $vals = $query->getFlattenedParams();
    $sql = $query->getDql();
    $sql = str_replace('?', '%s', $sql);
    return vsprintf($sql, $vals);
}
5 голосов
/ 08 мая 2014

Вы можете использовать:

$query->getSQL();

Если вы используете MySQL, вы можете использовать Workbench для просмотра запущенных операторов SQL. Вы также можете использовать просмотр текущего запроса из mysql, используя следующую команду:

 SHOW FULL PROCESSLIST \G
...