[DoctrineMongoDBBundle] made queries in profiler look like mongodb js shell code

This commit is contained in:
Kris Wallsmith 2011-03-10 10:16:06 -08:00
parent d59676fbb7
commit ec46c6e6c5

View File

@ -12,72 +12,212 @@
namespace Symfony\Bundle\DoctrineMongoDBBundle\Logger;
use Symfony\Component\HttpKernel\Log\LoggerInterface;
use Symfony\Component\Yaml\Yaml;
/**
* Logger for the Doctrine MongoDB ODM.
*
* The {@link logQuery()} method is configured as the logger callable in the
* service container.
*
* @author Kris Wallsmith <kris.wallsmith@symfony.com>
*/
class DoctrineMongoDBLogger
{
const LOG_PREFIX = 'MongoDB query: ';
protected $logger;
protected $nbQueries;
public function __construct(LoggerInterface $logger = null)
protected $prefix;
protected $queries;
protected $processed;
protected $formattedQueries;
protected $nbRealQueries;
/**
* Constructor.
*
* @param LoggerInterface $logger The Symfony logger
* @param string $prefix A prefix for messages sent to the Symfony logger
*/
public function __construct(LoggerInterface $logger = null, $prefix = 'MongoDB query: ')
{
$this->logger = $logger;
$this->nbQueries = 0;
}
public function logQuery($query)
{
++$this->nbQueries;
if (null !== $this->logger) {
$this->logger->info(static::LOG_PREFIX.static::formatQuery($query));
}
}
public function getNbQueries()
{
return $this->nbQueries;
}
public function getQueries()
{
if (null === $this->logger) {
return false;
}
$logger = $this->logger->getDebugLogger();
if (!$logger) {
return false;
}
$offset = strlen(static::LOG_PREFIX);
$mapper = function($log) use($offset)
{
if (0 === strpos($log['message'], DoctrineMongoDBLogger::LOG_PREFIX)) {
return substr($log['message'], $offset);
}
};
// map queries from logs, remove empty entries and re-index the array
return array_values(array_filter(array_map($mapper, $logger->getLogs())));
$this->prefix = $prefix;
$this->queries = array();
$this->processed = false;
}
/**
* Formats the supplied query array recursively.
* Logs a query.
*
* @param array $query All or part of a query array
* This method is configured as the logger callable in the service
* container.
*
* @return string A serialized object for the log
* @param array $query A query log array from Doctrine
*/
static protected function formatQuery(array $query, $array = true)
public function logQuery($query)
{
$this->queries[] = $query;
$this->processed = false;
if (null !== $this->logger) {
$this->logger->info($this->prefix.static::bsonEncode($query));
}
}
/**
* Returns the number of queries that have been logged.
*
* @return integer The number of queries logged
*/
public function getNbQueries()
{
if (!$this->processed) {
$this->processQueries();
}
return $this->nbRealQueries;
}
/**
* Returns a human-readable array of queries logged.
*
* @return array An array of queries
*/
public function getQueries()
{
if (!$this->processed) {
$this->processQueries();
}
return $this->formattedQueries;
}
/**
* Groups and formats query arrays.
*
* @param array $queries An array of query arrays
*
* @return array An array of human-readable queries
*/
protected function processQueries()
{
$this->formattedQueries = array();
$this->nbRealQueries = 0;
$grouped = array();
$ordered = array();
foreach ($this->queries as $query) {
$cursor = serialize($query['query']).serialize($query['fields']);
// append if issued from cursor (currently just "sort")
if (isset($query['sort'])) {
unset($query['query'], $query['fields']);
$grouped[$cursor][count($grouped[$cursor]) - 1][] = $query;
} else {
$grouped[$cursor][] = array($query);
$ordered[] =& $grouped[$cursor][count($grouped[$cursor]) - 1];
}
}
$i = 0;
$db = '';
$query = '';
foreach ($ordered as $logs) {
foreach ($logs as $log) {
if (isset($log['db']) && $db != $log['db']) {
// for readability
$this->formattedQueries[$i++] = 'use '.$log['db'].';';
$db = $log['db'];
}
if (isset($log['collection'])) {
// flush the previous and start a new query
if (!empty($query)) {
if ('.' == $query[0]) {
$query = 'db'.$query;
}
$this->formattedQueries[$i++] = $query.';';
++$this->nbRealQueries;
}
$query = 'db.'.$log['collection'];
}
// format the method call
if (isset($log['authenticate'])) {
$query .= '.authenticate()';
} elseif (isset($log['batchInsert'])) {
$query .= '.batchInsert(**'.$log['num'].' item(s)**)';
} elseif (isset($log['command'])) {
$query .= '.command()';
} elseif (isset($log['count'])) {
$query .= '.count(';
if ($log['query'] || $log['limit'] || $log['skip']) {
$query .= static::bsonEncode($log['query']);
if ($log['limit'] || $log['skip']) {
$query .= ', '.static::bsonEncode($log['limit']);
if ($log['skip']) {
$query .= ', '.static::bsonEncode($log['skip']);
}
}
}
$query .= ')';
} elseif (isset($log['createCollection'])) {
$query .= '.createCollection()';
} elseif (isset($log['createDBRef'])) {
$query .= '.createDBRef()';
} elseif (isset($log['deleteIndex'])) {
$query .= '.dropIndex('.static::bsonEncode($log['keys']).')';
} elseif (isset($log['deleteIndexes'])) {
$query .= '.dropIndexes()';
} elseif (isset($log['drop'])) {
$query .= '.drop()';
} elseif (isset($log['dropDatabase'])) {
$query .= '.dropDatabase()';
} elseif (isset($log['ensureIndex'])) {
$query .= '.ensureIndex('.static::bsonEncode($log['keys']).', '.static::bsonEncode($log['options']).')';
} elseif (isset($log['execute'])) {
$query .= '.execute()';
} elseif (isset($log['find'])) {
$query .= '.find('.static::bsonEncode($log['query']);
if (!empty($log['fields'])) {
$query .= ', '.static::bsonEncode($log['fields']);
}
$query .= ')';
} elseif (isset($log['findOne'])) {
$query .= '.findOne('.static::bsonEncode($log['query']);
if (!empty($log['fields'])) {
$query .= ', '.static::bsonEncode($log['fields']);
}
$query .= ')';
} elseif (isset($log['getDBRef'])) {
$query .= '.getDBRef()';
} elseif (isset($log['group'])) {
$query .= '.group('.static::bsonEncode(array(
'keys' => $log['keys'],
'initial' => $log['initial'],
'reduce' => $log['reduce'],
)).')';
} elseif (isset($log['insert'])) {
$query .= '.insert('.static::bsonEncode($log['document']).')';
} elseif (isset($log['remove'])) {
$query .= '.remove('.static::bsonEncode($log['query']).')';
} elseif (isset($log['save'])) {
$query .= '.save('.static::bsonEncode($log['document']).')';
} elseif (isset($log['sort'])) {
$query .= '.sort('.static::bsonEncode($log['sortFields']).')';
} elseif (isset($log['update'])) {
// todo: include $log['options']
$query .= '.update('.static::bsonEncode($log['query']).', '.static::bsonEncode($log['newObj']).')';
} elseif (isset($log['validate'])) {
$query .= '.validate()';
}
}
}
}
static protected function bsonEncode($query, $array = true)
{
$parts = array();
@ -91,7 +231,7 @@ class DoctrineMongoDBLogger
} elseif (is_scalar($value)) {
$formatted = '"'.$value.'"';
} elseif (is_array($value)) {
$formatted = static::formatQuery($value);
$formatted = static::bsonEncode($value);
} elseif ($value instanceof \MongoId) {
$formatted = 'ObjectId("'.$value.'")';
} elseif ($value instanceof \MongoDate) {
@ -107,7 +247,7 @@ class DoctrineMongoDBLogger
} elseif ($value instanceof \MongoBinData) {
$formatted = 'new BinData("'.$value->bin.'", "'.$value->type.'")';
} elseif ($value instanceof \stdClass) {
$formatted = static::formatQuery((array) $value, false);
$formatted = static::bsonEncode((array) $value);
} else {
$formatted = (string) $value;
}