Doctrine - How to print out the real sql, not just the prepared statement?

后端 未结 19 2187
自闭症患者
自闭症患者 2020-11-30 18:59

We\'re using Doctrine, a PHP ORM. I am creating a query like this:

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

相关标签:
19条回答
  • 2020-11-30 19:37

    I have created a Doctrine2 Logger that does exactly this. It "hydrates" the parametrized sql query with the values using Doctrine 2 own data type conversors.

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

    Usage Example:; The following peace of code will echo on standard output any INSERT,UPDATE,DELETE SQL sentences generated with $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
                            )
                        )
                    );
    
    0 讨论(0)
  • 2020-11-30 19:37

    More clear solution:

     /**
     * 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);
    }
    
    0 讨论(0)
  • 2020-11-30 19:39

    I made some research for this topic, because i wanted to debug a generated SQL query and execute it in the sql editor. As seen in all the answers, it is a highly technical topic.

    When i assume that the initial question is base on dev-env, one very simple answer is missing at the moment. You can just use the build in Symfony profiler. Just click on the Doctrine Tab, Scroll to the query you want to inspect. Then click on "view runnable query" and you can paste your query directly in your SQL editor

    More UI base approach but very quick and without debugging code overhead.

    0 讨论(0)
  • 2020-11-30 19:41

    My solution:

     /**
     * 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;}
    

    Example of usage:

    $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());
    
    0 讨论(0)
  • 2020-11-30 19:42
    $sql = $query->getSQL();
    
    $parameters = [];
        foreach ($query->getParameters() as $parameter) {
            $parameters[] = $parameter->getValue();
        }
    
    $result = $connection->executeQuery($sql, $parameters)
            ->fetchAll();
    
    0 讨论(0)
  • 2020-11-30 19:44

    I wrote a simple logger, which can log query with inserted parameters. Installation:

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

    Usage:

    $connection = $this->getEntityManager()->getConnection(); 
    $logger = new \Cmyker\DoctrineSqlLogger\Logger($connection);
    $connection->getConfiguration()->setSQLLogger($logger);
    //some query here
    echo $logger->lastQuery;
    
    0 讨论(0)
提交回复
热议问题