Doctrine - comment imprimer le vrai sql, pas seulement la déclaration préparée?
nous utilisons la Doctrine, un ORM PHP. Je crée une requête comme celle-ci:
$q = Doctrine_Query::create()->select('id')->from('MyTable');
et puis dans la fonction j'ajoute dans diverses clauses où et les choses comme approprié, comme ceci
$q->where('normalisedname = ? OR name = ?', array($string, $originalString));
plus tard, avant execute()
- ing que l'objet d'interrogation, je veux imprimer le SQL brut afin de l'examiner, et faire ceci:
$q->getSQLQuery();
toutefois, que la seule impression de la déclaration préparée, pas la pleine requête. Je veux voir ce qu'il envoie au MySQL, mais à la place il imprime une déclaration préparée, y compris ?
's. Y a-t-il un moyen de voir la requête "complète"?
14 réponses
Doctrine n'envoie pas une "requête SQL réelle" au serveur de base de données : il utilise en fait des déclarations préparées, ce qui signifie:
- envoyer la déclaration, pour qu'elle soit préparée (c'est ce qui est retourné par
$query->getSql()
) - et, ensuite, l'envoi des paramètres (retournés par
$query->getParameters()
) - et l'exécution des déclarations préparées
cela signifie qu'il n'y a jamais de" vrai " SQL requête du côté de PHP-donc, Doctrine ne peut pas l'afficher.
un exemple..
$qb = $this->createQueryBuilder('a');
$query=$qb->getQuery();
Show SQL: $sql=$query->getSQL();
Afficher Les Paramètres: $parameters=$query->getParameters();
vous pouvez vérifier la requête exécutée par votre application si vous Enregistrez toutes les requêtes dans mysql:
http://dev.mysql.com/doc/refman/5.1/en/query-log.html
il y aura plus de requêtes non seulement celle que vous recherchez, mais vous pouvez la récupérer.
mais habituellement ->getSql();
travaux
Edit:
pour voir toutes les requêtes mysql que j'utilise
sudo vim /etc/mysql/my.cnf
et ajouter ces 2 lignes:
general_log = on
general_log_file = /tmp/mysql.log
et redémarrer mysql
j'ai créé un Logger Doctrine2 qui fait exactement cela. Il "hydrate" la requête SQL paramétrée avec les valeurs en utilisant Doctrine 2 propres types de données 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;
}
}
Exemple D'Utilisation:; La paix de code suivante résonnera sur la sortie standard toute insertion, mise à jour, suppression de phrases SQL générée avec le Gestionnaire D'entité $em,
/**@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
)
)
);
il n'y a pas d'autre requête réelle, c'est ainsi que les déclarations préparées fonctionnent. Les valeurs sont liées dans le serveur de base de données, pas dans la couche application.
voir ma réponse à cette question: en PHP avec PDO, Comment vérifier la requête paramétrée SQL finale?
(Répété ici par commodité:)
L'utilisation de déclarations préparées avec des valeurs paramétrées n'est pas simplement une autre façon de créez dynamiquement une chaîne de caractères SQL. Vous créez une instruction préparée à la base de données, puis envoyez les valeurs des paramètres seulement.
donc ce qui est probablement envoyé à la base de données sera un
PREPARE ...
, puisSET ...
et enfinEXECUTE ....
vous ne serez pas en mesure d'obtenir une chaîne SQL comme
SELECT * FROM ...
, même si elle produirait des résultats équivalents, parce qu'aucune telle requête n'a jamais été réellement envoyée à la base de données.
getSqlQuery()
montre techniquement toute la commande SQL, mais c'est beaucoup plus utile quand vous pouvez voir les paramètres aussi bien.
echo $q->getSqlQuery();
foreach ($q->getFlattenedParams() as $index => $param)
echo "$index => $param";
pour rendre ce motif plus réutilisable, il y a une belle approche décrite dans les commentaires à" 15197092020 "SQL brut de Doctrine Query Object .
solution plus claire:
/**
* 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);
}
ma 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;}
exemple d'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());
vous pouvez facilement accéder aux paramètres SQL en utilisant l'approche suivante.
$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,',');
donc si vous avez imprimé les $param_values
et $col_names
, vous pouvez obtenir les valeurs des paramètres en passant par le sql et les noms de colonne respectifs.
Note : Si $param
renvoie un tableau, vous devez le répéter, car les paramètres à l'intérieur de IN (:?)
viennent généralement comme un tableau imbriqué.
en attendant si vous avez trouvé un autre approche, veuillez avoir la gentillesse de partager avec nous :)
Merci!
vous pouvez utiliser:
$query->getSQL();
si vous utilisez MySQL, vous pouvez utiliser Workbench pour afficher les instructions SQL en cours d'exécution. Vous pouvez également utiliser view the running query à partir de mysql en utilisant ce qui suit :
SHOW FULL PROCESSLIST \G
peut-être peut-il être utile pour quelqu'un:
// 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;
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);
j'ai écrit un logger simple, qui peut log requête avec les paramètres insérés. Installation:
composer require cmyker/doctrine-sql-logger:dev-master
Utilisation:
$connection = $this->getEntityManager()->getConnection();
$logger = new \Cmyker\DoctrineSqlLogger\Logger($connection);
$connection->getConfiguration()->setSQLLogger($logger);
//some query here
echo $logger->lastQuery;
pour imprimer une requête SQL dans la Doctrine, utilisez:
$query->getResult()->getSql();