Skip to content

Commit

Permalink
Adding basic collector for ZDT (using a simple DBAL SQLLogger)
Browse files Browse the repository at this point in the history
  • Loading branch information
Ocramius committed Aug 2, 2012
1 parent 5fb90e6 commit 8a4c279
Show file tree
Hide file tree
Showing 7 changed files with 294 additions and 5 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Expand Up @@ -11,7 +11,7 @@ before_script:
- rm config/application.config.php && cp ../DoctrineORMModule/.travis/application.config.php config/
- cp ../DoctrineORMModule/.travis/composer.json ./
- curl -s http://getcomposer.org/installer | php
- php composer.phar install
- php composer.phar install --dev
- rm -rf vendor/doctrine/doctrine-orm-module
- cp -r ../DoctrineORMModule vendor/doctrine/doctrine-orm-module
- cp ../DoctrineORMModule/.travis/travis.local.php config/autoload/
Expand Down
6 changes: 6 additions & 0 deletions composer.json
Expand Up @@ -39,6 +39,12 @@
"doctrine/migrations": "dev-master",
"zendframework/zendframework": "dev-master"
},
"require-dev": {
"zendframework/zend-developer-tools": "dev-master"
},
"suggest": {
"zendframework/zend-developer-tools": "zend-developer-tools if you want to profile operations executed by the ORM during development"
},
"minimum-stability": "dev",
"autoload": {
"psr-0": {
Expand Down
17 changes: 17 additions & 0 deletions config/module.config.php
Expand Up @@ -50,4 +50,21 @@
'orm_default' => array()
),
),

'view_manager' => array(
'template_map' => array(
'zend-developer-tools/toolbar/doctrine-orm' => __DIR__ . '/../view/zend-developer-tools/toolbar/doctrine-orm.phtml',
),
),

'zdt' => array(
'collectors' => array(
'orm_default' => 'doctrine.collector.orm_default',
),
'toolbar' => array(
'entries' => array(
'orm_default' => 'zend-developer-tools/toolbar/doctrine-orm',
),
),
),
);
115 changes: 115 additions & 0 deletions src/DoctrineORMModule/Collector/SQLLoggerCollector.php
@@ -0,0 +1,115 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/

namespace DoctrineORMModule\Collector;

use ZendDeveloperTools\Collector\CollectorInterface;
use ZendDeveloperTools\Collector\AutoHideInterface;

use Zend\Mvc\MvcEvent;

use Doctrine\DBAL\Logging\DebugStack;

/**
* Collector to be used in ZendDeveloperTools to record and display SQL queries
*
* @license MIT
* @link www.doctrine-project.org
* @author Marco Pivetta <ocramius@gmail.com>
*/
class SQLLoggerCollector implements CollectorInterface, AutoHideInterface
{
/**
* Collector priority
*/
const PRIORITY = 10;

/**
* @var DebugStack
*/
protected $sqlLogger;

/**
* @var string
*/
protected $name;

/**
* @param DebugStack $logger
* @param string $name
*/
public function __construct(DebugStack $sqlLogger, $name)
{
$this->sqlLogger = $sqlLogger;
$this->name = (string) $name;
}

/**
* {@inheritDoc}
*/
public function getName()
{
return $this->name;
}

/**
* {@inheritDoc}
*/
public function getPriority()
{
return static::PRIORITY;
}

/**
* {@inheritDoc}
*/
public function collect(MvcEvent $mvcEvent)
{
}

/**
* {@inheritDoc}
*/
public function canHide()
{
return empty($this->sqlLogger->queries);
}

/**
* @return int
*/
public function getQueryCount()
{
return count($this->sqlLogger->queries);
}

/**
* @return float
*/
public function getQueryTime()
{
$time = 0.0;

foreach ($this->sqlLogger->queries as $query) {
$time += $query['executionMS'];
}

return $time;
}
}
30 changes: 26 additions & 4 deletions src/DoctrineORMModule/Module.php
Expand Up @@ -21,11 +21,19 @@

use Doctrine\Common\Annotations\AnnotationRegistry;
use Doctrine\ORM\Tools\Console\ConsoleRunner;

use DoctrineModule\Service\DriverFactory;
use DoctrineModule\Service\EventManagerFactory;

