Doctrine-Jak wydrukować prawdziwy SQL, a nie tylko przygotowane oświadczenie?

Używamy Doctrine, PHP ORM. Tworzę takie zapytanie:

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

A następnie w funkcji dodaję w różnych gdzie klauzule i rzeczy, jak to

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

Później, przed execute() - w tym obiekcie zapytania, chcę wydrukować surowy SQL, aby go zbadać, i zrobić to:

$q->getSQLQuery();

Jednak, że wypisuje tylko przygotowane oświadczenie, a nie pełne zapytanie. Chcę zobaczyć co wysyła do MySQL, ale zamiast tego drukuje czy jest jakiś sposób, aby zobaczyć "pełne" zapytanie?

Author: cpburnz, 2010-01-19

14 answers

Doctrine nie wysyła "prawdziwego zapytania SQL" do serwera bazy danych : w rzeczywistości używa gotowych instrukcji, co oznacza:

  • wysyłanie instrukcji, aby była przygotowana (to jest to, co jest zwracane przez $query->getSql())
  • i następnie wysyłanie parametrów (zwracanych przez $query->getParameters())
  • i wykonanie przygotowanych oświadczeń

Oznacza to, że nigdy nie ma "prawdziwego" zapytania SQL po stronie PHP - więc Doctrine nie może go wyświetlić.

 135
Author: Pascal MARTIN,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-01 00:30:36

Przykład..

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

Show SQL: $sql=$query->getSQL();

Pokaż Parametry: $parameters=$query->getParameters();

 74
Author: Andy.Diaz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-05 14:21:19

Możesz sprawdzić zapytanie wykonane przez Twoją aplikację, jeśli zarejestrujesz wszystkie zapytania w mysql:

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

Będzie więcej zapytań nie tylko tych, których szukasz, ale możesz je uzyskać.

Ale zazwyczaj ->getSql(); działa

Edit:

Aby wyświetlić wszystkie zapytania mysql używam

sudo vim /etc/mysql/my.cnf 

I dodaj te 2 linijki:

general_log = on
general_log_file = /tmp/mysql.log

I restart mysql

 31
Author: alex toader,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-09 08:36:58

Stworzyłem Logger Doctrine2, który robi dokładnie to. "Hydratuje" parametryzowane zapytanie sql z wartościami przy użyciu własnego typu danych 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  [email protected]
 */
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;
    }
}

Przykład Użycia:; Następujący spokój kodu będzie odbijał się echem na standardowym wyjściu każdego wstawiania,aktualizowania, usuwania zdań SQL wygenerowanych za pomocą $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
                        )
                    )
                );
 14
Author: dsamblas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-05 16:33:13

Nie ma innego prawdziwego zapytania, tak działają przygotowane instrukcje. Wartości są powiązane w serwerze bazy danych, a nie w warstwie aplikacji.

Zobacz moją odpowiedź na to pytanie: w PHP z PDO, jak sprawdzić ostateczne parametryzowane zapytanie SQL?

(powtórzone tutaj dla wygody:)

Używanie gotowych instrukcji z parametryzowanymi wartościami nie jest po prostu innym sposobem dynamicznego tworzenia ciągu SQL. Tworzysz przygotowane oświadczenie w bazie danych, a następnie wyślij same wartości parametrów.

Więc to, co prawdopodobnie zostanie wysłane do bazy danych, będzie PREPARE ..., następnie SET ... i wreszcie EXECUTE ....

Nie będziesz w stanie uzyskać jakiegoś ciągu SQL, takiego jak SELECT * FROM ..., nawet jeśli przyniosłoby to równoważne wyniki, ponieważ takie zapytanie nigdy nie zostało wysłane do bazy danych.

 13
Author: Ben James,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:26

getSqlQuery() technicznie pokazuje całe polecenie SQL, ale jest o wiele bardziej przydatne, gdy można zobaczyć parametry, jak również.

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

Aby uczynić ten wzór bardziej wielokrotnym, istnieje ładne podejście opisane w comments atRaw SQL from Doctrine Query Object .

 13
Author: ladenedge,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-14 04:59:16

Bardziej przejrzyste rozwiązanie:

 /**
 * 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);
}
 6
Author: dudapiotr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-08 07:32:14

Moje rozwiązanie:

 /**
 * 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 <[email protected]>
 * @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;}

Przykład użycia:

$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());
 6
Author: moledet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-23 14:03:00

Możesz łatwo uzyskać dostęp do parametrów SQL za pomocą następującego podejścia.

   $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,',');    

Więc jeśli wydrukowałeś $param_values i $col_names, możesz uzyskać wartości parametrów przechodzące przez SQL i odpowiednie nazwy kolumn.

Notatka: Jeśli $param zwróci tablicę, musisz ją ponownie powtórzyć, ponieważ parametry wewnątrz IN (:?) zwykle są w postaci zagnieżdżonej tablicy.

W międzyczasie, jeśli znalazłeś inne podejście, bądź uprzejmy i podziel się z nami:)

Dziękuję!

 6
Author: Anjana Silva,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-03 17:26:02

Możesz użyć :

$query->getSQL();

Jeśli używasz MySQL możesz użyć Workbench do wyświetlania uruchomionych poleceń SQL. Możesz również użyć widoku uruchomionego zapytania z mysql, używając następującego polecenia:

 SHOW FULL PROCESSLIST \G
 5
Author: lac_dev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-08 15:12:06

Może się komuś przyda:

// Printing the SQL with real values
$vals = $query->getFlattenedParams();
foreach(explode('?', $query->getSqlQuery()) as $i => $part) {
    $sql = (isset($sql) ? $sql : null) . $part;
    if (isset($vals[$i])) $sql .= $vals[$i];
}

echo $sql;
 4
Author: wcomnisky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-23 19:16:28
Solution:1
====================================================================================

function showQuery($query)
{
    return sprintf(str_replace('?', '%s', $query->getSql()), $query->getParams());
}

// call function  
echo showQuery($doctrineQuery);

Solution:2
====================================================================================

function showQuery($query)
{
    // define vars              
    $output    = NULL;
    $out_query = $query->getSql();
    $out_param = $query->getParams();

    // replace params
   for($i=0; $i<strlen($out_query); $i++) {
       $output .= ( strpos($out_query[$i], '?') !== FALSE ) ? "'" .str_replace('?', array_shift($out_param), $out_query[$i]). "'" : $out_query[$i];
   }

   // output
   return sprintf("%s", $output);
}

// call function  
echo showQuery($doctrineQueryObject);
 4
Author: Sandip Patel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-22 05:44:20

Napisałem prosty logger, który może rejestrować zapytania z wstawionymi parametrami. Instalacja:

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

Użycie:

$connection = $this->getEntityManager()->getConnection(); 
$logger = new \Cmyker\DoctrineSqlLogger\Logger($connection);
$connection->getConfiguration()->setSQLLogger($logger);
//some query here
echo $logger->lastQuery;
 1
Author: Cmyker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-13 09:42:52

Aby wydrukować zapytanie SQL w Doctrine, użyj:

$query->getResult()->getSql();
 0
Author: Jaydeep Patel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-27 22:58:21