Completed
Pull Request — master (#479)
by Gregor
03:07
created

TemplateHelper::getApplicationRootPath()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 2
1
<?php
2
/**
3
 * Whoops - php errors for cool kids
4
 * @author Filipe Dobreira <http://github.com/filp>
5
 */
6
7
namespace Whoops\Util;
8
9
use Symfony\Component\VarDumper\Caster\Caster;
10
use Symfony\Component\VarDumper\Cloner\AbstractCloner;
11
use Symfony\Component\VarDumper\Cloner\VarCloner;
12
use Symfony\Component\VarDumper\Dumper\HtmlDumper;
13
use Whoops\Exception\Frame;
14
15
/**
16
 * Exposes useful tools for working with/in templates
17
 */
18
class TemplateHelper
19
{
20
    /**
21
     * An array of variables to be passed to all templates
22
     * @var array
23
     */
24
    private $variables = [];
25
26
    /**
27
     * @var HtmlDumper
28
     */
29
    private $htmlDumper;
30
31
    /**
32
     * @var HtmlDumperOutput
33
     */
34
    private $htmlDumperOutput;
35
36
    /**
37
     * @var AbstractCloner
38
     */
39
    private $cloner;
40
41
    /**
42
     * @var string
43
     */
44
    private $applicationRootPath;
45
46
    /**
47
     * Escapes a string for output in an HTML document
48
     *
49
     * @param  string $raw
50
     * @return string
51
     */
52 2
    public function escape($raw)
53
    {
54 2
        $flags = ENT_QUOTES;
55
56
        // HHVM has all constants defined, but only ENT_IGNORE
57
        // works at the moment
58 2
        if (defined("ENT_SUBSTITUTE") && !defined("HHVM_VERSION")) {
59 2
            $flags |= ENT_SUBSTITUTE;
60 2
        } else {
61
            // This is for 5.3.
62
            // The documentation warns of a potential security issue,
63
            // but it seems it does not apply in our case, because
64
            // we do not blacklist anything anywhere.
65
            $flags |= ENT_IGNORE;
66
        }
67
68 2
        $raw = str_replace(chr(9), '    ', $raw);
69
70 2
        return htmlspecialchars($raw, $flags, "UTF-8");
71
    }
72
73
    /**
74
     * Escapes a string for output in an HTML document, but preserves
75
     * URIs within it, and converts them to clickable anchor elements.
76
     *
77
     * @param  string $raw
78
     * @return string
79
     */
80 1
    public function escapeButPreserveUris($raw)
81
    {
82 1
        $escaped = $this->escape($raw);
83 1
        return preg_replace(
84 1
            "@([A-z]+?://([-\w\.]+[-\w])+(:\d+)?(/([\w/_\.#-]*(\?\S+)?[^\.\s])?)?)@",
85 1
            "<a href=\"$1\" target=\"_blank\">$1</a>", $escaped
86 1
        );
87
    }
88
89
    /**
90
     * Makes sure that the given string breaks on the delimiter.
91
     *
92
     * @param  string $delimiter
93
     * @param  string $s
94
     * @return string
95
     */
96 1
    public function breakOnDelimiter($delimiter, $s)
97
    {
98 1
        $parts = explode($delimiter, $s);
99 1
        foreach ($parts as &$part) {
100 1
            $part = '<div class="delimiter">' . $part . '</div>';
101 1
        }
102
103 1
        return implode($delimiter, $parts);
104
    }
105
106
    /**
107
     * Replace the part of the path that all files have in common.
108
     *
109
     * @param  string $path
110
     * @return string
111
     */
112 1
    public function shorten($path)
113
    {
114 1
        if ($this->applicationRootPath !== null && $this->applicationRootPath != "/") {
115 1
            $path = str_replace($this->applicationRootPath, '&hellip;', $path);
116 1
        }
117
118 1
        return $path;
119
    }
120
121
    private function getDumper()
122
    {
123
        if (!$this->htmlDumper && class_exists('Symfony\Component\VarDumper\Cloner\VarCloner')) {
124
            $this->htmlDumperOutput = new HtmlDumperOutput();
125
            // re-use the same var-dumper instance, so it won't re-render the global styles/scripts on each dump.
126
            $this->htmlDumper = new HtmlDumper($this->htmlDumperOutput);
127
128
            $styles = [
129
                'default' => 'color:#FFFFFF; line-height:normal; font:12px "Inconsolata", "Fira Mono", "Source Code Pro", Monaco, Consolas, "Lucida Console", monospace !important; word-wrap: break-word; white-space: pre-wrap; position:relative; z-index:99999; word-break: normal',
130
                'num' => 'color:#BCD42A',
131
                'const' => 'color: #4bb1b1;',
132
                'str' => 'color:#BCD42A',
133
                'note' => 'color:#ef7c61',
134
                'ref' => 'color:#A0A0A0',
135
                'public' => 'color:#FFFFFF',
136
                'protected' => 'color:#FFFFFF',
137
                'private' => 'color:#FFFFFF',
138
                'meta' => 'color:#FFFFFF',
139
                'key' => 'color:#BCD42A',
140
                'index' => 'color:#ef7c61',
141
            ];
142
            $this->htmlDumper->setStyles($styles);
143
        }
144
145
        return $this->htmlDumper;
146
    }
147
148
    /**
149
     * Format the given value into a human readable string.
150
     *
151
     * @param  mixed $value
152
     * @return string
153
     */
154
    public function dump($value)
155
    {
156
        $dumper = $this->getDumper();
157
158
        if ($dumper) {
159
            // re-use the same DumpOutput instance, so it won't re-render the global styles/scripts on each dump.
160
            // exclude verbose information (e.g. exception stack traces)
161
            if (class_exists('Symfony\Component\VarDumper\Caster\Caster')) {
162
                $cloneVar = $this->getCloner()->cloneVar($value, Caster::EXCLUDE_VERBOSE);
163
            // Symfony VarDumper 2.6 Caster class dont exist.
164
            } else {
165
                $cloneVar = $this->getCloner()->cloneVar($value);
166
            }
167
168
            $dumper->dump(
169
                $cloneVar,
170
                $this->htmlDumperOutput
171
            );
172
173
            $output = $this->htmlDumperOutput->getOutput();
174
            $this->htmlDumperOutput->clear();
175
176
            return $output;
177
        }
178
179
        return print_r($value, true);
180
    }
181
182
    /**
183
     * Format the args of the given Frame as a human readable html string
184
     *
185
     * @param  Frame $frame
186
     * @return string the rendered html
187
     */
188
    public function dumpArgs(Frame $frame)
189
    {
190
        // we support frame args only when the optional dumper is available
191
        if (!$this->getDumper()) {
192
            return '';
193
        }
194
195
        $html = '';
196
        $numFrames = count($frame->getArgs());
197
198
        if ($numFrames > 0) {
199
            $html = '<ol class="linenums">';
200
            foreach($frame->getArgs() as $j => $frameArg) {
201
                $html .= '<li>'. $this->dump($frameArg) .'</li>';
202
            }
203
            $html .= '</ol>';
204
        }
205
206
        return $html;
207
    }
208
209
    /**
210
     * Convert a string to a slug version of itself
211
     *
212
     * @param  string $original
213
     * @return string
214
     */
215 1
    public function slug($original)
216
    {
217 1
        $slug = str_replace(" ", "-", $original);
218 1
        $slug = preg_replace('/[^\w\d\-\_]/i', '', $slug);
219 1
        return strtolower($slug);
220
    }
221
222
    /**
223
     * Given a template path, render it within its own scope. This
224
     * method also accepts an array of additional variables to be
225
     * passed to the template.
226
     *
227
     * @param string $template
228
     * @param array  $additionalVariables
229
     */
230 1
    public function render($template, array $additionalVariables = null)
231
    {
232 1
        $variables = $this->getVariables();
233
234
        // Pass the helper to the template:
235 1
        $variables["tpl"] = $this;
236
237 1
        if ($additionalVariables !== null) {
238 1
            $variables = array_replace($variables, $additionalVariables);
239 1
        }
240
241 1
        call_user_func(function () {
242 1
            extract(func_get_arg(1));
0 ignored issues
show
Bug introduced by
func_get_arg(1) cannot be passed to extract() as the parameter $var_array expects a reference.
Loading history...
243 1
            require func_get_arg(0);
244 1
        }, $template, $variables);
245 1
    }
246
247
    /**
248
     * Sets the variables to be passed to all templates rendered
249
     * by this template helper.
250
     *
251
     * @param array $variables
252
     */
253 1
    public function setVariables(array $variables)
254
    {
255 1
        $this->variables = $variables;
256 1
    }
257
258
    /**
259
     * Sets a single template variable, by its name:
260
     *
261
     * @param string $variableName
262
     * @param mixd   $variableValue
263
     */
264 1
    public function setVariable($variableName, $variableValue)
265
    {
266 1
        $this->variables[$variableName] = $variableValue;
267 1
    }
268
269
    /**
270
     * Gets a single template variable, by its name, or
271
     * $defaultValue if the variable does not exist
272
     *
273
     * @param  string $variableName
274
     * @param  mixed  $defaultValue
275
     * @return mixed
276
     */
277 1
    public function getVariable($variableName, $defaultValue = null)
278
    {
279 1
        return isset($this->variables[$variableName]) ?
280 1
            $this->variables[$variableName] : $defaultValue;
281
    }
282
283
    /**
284
     * Unsets a single template variable, by its name
285
     *
286
     * @param string $variableName
287
     */
288 1
    public function delVariable($variableName)
289
    {
290 1
        unset($this->variables[$variableName]);
291 1
    }
292
293
    /**
294
     * Returns all variables for this helper
295
     *
296
     * @return array
297
     */
298 1
    public function getVariables()
299
    {
300 1
        return $this->variables;
301
    }
302
303
    /**
304
     * Set the cloner used for dumping variables.
305
     *
306
     * @param AbstractCloner $cloner
307
     */
308
    public function setCloner($cloner)
309
    {
310
        $this->cloner = $cloner;
311
    }
312
313
    /**
314
     * Get the cloner used for dumping variables.
315
     *
316
     * @return AbstractCloner
317
     */
318
    public function getCloner()
319
    {
320
        if (!$this->cloner) {
321
            $this->cloner = new VarCloner();
322
        }
323
        return $this->cloner;
324
    }
325
326
    /**
327
     * Set the application root path.
328
     *
329
     * @param string $applicationRootPath
330
     */
331
    public function setApplicationRootPath($applicationRootPath)
332
    {
333
        $this->applicationRootPath = $applicationRootPath;
334
    }
335
336
    /**
337
     * Return the application root path.
338
     *
339
     * @return string
340
     */
341
    public function getApplicationRootPath()
342
    {
343
        return $this->applicationRootPath;
344
    }
345
}
346