Ver Fonte

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

Kris Wallsmith há 14 anos atrás
pai
commit
ec46c6e6c5

+ 173 - 33
src/Symfony/Bundle/DoctrineMongoDBBundle/Logger/DoctrineMongoDBLogger.php

@@ -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;
+        $this->prefix = $prefix;
+        $this->queries = array();
+        $this->processed = false;
     }
 
+    /**
+     * Logs a query.
+     *
+     * This method is configured as the logger callable in the service
+     * container.
+     *
+     * @param array $query A query log array from Doctrine
+     */
     public function logQuery($query)
     {
-        ++$this->nbQueries;
+        $this->queries[] = $query;
+        $this->processed = false;
 
         if (null !== $this->logger) {
-            $this->logger->info(static::LOG_PREFIX.static::formatQuery($query));
+            $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()
     {
-        return $this->nbQueries;
+        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 (null === $this->logger) {
-            return false;
+        if (!$this->processed) {
+            $this->processQueries();
         }
 
-        $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())));
+        return $this->formattedQueries;
     }
 
     /**
-     * Formats the supplied query array recursively.
+     * Groups and formats query arrays.
      *
-     * @param array $query All or part of a query array
+     * @param array $queries An array of query arrays
      *
-     * @return string A serialized object for the log
+     * @return array An array of human-readable queries
      */
-    static protected function formatQuery(array $query, $array = true)
+    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;
             }