Issues (49)

code/Proxy/SSViewerProxy.php (4 issues)

1
<?php
2
3
namespace LeKoala\DebugBar\Proxy;
4
5
use LeKoala\DebugBar\DebugBar;
6
use SilverStripe\View\SSViewer;
7
use SilverStripe\Control\Director;
8
9
/**
10
 * The template parser proxy will monitor the templates that are used during a page request. Since the
11
 * use of the template parser is behind cache checks, this will only execute during a cache flush.
12
 */
13
class SSViewerProxy extends SSViewer
14
{
15
    /**
16
     * Tracks all templates used in the current request
17
     *
18
     * @var array
19
     */
20
    protected static $allTemplates = array();
21
22
    /**
23
     * Whether the class has been used, meaning whether the page has been cached
24
     *
25
     * @var boolean
26
     */
27
    protected static $cached = true;
28
29
    /**
30
     * Overloaded to track all templates used in the current request
31
     *
32
     * {@inheritDoc}
33
     */
34
    public function process($item, $arguments = null, $inheritedScope = null)
35
    {
36
        // If there is no debug bar instance, process as usual
37
        if (!DebugBar::getDebugBar()) {
38
            return parent::process($item, $arguments, $inheritedScope);
39
        }
40
        $templateName = self::normalizeTemplateName($this->chosen);
41
        self::trackTemplateUsed($templateName);
42
43
        $startTime = microtime(true);
44
        DebugBar::withDebugBar(function (\DebugBar\DebugBar $debugBar) use ($templateName) {
45
            /** @var \DebugBar\DataCollector\TimeDataCollector $timeData */
46
            $timeData = $debugBar->getCollector('time');
47
            if (!$timeData) {
0 ignored issues
show
$timeData is of type DebugBar\DataCollector\TimeDataCollector, thus it always evaluated to true.
Loading history...
48
                return;
49
            }
50
            $timeData->startMeasure($templateName, $templateName);
51
        });
52
53
        $result = parent::process($item, $arguments, $inheritedScope);
54
        $endTime = microtime(true);
55
        $totalTime = sprintf("%.2f", $endTime - $startTime);
56
57
        DebugBar::withDebugBar(function (\DebugBar\DebugBar $debugBar) use ($templateName) {
58
            /** @var \DebugBar\DataCollector\TimeDataCollector $timeData */
59
            $timeData = $debugBar->getCollector('time');
60
            if (!$timeData) {
0 ignored issues
show
$timeData is of type DebugBar\DataCollector\TimeDataCollector, thus it always evaluated to true.
Loading history...
61
                return;
62
            }
63
            if ($timeData->hasStartedMeasure($templateName)) {
64
                $timeData->stopMeasure($templateName);
65
            }
66
        });
67
68
        $templateRenderWarningLevel = DebugBar::config()->get('template_rendering_warning_level');
69
        if ($templateRenderWarningLevel && $totalTime > $templateRenderWarningLevel) {
70
            $sourceFile = $this->getCacheFile($this->chosen);
71
            $messages = DebugBar::getMessageCollector();
72
            if ($messages) {
0 ignored issues
show
$messages is of type DebugBar\DataCollector\MessagesCollector, thus it always evaluated to true.
Loading history...
73
                $messages->addMessage(
74
                    "The template $templateName needed $totalTime seconds to render." .
75
                        "\nYou could reduce this by implementing partial caching." .
76
                        "\nYou can also check the cache file : $sourceFile",
77
                    'warning',
78
                    true
79
                );
80
            }
81
        }
82
83
        return $result;
84
    }
85
86
    /**
87
     * Get the cache file for a given template
88
     *
89
     * Useful to get to path to a slow template for example
90
     *
91
     * @param string $template
92
     * @return string
93
     */
94
    public function getCacheFile($template = null)
95
    {
96
        if ($template === null) {
97
            $template = $this->chosen;
98
        }
99
        return TEMP_PATH . DIRECTORY_SEPARATOR . '.cache'
100
            . str_replace(['\\', '/', ':'], '.', Director::makeRelative(realpath($template)));
101
    }
102
103
    /**
104
     * Get the templates used in the current request and the number of times they were called
105
     *
106
     * @return array
107
     */
108
    public static function getTemplatesUsed()
109
    {
110
        return static::$allTemplates;
111
    }
112
113
    /**
114
     * Reset the array
115
     *
116
     * @return void
117
     */
118
    public static function resetTemplatesUsed()
119
    {
120
        static::$allTemplates = [];
121
    }
122
123
    /**
124
     * Helps tracking the use of templates
125
     *
126
     * @param string $templateName
127
     */
128
    protected static function trackTemplateUsed($templateName)
129
    {
130
        if (in_array($templateName, static::$allTemplates)) {
131
            return;
132
        }
133
        static::$allTemplates[] = $templateName;
134
    }
135
136
    /**
137
     * Remove base path from template
138
     *
139
     * @param string $templateName
140
     * @return string
141
     */
142
    protected static function normalizeTemplateName($templateName)
143
    {
144
        // Fallback for if the templateName is not a string or array (or anything, really)
145
        if (!$templateName) {
146
            $templateName = '';
147
        }
148
        return str_ireplace(BASE_PATH, '', $templateName);
0 ignored issues
show
Bug Best Practice introduced by
The expression return str_ireplace(LeKo...ATH, '', $templateName) also could return the type array which is incompatible with the documented return type string.
Loading history...
149
    }
150
}
151