use DoctrineORMModule\Service\ConfigurationFactory as ORMConfigurationFactory;
use DoctrineORMModule\Service\EntityManagerFactory;
use DoctrineORMModule\Service\DBALConnectionFactory;
use DoctrineORMModule\Form\Annotation\AnnotationBuilder;

// @todo move to own factory to allow wrapping of controllers
use DoctrineORMModule\Collector\SQLLoggerCollector;
use Doctrine\DBAL\Logging\DebugStack;
use Doctrine\DBAL\Logging\LoggerChain;

use Zend\ModuleManager\ModuleManagerInterface;
use Zend\ModuleManager\Feature\ServiceProviderInterface;
Expand Down Expand Up @@ -117,9 +125,7 @@ public function getServiceConfig()
),
'factories' => array(
'DoctrineORMModule\Form\Annotation\AnnotationBuilder' => function(ServiceLocatorInterface $sl) {
return new \DoctrineORMModule\Form\Annotation\AnnotationBuilder(
$sl->get('doctrine.entitymanager.orm_default')
);
return new AnnotationBuilder($sl->get('doctrine.entitymanager.orm_default'));
},

'doctrine.connection.orm_default' => new DBALConnectionFactory('orm_default'),
Expand All @@ -128,7 +134,23 @@ public function getServiceConfig()

'doctrine.driver.orm_default' => new DriverFactory('orm_default'),
'doctrine.eventmanager.orm_default' => new EventManagerFactory('orm_default'),
)
'doctrine.collector.orm_default' => function(ServiceLocatorInterface $sl) {
$debugStackLogger = new DebugStack();
/* @var $configuration \Doctrine\ORM\Configuration */
$configuration = $sl->get('doctrine.configuration.orm_default');

if (null !== $configuration->getSQLLogger()) {
$logger = new LoggerChain();
$logger->addLogger($debugStackLogger);
$logger->addLogger($configuration->getSQLLogger());
$configuration->setSQLLogger($logger);
} else {
$configuration->setSQLLogger($debugStackLogger);
}

return new SQLLoggerCollector($debugStackLogger, 'orm_default');
},
),
);
}
}
102 changes: 102 additions & 0 deletions tests/DoctrineORMModuleTest/Collector/SQLLoggerCollectorTest.php
@@ -0,0 +1,102 @@
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/

namespace DoctrineORMModuleTest\Paginator;

use PHPUnit_Framework_TestCase as TestCase;
use DoctrineORMModule\Collector\SQLLoggerCollector;
use Doctrine\DBAL\Logging\DebugStack;
use Zend\Mvc\MvcEvent;


