Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit f39ed57

Browse filesBrowse files
wouterjfabpot
authored andcommitted
Created stopwatch tag
1 parent 43e066f commit f39ed57
Copy full SHA for f39ed57

File tree

Expand file treeCollapse file tree

6 files changed

+276
-0
lines changed
Filter options
Expand file treeCollapse file tree

6 files changed

+276
-0
lines changed

‎src/Symfony/Bridge/Twig/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Bridge/Twig/CHANGELOG.md
+5Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
2.4.0
5+
-----
6+
7+
* added stopwatch tag to time templates with the WebProfilerBundle
8+
49
2.3.0
510
-----
611

+61Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bridge\Twig\Extension;
13+
14+
use Symfony\Component\Stopwatch\Stopwatch;
15+
use Symfony\Bridge\Twig\TokenParser\StopwatchTokenParser;
16+
17+
/**
18+
* Twig extension for the stopwatch helper.
19+
*
20+
* @author Wouter J <wouter@wouterj.nl>
21+
*/
22+
class StopwatchExtension extends \Twig_Extension
23+
{
24+
private $stopwatch;
25+
26+
public function __construct(Stopwatch $stopwatch = null)
27+
{
28+
$this->stopwatch = $stopwatch;
29+
}
30+
31+
public function getTokenParsers()
32+
{
33+
return array(
34+
/*
35+
* {% stopwatch foo %}
36+
* Some stuff which will be recorded on the timeline
37+
* {% endstopwatch %}
38+
*/
39+
new StopwatchTokenParser($this->stopwatch !== null),
40+
);
41+
}
42+
43+
public function getName()
44+
{
45+
return 'stopwatch';
46+
}
47+
48+
public function startEvent($name)
49+
{
50+
if ($this->stopwatch instanceof Stopwatch) {
51+
$this->stopwatch->start($name, 'template');
52+
}
53+
}
54+
55+
public function stopEvent($name)
56+
{
57+
if ($this->stopwatch instanceof Stopwatch) {
58+
$this->stopwatch->stop($name);
59+
}
60+
}
61+
}
+36Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bridge\Twig\Node;
13+
14+
/**
15+
* Represents a stopwatch node.
16+
*
17+
* @author Wouter J <wouter@wouterj.nl>
18+
*/
19+
class StopwatchNode extends \Twig_Node
20+
{
21+
public function __construct($name, $body, $lineno = 0, $tag = null)
22+
{
23+
parent::__construct(array('body' => $body), array('name' => $name), $lineno, $tag);
24+
}
25+
26+
public function compile(\Twig_Compiler $compiler)
27+
{
28+
$name = $this->getAttribute('name');
29+
30+
$compiler
31+
->write('$this->env->getExtension(\'stopwatch\')->startEvent(\''.$name.'\');')
32+
->subcompile($this->getNode('body'))
33+
->write('$this->env->getExtension(\'stopwatch\')->stopEvent(\''.$name.'\');')
34+
->raw("\n");
35+
}
36+
}
+91Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bridge\Twig\Tests\Extension;
13+
14+
use Symfony\Bridge\Twig\Extension\StopwatchExtension;
15+
use Symfony\Component\Stopwatch\Stopwatch;
16+
use Symfony\Bridge\Twig\Tests\TestCase;
17+
18+
class StopwatchExtensionTest extends TestCase
19+
{
20+
protected function setUp()
21+
{
22+
parent::setUp();
23+
24+
if (!class_exists('Symfony\Component\Stopwatch\Stopwatch')) {
25+
$this->markTestSkipped('The "Stopwatch" component is not available');
26+
}
27+
}
28+
29+
/**
30+
* @expectedException \Twig_Error_Syntax
31+
*/
32+
public function testFailIfNameAlreadyExists()
33+
{
34+
$this->testTiming('{% stopwatch foo %}{% endstopwatch %}{% stopwatch foo %}{% endstopwatch %}', array());
35+
}
36+
37+
/**
38+
* @expectedException \Twig_Error_Syntax
39+
*/
40+
public function testFailIfStoppingWrongEvent()
41+
{
42+
$this->testTiming('{% stopwatch foo %}{% endstopwatch bar %}', array());
43+
}
44+
45+
/**
46+
* @dataProvider getTimingTemplates
47+
*/
48+
public function testTiming($template, $events)
49+
{
50+
$twig = new \Twig_Environment(new \Twig_Loader_String(), array('debug' => true, 'cache' => false, 'autoescape' => true, 'optimizations' => 0));
51+
$twig->addExtension(new StopwatchExtension($this->getStopwatch($events)));
52+
53+
try {
54+
$nodes = $twig->render($template);
55+
} catch (\Twig_Error_Runtime $e) {
56+
throw $e->getPrevious();
57+
}
58+
}
59+
60+
public function getTimingTemplates()
61+
{
62+
return array(
63+
array('{% stopwatch foo %}something{% endstopwatch %}', 'foo'),
64+
array('{% stopwatch foo %}symfony2 is fun{% endstopwatch %}{% stopwatch bar %}something{% endstopwatch %}', array('foo', 'bar')),
65+
66+
array('{% stopwatch foo %}something{% endstopwatch foo %}', 'foo'),
67+
68+
array("{% stopwatch 'foo.bar' %}something{% endstopwatch %}", 'foo.bar'),
69+
);
70+
}
71+
72+
protected function getStopwatch($events = array())
73+
{
74+
$events = is_array($events) ? $events : array($events);
75+
$stopwatch = $this->getMock('Symfony\Component\Stopwatch\Stopwatch');
76+
77+
$i = -1;
78+
foreach ($events as $eventName) {
79+
$stopwatch->expects($this->at(++$i))
80+
->method('start')
81+
->with($this->equalTo($eventName), 'template')
82+
;
83+
$stopwatch->expects($this->at(++$i))
84+
->method('stop')
85+
->with($this->equalTo($eventName))
86+
;
87+
}
88+
89+
return $stopwatch;
90+
}
91+
}
+77Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bridge\Twig\TokenParser;
13+
14+
use Symfony\Bridge\Twig\Node\StopwatchNode;
15+
16+
/**
17+
* Token Parser for the stopwatch tag.
18+
*
19+
* @author Wouter J <wouter@wouterj.nl>
20+
*/
21+
class StopwatchTokenParser extends \Twig_TokenParser
22+
{
23+
protected $stopwatchIsAvailable;
24+
protected $_events = array();
25+
26+
public function __construct($stopwatchIsAvailable)
27+
{
28+
$this->stopwatchIsAvailable = $stopwatchIsAvailable;
29+
}
30+
31+
public function parse(\Twig_Token $token)
32+
{
33+
$lineno = $token->getLine();
34+
$stream = $this->parser->getStream();
35+
36+
// {% stopwatch bar %}
37+
if ($stream->test(\Twig_Token::NAME_TYPE)) {
38+
$name = $stream->expect(\Twig_Token::NAME_TYPE)->getValue();
39+
} else {
40+
$name = $stream->expect(\Twig_Token::STRING_TYPE)->getValue();
41+
}
42+
43+
if (in_array($name, $this->_events)) {
44+
throw new \Twig_Error_Syntax(sprintf("The stopwatch event '%s' has already been defined", $name));
45+
}
46+
$this->_events[] = $name;
47+
48+
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
49+
50+
// {% endstopwatch %} or {% endstopwatch bar %}
51+
$body = $this->parser->subparse(array($this, 'decideStopwatchEnd'), true);
52+
if ($stream->test(\Twig_Token::NAME_TYPE) || $stream->test(\Twig_Token::STRING_TYPE)) {
53+
$value = $stream->next()->getValue();
54+
55+
if ($name != $value) {
56+
throw new \Twig_Error_Syntax(sprintf("Expected endstopwatch for event '%s' (but %s given)", $name, $value));
57+
}
58+
}
59+
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
60+
61+
if ($this->stopwatchIsAvailable) {
62+
return new StopwatchNode($name, $body, $lineno, $this->getTag());
63+
}
64+
65+
return $body;
66+
}
67+
68+
public function decideStopwatchEnd(\Twig_Token $token)
69+
{
70+
return $token->test('endstopwatch');
71+
}
72+
73+
public function getTag()
74+
{
75+
return 'stopwatch';
76+
}
77+
}

