Issues (60)

code/Proxy/SSViewerProxy.php (5 issues)

1
<?php
2
3
namespace LeKoala\DebugBar\Proxy;
4
5
use LeKoala\DebugBar\DebugBar;
6
use SilverStripe\ORM\FieldType\DBHTMLText;
7
use SilverStripe\View\SSViewer;
8
use SilverStripe\Control\Director;
9
10
/**
11
 * The template parser proxy will monitor the templates that are used during a page request. Since the
12
 * use of the template parser is behind cache checks, this will only execute during a cache flush.
13
 */
14
class SSViewerProxy extends SSViewer
15
{
16
    /**
17
     * Tracks all templates used in the current request
18
     *
19
     * @var array
20
     */
21
    protected static $allTemplates = [];
22
23
    /**
24
     * Whether the class has been used, meaning whether the page has been cached
25
     *
26
     * @var boolean
27
     */
28
    protected static $cached = true;
29
30
    /**
31
     * Overloaded to track all templates used in the current request
32
     *
33
     * {@inheritDoc}
34
     */
35
    public function process(mixed $item, array $overlay = []): DBHTMLText
36
    {
37
        // If there is no debug bar instance, process as usual
38
        if (!DebugBar::getDebugBar()) {
39
            return parent::process($item, $overlay);
40
        }
41
        $templateName = self::normalizeTemplateName($this->getTemplateEngine()->getSelectedTemplatePath());
0 ignored issues
show
The method getSelectedTemplatePath() does not exist on SilverStripe\View\TemplateEngine. It seems like you code against a sub-type of SilverStripe\View\TemplateEngine such as LeKoala\DebugBar\View\TemplateEngine. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

41
        $templateName = self::normalizeTemplateName($this->getTemplateEngine()->/** @scrutinizer ignore-call */ getSelectedTemplatePath());
Loading history...
42
        self::trackTemplateUsed($templateName);
43
44
        $startTime = microtime(true);
45
        DebugBar::withDebugBar(function (\DebugBar\DebugBar $debugBar) use ($templateName) {
46
            /** @var \DebugBar\DataCollector\TimeDataCollector $timeData */
47
            $timeData = $debugBar->getCollector('time');
48
            if (!$timeData) {
0 ignored issues
show
$timeData is of type DebugBar\DataCollector\TimeDataCollector, thus it always evaluated to true.
Loading history...
49
                return;
50
            }
51
            $timeData->startMeasure($templateName, $templateName);
52
        });
53
54
        $result = parent::process($item, $overlay);
55
        $endTime = microtime(true);
56
        $totalTime = sprintf("%.2f", $endTime - $startTime);
57
58
        DebugBar::withDebugBar(function (\DebugBar\DebugBar $debugBar) use ($templateName) {
59
            /** @var \DebugBar\DataCollector\TimeDataCollector $timeData */
60
            $timeData = $debugBar->getCollector('time');
61
            if (!$timeData) {
0 ignored issues
show
$timeData is of type DebugBar\DataCollector\TimeDataCollector, thus it always evaluated to true.
Loading history...
62
                return;
63
            }
64
            if ($timeData->hasStartedMeasure($templateName)) {
65
                $timeData->stopMeasure($templateName);
66
            }
67
        });
68
69
        $templateRenderWarningLevel = DebugBar::config()->get('template_rendering_warning_level');
70
        if ($templateRenderWarningLevel && $totalTime > $templateRenderWarningLevel) {
71
            $sourceFile = $this->getCacheFile($this->getTemplateEngine()->getSelectedTemplatePath());
72
            $messages = DebugBar::getMessageCollector();
73
            if ($messages) {
0 ignored issues
show
$messages is of type DebugBar\DataCollector\MessagesCollector, thus it always evaluated to true.
Loading history...
74
                $messages->addMessage(
75
                    "The template $templateName needed $totalTime seconds to render." .
76
                        "\nYou could reduce this by implementing partial caching." .
77
                        "\nYou can also check the cache file : $sourceFile",
78
                    'warning',
79
                    true
80
                );
81
            }
82
        }
83
84
        return $result;
85
    }
86
87
    /**
88
     * Get the cache file for a given template
89
     *
90
     * Useful to get to path to a slow template for example
91
     *
92
     * @param string $template
93
     * @return string
94
     */
95
    public function getCacheFile($template = null)
96
    {
97
        if ($template === null) {
98
            $template = $this->getTemplateEngine()->getSelectedTemplatePath();
99
        }
100
        return TEMP_PATH . DIRECTORY_SEPARATOR . '.cache'
101
            . str_replace(['\\', '/', ':'], '.', Director::makeRelative(realpath($template)));
102
    }
103
104
    /**
105
     * Get the templates used in the current request and the number of times they were called
106
     *
107
     * @return array
108
     */
109
    public static function getTemplatesUsed()
110
    {
111
        return static::$allTemplates;
112
    }
113
114
    /**
115
     * Reset the array
116
     *
117
     * @return void
118
     */
119
    public static function resetTemplatesUsed()
120
    {
121
        static::$allTemplates = [];
122
    }
123
124
    /**
125
     * Helps tracking the use of templates
126
     *
127
     * @param string $templateName
128
     */
129
    protected static function trackTemplateUsed($templateName)
130
    {
131
        if (in_array($templateName, static::$allTemplates)) {
132
            return;
133
        }
134
        static::$allTemplates[] = $templateName;
135
    }
136
137
    /**
138
     * Remove base path from template
139
     *
140
     * @param string $templateName
141
     * @return string
142
     */
143
    protected static function normalizeTemplateName($templateName)
144
    {
145
        // Fallback for if the templateName is not a string or array (or anything, really)
146
        if (!$templateName) {
147
            $templateName = '';
148
        }
149
        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...
150
    }
151
}
152