Issues (59)

code/Proxy/SSViewerProxy.php (7 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 = [];
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);
0 ignored issues
show
Deprecated Code introduced by
The property SilverStripe\View\SSViewer::$chosen has been deprecated: 5.4.0 Will be moved to SilverStripe\TemplateEngine\SSTemplateEngine in a future major release ( Ignorable by Annotation )

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

40
        $templateName = self::normalizeTemplateName(/** @scrutinizer ignore-deprecated */ $this->chosen);

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
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);
0 ignored issues
show
Deprecated Code introduced by
The property SilverStripe\View\SSViewer::$chosen has been deprecated: 5.4.0 Will be moved to SilverStripe\TemplateEngine\SSTemplateEngine in a future major release ( Ignorable by Annotation )

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

70
            $sourceFile = $this->getCacheFile(/** @scrutinizer ignore-deprecated */ $this->chosen);

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
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;
0 ignored issues
show
Deprecated Code introduced by
The property SilverStripe\View\SSViewer::$chosen has been deprecated: 5.4.0 Will be moved to SilverStripe\TemplateEngine\SSTemplateEngine in a future major release ( Ignorable by Annotation )

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

97
            $template = /** @scrutinizer ignore-deprecated */ $this->chosen;

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
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