我们使用Doctrine,一个PHP ORM。我创建了一个这样的查询:

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

然后在函数中,我添加了各种where子句和适当的东西,像这样

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

稍后,在execute()-ing该查询对象之前,我想打印出原始SQL以检查它,并这样做:

$q->getSQLQuery();

但是,这只打印准备好的语句,而不是完整的查询。我想看看它正在发送什么到MySQL,但相反,它正在打印一个准备好的语句,包括?是否有一些方法可以看到'full'查询?


当前回答

你可以通过将sql prepared语句与绑定结合来构建一个sql字符串,就像这样:

$sql = str_replace_array('?', $query->getBindings(), $query->toSql())
str_replace_array(string $search, array $replacement, string $subject): string

PHP的str_replace_array函数将$subject中的每个$search实例依次替换为$replacement数组中的值。

其他回答

我写了一个简单的日志记录器,它可以记录插入参数的查询。 安装:

composer require cmyker/doctrine-sql-logger:dev-master

用法:

$connection = $this->getEntityManager()->getConnection(); 
$logger = new \Cmyker\DoctrineSqlLogger\Logger($connection);
$connection->getConfiguration()->setSQLLogger($logger);
//some query here
echo $logger->lastQuery;

我已经创建了一个Doctrine2 Logger,它就是这样做的。它使用Doctrine 2自己的数据类型转换器将参数化sql查询与值“水合”起来。

<?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;
    }
}

使用例子:; 下面的代码将在标准输出中返回使用$em实体管理器生成的任何INSERT,UPDATE,DELETE SQL语句,

/**@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
                        )
                    )
                );

修改了@dsamblas函数,当参数是日期字符串(如'2019-01-01')时工作,并且当有使用IN传递的数组时工作

$qb->expr()->in('ps.code', ':activeCodes'),

. 所以做dsamblas写的所有事情,但是用这个替换startQuery,或者看看区别,然后添加我的代码。(以防他修改了他的功能,而我的版本没有修改)。

public function startQuery($sql, array $params = null, array $types = null)

{
    if($this->isLoggable($sql)){
        if(!empty($params)){
            foreach ($params as $key=>$param) {

                try {
                    $type=Type::getType($types[$key]);
                    $value=$type->convertToDatabaseValue($param,$this->dbPlatform);
                } catch (Exception $e) {
                    if (is_array($param)) {
                        // connect arrays like ("A", "R", "C") for SQL IN
                        $value = '"' . implode('","', $param) . '"';
                    } else {
                        $value = $param; // case when there are date strings
                    }
                }

                $sql = join(var_export($value, true), explode('?', $sql, 2));
            }

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

没有测试太多。

博士TL;

$qb = ... // your query builder
$query = $qb->getQuery();
// temporarily enable logging for your query (will also work in prod env)
$conf = $query->getEntityManager()->getConnection()->getConfiguration();
$backupLogger = $conf->getSQLLogger();
$logger = new \Doctrine\DBAL\Logging\DebugStack();
$conf->setSQLLogger($logger);
// execute query
$res = $query->getResult();
$conf->setSQLLogger($backupLogger); //restore logger for other queries
$params = [
  'query' => array_pop($logger->queries) //extract query log details
  //your other twig params here...
]
return $params; //send this to your twig template...

在你的枝条文件中,使用Doctrine的枝条助手过滤器:

// show raw query:
{{ (query.sql ~ ';')|doctrine_replace_query_parameters(query.params)
// highlighted
{{ (query.sql ~ ';')|doctrine_replace_query_parameters(query.params)|doctrine_pretty_query(highlight_only = true) }}
// highlighted and formatted (i.e. with tabs and newlines)
{{ (query.sql ~ ';')|doctrine_replace_query_parameters(query.params)|doctrine_pretty_query }}

解释:

其他的回答提到“准备好的语句实际上是“真正的查询”是对的,但它们并没有回答提问者的明显期望……每个开发人员都希望显示“可运行查询”以进行调试(或显示给用户)。

我查了一下Symfony profiler的源码看看他们是怎么做的。教义部分是Doctrine的责任,所以他们做了一个教义包来与Symfony集成。查看doctrine-bundle/Resources/views/Collector/db.html。枝条文件,你会发现他们是怎么做的(这可能会改变不同的版本)。有趣的是,他们创建了我们可以重用的细枝过滤器(见上文)。

为了使一切正常工作,我们需要为查询启用Logging。有多种方法可以做到这一点,在这里我使用了DebugStack,它允许记录查询而不实际打印它们。这也确保这将在生产模式下工作,如果这是你所需要的……

如果你需要进一步格式化,你会看到他们在一个样式标签中包含了一些CSS,所以简单地“窃取”它^^:

.highlight pre { margin: 0; white-space: pre-wrap; }
.highlight .keyword   { color: #8959A8; font-weight: bold; }
.highlight .word      { color: #222222; }
.highlight .variable  { color: #916319; }
.highlight .symbol    { color: #222222; }
.highlight .comment   { color: #999999; }
.highlight .backtick  { color: #718C00; }
.highlight .string    { color: #718C00; }
.highlight .number    { color: #F5871F; font-weight: bold; }
.highlight .error     { color: #C82829; }

希望这对你有帮助;-)

要打印出Doctrine中的SQL查询,请使用:

$query->getResult()->getSql();