Skip to content

Commit

Permalink
Upgrade to new MongoDB driver and library (PHP 7 support)
Browse files Browse the repository at this point in the history
  • Loading branch information
jmikola committed Jun 21, 2017
1 parent 415de4c commit 403e4e9
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 37 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
],
"require": {
"php": ">=5.4.0",
"ext-mongo": "^1.3",
"mongodb/mongodb": "^1.1",
"silex/silex": "^2.0",
"symfony/twig-bridge": "^3.3",
"twig/twig": "^1.34"
Expand Down
65 changes: 61 additions & 4 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

61 changes: 38 additions & 23 deletions src/MongoQP/QueryProfiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,49 +2,64 @@

namespace MongoQP;

use MongoDB\Client;
use MongoDB\BSON\Javascript;
use MongoDB\BSON\Regex;
use MongoDB\Driver\ReadPreference;
use MongoDB\Model\CollectionInfo;
use MongoDB\Model\DatabaseInfo;

class QueryProfiler
{
private $mongo;
private $client;
private $code;
private $timezone;

public function __construct(\MongoClient $mongo, array $code)
public function __construct(Client $client, array $code)
{
$this->mongo = $mongo;
$this->client = $client;
$this->code = $code;
$this->timezone = new \DateTimeZone(ini_get('date.timezone'));
}

public function getPrimaryHostAndPort()
{
$server = $this->client->getManager()->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));

return $server->getHost() . ':' . $server->getPort();
}

public function getDatabases()
{
return array_map(
function($database) { return $database['name']; },
$this->mongo->listDBs()['databases']
function(DatabaseInfo $databaseInfo) { return $databaseInfo->getName(); },
iterator_to_array($this->client->listDatabases())
);
}

public function getCollections($database)
{
return $this->mongo->selectDB($database)->getCollectionNames();
return array_map(
function(CollectionInfo $collectionInfo) { return $collectionInfo->getName(); },
iterator_to_array($this->client->selectDatabase($database)->listCollections())
);
}

public function getProfilingLevel($database)
{
return $this->mongo->selectDB($database)->getProfilingLevel();
return $this->client->selectDatabase($database)->command(['profile' => -1])->toArray()[0]['was'];
}

public function setProfilingLevel($database, $level)
{
$this->mongo->selectDB($database)->setProfilingLevel((int) $level);
$this->client->selectDatabase($database)->command(['profile' => (int) $level]);
}

public function getProfilingData($database, $collection = null)
{
$mongodb = $this->mongo->selectDB($database);
$database = $this->client->selectDatabase($database);

// Ensure the database has a "system.profile" collection
if ( ! in_array('system.profile', $mongodb->getCollectionNames(true))) {
return array();
if ( ! in_array('system.profile', $this->getCollections($database))) {
return [];
}

/* Exclude system collection queries. Commands, which are queries on the
Expand All @@ -54,27 +69,27 @@ public function getProfilingData($database, $collection = null)
* database prefix.
*/
$query = ['ns' => [
'$not' => new \MongoRegex('/^' . preg_quote("$database.system.") . '/'),
'$not' => new Regex('^' . preg_quote("$database.system.")),
'$in' => [
"$database.\$cmd",
isset($collection) ? "$database.$collection" : new \MongoRegex('/^' . preg_quote("$database.") . '/'),
],
]];

$rs = $mongodb->command([
$rs = $database->command([
'mapreduce' => 'system.profile',
'map' => $this->code['map'],
'reduce' => $this->code['reduce'],
'finalize' => $this->code['finalize'],
'map' => new Javascript($this->code['map']),
'reduce' => new Javascript($this->code['reduce']),
'finalize' => new Javascript($this->code['finalize']),
'out' => ['inline' => 1],
'query' => $query,
'scope' => [
'database' => $database,
'collection' => $collection,
'skeleton' => $this->code['skeleton'],
'skeleton' => new Javascript($this->code['skeleton']),
],
'jsMode' => true,
]);
])->toArray()[0];

if ( ! $rs['ok']) {
throw new \RuntimeException(
Expand All @@ -84,9 +99,9 @@ public function getProfilingData($database, $collection = null)
}

foreach ($rs['results'] as $i => $result) {
$rs['results'][$i] = $result['_id'] + $result['value'];
$rs['results'][$i]['ts']['min'] = new \DateTime('@' . $rs['results'][$i]['ts']['min']->sec);
$rs['results'][$i]['ts']['max'] = new \DateTime('@' . $rs['results'][$i]['ts']['max']->sec);
$rs['results'][$i] = $result['_id']->getArrayCopy() + $result['value']->getArrayCopy();
$rs['results'][$i]['ts']['min'] = $rs['results'][$i]['ts']['min']->toDateTime();
$rs['results'][$i]['ts']['max'] = $rs['results'][$i]['ts']['max']->toDateTime();
}

return $rs['results'];
Expand Down
21 changes: 13 additions & 8 deletions src/MongoQP/Silex/Provider/QueryProfilerServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace MongoQP\Silex\Provider;

use MongoDB\Client;
use MongoQP\QueryProfiler;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
Expand All @@ -10,20 +11,24 @@ class QueryProfilerServiceProvider implements ServiceProviderInterface
{
public function register(Container $app)
{
if (!isset($app['mongo'])) {
$app['mongo'] = function() { return new \MongoClient(); };
}
$app['mongodb.client'] = function() use ($app) {
return new Client(
$app['mongodb.client.uri'],
$app['mongodb.client.uriOptions'],
$app['mongodb.client.driverOptions']
);
};

$app['query.profiler'] = function() use ($app) {
$jsDir = __DIR__.'/../../../js';
$code = [
'map' => new \MongoCode(file_get_contents($jsDir.'/map.js')),
'reduce' => new \MongoCode(file_get_contents($jsDir.'/reduce.js')),
'finalize' => new \MongoCode(file_get_contents($jsDir.'/finalize.js')),
'skeleton' => new \MongoCode(file_get_contents($jsDir.'/skeleton.js')),
'map' => file_get_contents($jsDir.'/map.js'),
'reduce' => file_get_contents($jsDir.'/reduce.js'),
'finalize' => file_get_contents($jsDir.'/finalize.js'),
'skeleton' => file_get_contents($jsDir.'/skeleton.js'),
];

return new QueryProfiler($app['mongo'], $code);
return new QueryProfiler($app['mongodb.client'], $code);
};
}
}
3 changes: 3 additions & 0 deletions src/config.php.dist
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
<?php

$app['debug'] = false;
$app['mongodb.client.uri'] = null;
$app['mongodb.client.uriOptions'] = [];
$app['mongodb.client.driverOptions'] = [];
$app['twig.cache_dir'] = sys_get_temp_dir() . '/mongoqp-cache';
2 changes: 1 addition & 1 deletion src/views/layout.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<div class="page-header">
<div class="row-fluid">
<div class="span6"><h1>mongoqp: <small>a query profile viewer</small></h1></div>
<div class="span6 connection"><i class="icon-leaf"></i> {{ app.mongo }}</div>
<div class="span6 connection"><i class="icon-leaf"></i> {{ app["query.profiler"].primaryHostAndPort }}</div>
</div>
</div>
{% block content '' %}
Expand Down

0 comments on commit 403e4e9

Please sign in to comment.