‎src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml
+6Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
<parameter key="twig.extension.yaml.class">Symfony\Bridge\Twig\Extension\YamlExtension</parameter>
1919
<parameter key="twig.extension.form.class">Symfony\Bridge\Twig\Extension\FormExtension</parameter>
2020
<parameter key="twig.extension.httpkernel.class">Symfony\Bridge\Twig\Extension\HttpKernelExtension</parameter>
21+
<parameter key="twig.extension.debug.stopwatch.class">Symfony\Bridge\Twig\Extension\StopwatchExtension</parameter>
2122
<parameter key="twig.form.engine.class">Symfony\Bridge\Twig\Form\TwigRendererEngine</parameter>
2223
<parameter key="twig.form.renderer.class">Symfony\Bridge\Twig\Form\TwigRenderer</parameter>
2324
<parameter key="twig.translation.extractor.class">Symfony\Bridge\Twig\Translation\TwigExtractor</parameter>
@@ -86,6 +87,11 @@
8687
<tag name="twig.extension" />
8788
</service>
8889

90+
<service id="twig.extension.debug.stopwatch" class="%twig.extension.debug.stopwatch.class%" public="false">
91+
<tag name="twig.extension" />
92+
<argument type="service" id="debug.stopwatch" on-invalid="ignore" />
93+
</service>
94+
8995
<service id="twig.extension.httpkernel" class="%twig.extension.httpkernel.class%" public="false">
9096
<argument type="service" id="fragment.handler" />
9197
</service>

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.