class SQLLoggerCollectorTest extends TestCase
{
/**
* @var DebugStack
*/
protected $logger;

/**
* @var string
*/
protected $name = 'test-collector-name';

/**
* @var SQLLoggerCollector
*/
protected $collector;

public function setUp()
{
parent::setUp();
$this->logger = new DebugStack();
$this->collector = new SQLLoggerCollector($this->logger, $this->name);
}

public function testHasCorrectName()
{
$this->assertSame($this->name, $this->collector->getName());
}

public function testGetPriority()
{
$this->assertInternalType('int', $this->collector->getPriority());
}

public function testCollect()
{
$this->collector->collect(new MvcEvent());
}

public function testCanHide()
{
$this->assertTrue($this->collector->canHide());
$this->logger->startQuery('some sql');
$this->assertFalse($this->collector->canHide());
}

public function testGetQueryCount()
{
$this->assertSame(0, $this->collector->getQueryCount());
$this->logger->startQuery('some sql');
$this->assertSame(1, $this->collector->getQueryCount());
$this->logger->startQuery('some more sql');
$this->assertSame(2, $this->collector->getQueryCount());
}

public function testGetQueryTime()
{
$start = microtime(true);
$this->assertEquals(0, $this->collector->getQueryTime());

$this->logger->startQuery('some sql');
$this->logger->stopQuery();
$time = microtime(true) - $start;
$time1 = $this->collector->getQueryTime();
$this->assertGreaterThan(0, $time1);
$this->assertLessThan($time, $time1);

$this->logger->startQuery('some more sql');
$this->logger->stopQuery();
$time = microtime(true) - $start;
$time2 = $this->collector->getQueryTime();
$this->assertGreaterThan($time1, $time2);
$this->assertLessThan($time, $time1);
}
}
27 changes: 27 additions & 0 deletions view/zend-developer-tools/toolbar/doctrine-orm.phtml
@@ -0,0 +1,27 @@
<div class="zdt-toolbar-entry">
<div class="zdt-toolbar-preview">
<img src="data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NzU1MkQ0QURDODkyMTFFMUE4RDU5MDZBOEM2RTM5QjYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NzU1MkQ0QUVDODkyMTFFMUE4RDU5MDZBOEM2RTM5QjYiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3NTUyRDRBQkM4OTIxMUUxQThENTkwNkE4QzZFMzlCNiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3NTUyRDRBQ0M4OTIxMUUxQThENTkwNkE4QzZFMzlCNiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PryYMQ8AAAN9SURBVHjapFRdSJNhFH6/7dvUzQWbOLacM92UNW1E4WDRhWKhiN0JEUU3/RAIXdiV0I1dKF7oRRe7mCmIonZRJM0agqRgiZIs0VnD5s/mVNRl4eZ+3E/PO76FjBVWBx7O9573fc97znPO+Riv10uOyVXgJnAOOAvkkMziARzAG+BlQUHBLyfMxsYG1bcAMyCJRqORra2tA4fDEfR4PEeQOAOhhxKJBMnLyxPodDpBSUlJrkQiyeX89AMPVCrVIYtD97CwjI6Ouru7u7/Mzc35uAiWgW3gCOBxF+OAFDgDaBCZsr6+XtbS0nKdZdnzsBmYmZmZjwqF4mJxcfGjeDz+an19fYWcUIqKiqhzo8VieVZbW6vCmmEXFhbicrmcuFyux5Q3OLVBuwDKBY02keZHBJwGlKurq9XQ9YAqGAzG6CYLTo7ghHCp3OVA+foG6nzpKcN+CnYlvvnHXxEIBMk1a7fbvRUVFZkykuGyLNMGLU66oFsCVPP39vaI2+02aLXaXJFIRItE/hYjIyMbXV1dU+iO5+zAwMCV2dnZybq6Oqlery9paGjILysrk6jVapFUKs1KjyQcDsdwMQj+/BMTE76pqakfoO1tb2+vqbKykjCDg4MfDAaDCTxOLy0tvWhvb+fPz8/ni8ViLbjKgz3B4/GYVJqwhdCbHvSrq7m52d/Y2FiOs/fpHqhjWLxIuKKYEKGpv5/2KNmBzQE48U25YbkeZOBcAacm4DZnT96PxWLJF9n9/f3vWKRnJqfApepMBclUlFTb8BcXF8Xg6oJGozn1LwWhWFtbO2hra/sE3cMODQ3JQajVbDYbMEb5VVVVcsykKDs7m/3TlOzu7obQcr6xsbFdaHtPT88hikSY4eHh9xiZS36//2lHR8fy9PR0eSAQUGMUZYhcAM6SteAmhsFebHt7OwyqPKWlpZ+bmpqCRqPxDujRmUwmhsUmU1hYSNCDD1tbW2kKbmzO+Xy+yc3NTS8chPh8Pg/2BP3rYExlSqVSKxQK9XjgRorXSCSSrCyLkYlyVU6JGgfUiI5Q/E7S7hD6KNU88DeJRj2kB/4HfX19X5OO4cxptVrVaNQcCF8mk2WftLoY2xA43+ns7HTabLYn8LfEjI+Pk5qaGiEW15B+FQi+jCKJ8EcWw3kWUmGOp4biRcFtEL87v9PpXMEIvoP5NffLIz8FGAAqeUQbl180BwAAAABJRU5ErkJggg==" alt="Database (Zend\Db)">
<span class="zdt-toolbar-info">
<?php echo $this->collector->getQueryCount(); ?>
queries in
<?php echo $this->ZDT_Time($this->collector->getQueryTime()); ?> s
</span>
</div>
<div class="zdt-toolbar-detail">
<span class="zdt-toolbar-info zdt-toolbar-info-heading">Details</span>
<span class="zdt-toolbar-info">
<span class="zdt-detail-label">Help us!</span>
<span class="zdt-detail-value zdt-detail-value-right">
Please help us improve
<br/>
profiling by forking and
<br/>
contributing to
<br/>
<a href="https://github.com/doctrine/DoctrineORMModule/fork_select" target="_blank">
DoctrineORMModule
</a>
</span>
</span>
</div>
</div>

0 comments on commit 8a4c279

Please sign in to comment.