From: Chuck Hagenbuch Date: Tue, 17 Feb 2009 05:51:06 +0000 (-0500) Subject: add benchmark, capture, and debug helpers X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=bdd007dd0779071e6545ec67b1c5171cee5031e5;p=horde.git add benchmark, capture, and debug helpers --- diff --git a/framework/View/lib/Horde/View/Helper/Benchmark.php b/framework/View/lib/Horde/View/Helper/Benchmark.php new file mode 100644 index 000000000..8acbc1e7c --- /dev/null +++ b/framework/View/lib/Horde/View/Helper/Benchmark.php @@ -0,0 +1,54 @@ + + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_View + * @subpackage Helper + */ + +/** + * Measures the execution time of a block in a template + * and reports the result to the log. Example: + * + * benchmark("Notes section") ?> + * expensiveNotesOperation() ?> + * end() ?> + * + * Will add something like "Notes section (0.34523)" to the log. + * + * You may give an optional logger level as the second argument + * ('debug', 'info', 'warn', 'error'). The default is 'info'. + * The level may also be given as a Horde_Log::* constant. + * + * @author Mike Naberezny + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_View + * @subpackage Helper + */ +class Horde_View_Helper_Benchmark extends Horde_View_Helper_Base +{ + /** + * Start a new benchmark. + * + * @param string $message Message to log after the benchmark has ended + * @param string|integer $level Log level to log after the benchmark has ended + * @return Horde_View_Helper_Benchmark_Timer + */ + public function benchmark($message = 'Benchmarking', $level = 'info') + { + return new Horde_View_Helper_Benchmark_Timer($message, $level, $this->_view->logger); + } + +} diff --git a/framework/View/lib/Horde/View/Helper/Benchmark/Timer.php b/framework/View/lib/Horde/View/Helper/Benchmark/Timer.php new file mode 100644 index 000000000..307b1fa89 --- /dev/null +++ b/framework/View/lib/Horde/View/Helper/Benchmark/Timer.php @@ -0,0 +1,95 @@ + + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_View + * @subpackage Helper + */ + +/** + * An instance of this class is returned by + * Horde_View_Helper_Benchmark::benchmark(). + * + * @author Mike Naberezny + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_View + * @subpackage Helper + */ +class Horde_View_Helper_Benchmark_Timer +{ + /** + * Time that the benchmark was started + * + * @var float microtime + */ + private $_start; + + /** + * Logger instance that will be used to record the + * time after the benchmark has ended + * + * @var null|Horde_Log_Logger + */ + private $_logger; + + /** + * Message to log after the benchmark has ended + * + * @var string + */ + private $_message; + + /** + * Log level to log after the benchmark has ended + * + * @var string|integer + */ + private $_level; + + /** + * Start a new benchmark. + * + * @param string $message Message to log after the benchmark has ended + * @param string|integer $level Log level to log after the benchmark has ended + * @param null|Horde_Log_Logger $logger Logger instance or NULL if none is available + */ + public function __construct($message, $level = 'info', $logger = null) + { + $this->_message = $message; + $this->_level = $level; + $this->_logger = $logger; + $this->_start = microtime(true); + } + + /** + * End the benchmark and log the result. + */ + public function end() + { + if ($this->_logger) { + // compute elapsed time & build message + $elapsed = microtime(true) - $this->_start; + $message = sprintf("{$this->_message} (%.5f)", $elapsed); + + // log message (level may be specified as integer or string) + if (is_integer($this->_level)) { + $this->_logger->log($message, $this->_level); + } else { + $this->_logger->{$this->_level}($message); + } + } + } + +} diff --git a/framework/View/lib/Horde/View/Helper/Capture.php b/framework/View/lib/Horde/View/Helper/Capture.php new file mode 100644 index 000000000..e38d67336 --- /dev/null +++ b/framework/View/lib/Horde/View/Helper/Capture.php @@ -0,0 +1,68 @@ + + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_View + * @subpackage Helper + */ + +/** + * Capture lets you extract parts of code which can be used in other points of + * the template or even layout file. + * + * @author Mike Naberezny + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_View + * @subpackage Helper + */ +class Horde_View_Helper_Capture extends Horde_View_Helper_Base +{ + /** + * Capture allows you to extract a part of the template into an + * instance variable. You can use this instance variable anywhere + * in your templates and even in your layout. Example: + * + * capture() ?> + * Welcome To my shiny new web page! + * greeting = $capture->end() ?> + * + * @return Horde_View_Helper_Capture_Base + */ + public function capture() + { + return new Horde_View_Helper_Capture_Base(); + } + + /** + * Calling contentFor() stores the block of markup for later use. + * Subsequently, you can retrieve it inside an instance variable + * that will be named "contentForName" in another template + * or in the layout. Example: + * + * contentFor("header") %> + * + * end() %> + * + * You can then use $this->contentForHeader anywhere in your templates: + * + * contentForHeader ?> + * + * @param string $name Name of the content that becomes the instance + * variable name. "foo" -> "$this->contentForFoo" + * @return Horde_View_Helper_Capture_ContentFor + */ + public function contentFor($name) + { + return new Horde_View_Helper_Capture_ContentFor($name, $this->_view); + } + +} diff --git a/framework/View/lib/Horde/View/Helper/Capture/Base.php b/framework/View/lib/Horde/View/Helper/Capture/Base.php new file mode 100644 index 000000000..13a3420a7 --- /dev/null +++ b/framework/View/lib/Horde/View/Helper/Capture/Base.php @@ -0,0 +1,61 @@ + + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_View + * @subpackage Helper + */ + +/** + * An instance of this class is returned by + * Horde_View_Helper_Capture::capture(). + * + * @author Mike Naberezny + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_View + * @subpackage Helper + */ +class Horde_View_Helper_Capture_Base +{ + /** + * Are we currently buffering? + * + * @var boolean + */ + protected $_buffering = true; + + /** + * Start capturing. + */ + public function __construct() + { + ob_start(); + } + + /** + * Stop capturing and return what was captured. + * + * @return string + * @throws Horde_View_Exception + */ + public function end() + { + if ($this->_buffering) { + $this->_buffering = false; + $output = ob_get_clean(); + return $output; + } else { + throw new Horde_View_Exception('Capture already ended'); + } + } + +} diff --git a/framework/View/lib/Horde/View/Helper/Capture/ContentFor.php b/framework/View/lib/Horde/View/Helper/Capture/ContentFor.php new file mode 100644 index 000000000..81072921e --- /dev/null +++ b/framework/View/lib/Horde/View/Helper/Capture/ContentFor.php @@ -0,0 +1,60 @@ + + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_View + * @subpackage Helper + */ + +/** + * An instance of this class is returned by + * Horde_View_Helper_Capture::contentFor(). + * + * @author Mike Naberezny + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_View + * @subpackage Helper + */ +class Horde_View_Helper_Capture_ContentFor extends Horde_View_Helper_Capture_Base +{ + /** + * Name that will become "$this->contentForName" + * + * @var string + */ + private $_name; + + /** + * Start capturing content that will be stored as + * $view->contentForName. + * + * @param string $name Name of the content that becomes the instance + * variable name. "foo" -> "$this->contentForFoo" + * @param Horde_View_Base $view + */ + public function __construct($name, $view) + { + $this->_name = $name; + $this->_view = $view; + parent::__construct(); + } + + /** + * Stop capturing content and store it in the view. + */ + public function end() + { + $name = 'contentFor' . ucfirst($this->_name); + $this->_view->$name = parent::end(); + } + +} diff --git a/framework/View/lib/Horde/View/Helper/Debug.php b/framework/View/lib/Horde/View/Helper/Debug.php new file mode 100644 index 000000000..746f8c9f2 --- /dev/null +++ b/framework/View/lib/Horde/View/Helper/Debug.php @@ -0,0 +1,60 @@ + + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_View + * @subpackage Helper + */ + +/** + * Dumps a variable for inspection. + * Portions borrowed from Paul M. Jones' Solar_Debug + * + * @author Mike Naberezny + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_View + * @subpackage Helper + */ +class Horde_View_Helper_Debug extends Horde_View_Helper_Base +{ + /** + * Dumps a variable for inspection. + * + * @param string $var + * @return string + */ + public function debug($var) + { + return '
'
+             . htmlspecialchars($this->_fetch($var))
+             . '
'; + } + + /** + * Returns formatted output from var_dump(). + * + * Buffers the var_dump output for a variable and applies some + * simple formatting for readability. + * + * @param mixed $var variable to dump + * @return string formatted results of var_dump() + */ + private function _fetch($var) + { + ob_start(); + var_dump($var); + $output = ob_get_clean(); + $output = preg_replace("/\]\=\>\n(\s+)/m", "] => ", $output); + return $output; + } + +} diff --git a/framework/View/package.xml b/framework/View/package.xml index 282d6c286..ba3467687 100644 --- a/framework/View/package.xml +++ b/framework/View/package.xml @@ -40,7 +40,17 @@ http://pear.php.net/dtd/package-2.0.xsd"> + + + + + + + + + + @@ -67,7 +77,13 @@ http://pear.php.net/dtd/package-2.0.xsd"> + + + + + + diff --git a/framework/View/test/Horde/View/Helper/BenchmarkTest.php b/framework/View/test/Horde/View/Helper/BenchmarkTest.php new file mode 100644 index 000000000..f84bb7db3 --- /dev/null +++ b/framework/View/test/Horde/View/Helper/BenchmarkTest.php @@ -0,0 +1,84 @@ + + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_View + * @subpackage UnitTests + */ + +/** + * @group view + * @author Mike Naberezny + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_View + * @subpackage UnitTests + */ +class Horde_View_Helper_BenchmarkTest extends PHPUnit_Framework_TestCase +{ + public function setUp() + { + $this->view = new Horde_View(); + $this->view->addHelper(new Horde_View_Helper_Benchmark($this->view)); + + $log = new Horde_Log_Logger($this->mock = new Horde_Log_Handler_Mock()); + $this->view->logger = $log; + } + + public function testWithoutLogger() + { + $this->view = new Horde_View(); + $this->view->addHelper(new Horde_View_Helper_Benchmark($this->view)); + + $bench = $this->view->benchmark(); + $bench->end(); + } + + public function testDefaults() + { + $bench = $this->view->benchmark(); + $bench->end(); + $this->assertEquals(1, count($this->mock->events)); + $this->assertLastLogged(); + } + + public function testWithMessage() + { + $bench = $this->view->benchmark('test_run'); + $bench->end(); + $this->assertEquals(1, count($this->mock->events)); + $this->assertLastLogged('test_run'); + } + + public function testWithMessageAndLevelAsString() + { + $bench = $this->view->benchmark('debug_run', 'debug'); + $bench->end(); + $this->assertEquals(1, count($this->mock->events)); + $this->assertLastLogged('debug_run', 'debug'); + } + + public function testWithMessageAndLevelAsInteger() + { + $bench = $this->view->benchmark('debug_run', Horde_Log::DEBUG); + $bench->end(); + $this->assertEquals(1, count($this->mock->events)); + $this->assertLastLogged('debug_run', 'debug'); + } + + public function assertLastLogged($message = 'Benchmarking', $level = 'info') + { + $last = end($this->mock->events); + $this->assertEquals(strtoupper($level), $last['levelName']); + $this->assertRegExp("/^$message \(.*\)$/", $last['message']); + } + +} diff --git a/framework/View/test/Horde/View/Helper/CaptureTest.php b/framework/View/test/Horde/View/Helper/CaptureTest.php new file mode 100644 index 000000000..59e9c9e88 --- /dev/null +++ b/framework/View/test/Horde/View/Helper/CaptureTest.php @@ -0,0 +1,64 @@ + + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_View + * @subpackage UnitTests + */ + +/** + * @group view + * @author Mike Naberezny + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_View + * @subpackage UnitTests + */ +class Horde_View_Helper_CaptureTest extends PHPUnit_Framework_TestCase +{ + public function setUp() + { + $this->view = new Horde_View(); + $this->helper = new Horde_View_Helper_Capture($this->view); + } + + public function testCapture() + { + $capture = $this->helper->capture(); + echo $expected = 'foo'; + + $this->assertEquals($expected, $capture->end()); + } + + public function testCaptureThrowsWhenAlreadyEnded() + { + $capture = $this->helper->capture(); + $capture->end(); + + try { + $capture->end(); + $this->fail(); + } catch (Exception $e) { + $this->assertType('Horde_View_Exception', $e); + $this->assertRegExp('/capture already ended/i', $e->getMessage()); + } + } + + public function testContentFor() + { + $capture = $this->helper->contentFor('foo'); + echo $expected = 'foo'; + $capture->end(); + + $this->assertEquals($expected, $this->view->contentForFoo); + } + +} diff --git a/framework/View/test/Horde/View/Helper/DebugTest.php b/framework/View/test/Horde/View/Helper/DebugTest.php new file mode 100644 index 000000000..9922fe7be --- /dev/null +++ b/framework/View/test/Horde/View/Helper/DebugTest.php @@ -0,0 +1,39 @@ + + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_View + * @subpackage UnitTests + */ + +/** + * @group view + * @author Mike Naberezny + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_View + * @subpackage UnitTests + */ +class Horde_View_Helper_DebugTest extends PHPUnit_Framework_TestCase +{ + public function setUp() + { + $this->helper = new Horde_View_Helper_Debug(new Horde_View()); + } + + // test truncate + public function testDebug() + { + $expected = '
string(7) "foo&bar"';
+        $this->assertContains($expected, $this->helper->debug('foo&bar'));
+    }
+
+}