Completed
Pull Request — master (#337)
by Markus
03:53 queued 01:30
created

TemplateHelper::getVariable()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 5
ccs 3
cts 3
cp 1
rs 9.4286
cc 2
eloc 3
nc 2
nop 2
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\Cloner\VarCloner;
10
use Symfony\Component\VarDumper\Dumper\CliDumper;
11
use Symfony\Component\VarDumper\Dumper\HtmlDumper;
12
use Whoops\Exception\Frame;
13
14
/**
15
 * Exposes useful tools for working with/in templates
16
 */
17
class TemplateHelper
18
{
19
    /**
20
     * An array of variables to be passed to all templates
21
     * @var array
22
     */
23
    private $variables = array();
24
25
    /**
26
     * Escapes a string for output in an HTML document
27
     *
28
     * @param  string $raw
29
     * @return string
30
     */
31 2
    public function escape($raw)
32
    {
33 2
        $flags = ENT_QUOTES;
34
35
        // HHVM has all constants defined, but only ENT_IGNORE
36
        // works at the moment
37 2
        if (defined("ENT_SUBSTITUTE") && !defined("HHVM_VERSION")) {
38 2
            $flags |= ENT_SUBSTITUTE;
39 2
        } else {
40
            // This is for 5.3.
41
            // The documentation warns of a potential security issue,
42
            // but it seems it does not apply in our case, because
43
            // we do not blacklist anything anywhere.
44
            $flags |= ENT_IGNORE;
45
        }
46
47 2
        return htmlspecialchars($raw, $flags, "UTF-8");
48
    }
49
50
    /**
51
     * Escapes a string for output in an HTML document, but preserves
52
     * URIs within it, and converts them to clickable anchor elements.
53
     *
54
     * @param  string $raw
55
     * @return string
56
     */
57 1
    public function escapeButPreserveUris($raw)
58
    {
59 1
        $escaped = $this->escape($raw);
60 1
        return preg_replace(
61 1
            "@([A-z]+?://([-\w\.]+[-\w])+(:\d+)?(/([\w/_\.#-]*(\?\S+)?[^\.\s])?)?)@",
62 1
            "<a href=\"$1\" target=\"_blank\">$1</a>", $escaped
63 1
        );
64
    }
65
66
    private function getDumper()
67
    {
68
        static $dumper = null;
69
70
        if (!$dumper && class_exists('Symfony\Component\VarDumper\Cloner\VarCloner')) {
71
            // re-use the same var-dumper instance, so it won't re-render the global styles/scripts on each dump.
72
            $dumper = new HtmlDumper();
73
74
            $styles = array(
75
                'default' => '',
76
                'num' => '',
77
                'const' => '',
78
                'str' => '',
79
                'note' => '',
80
                'ref' => '',
81
                'public' => '',
82
                'protected' => '',
83
                'private' => '',
84
                'meta' => '',
85
                'key' => '',
86
                'index' => '',
87
            );
88
            $dumper->setStyles($styles);
89
        }
90
91
        return $dumper;
92
    }
93
94
    /**
95
     * Format the given value into a human readable string.
96
     *
97
     * @param  mixed $value
98
     * @return string
99
     */
100
    public function dump($value)
101
    {
102
        $dumper = $this->getDumper();
103
104
        if ($dumper) {
105
            $cloner = new VarCloner();
106
            $output = '';
107
            $dumper->dump($cloner->cloneVar($value),  function ($line, $depth) use (&$output) {
108
                // A negative depth means "end of dump"
109
                if ($depth >= 0) {
110
                    // Adds a two spaces indentation to the line
111
                    $output .= str_repeat('  ', $depth).$line."\n";
112
                }
113
            });
114
            return $output;
115
        }
116
117
        return print_r($value, true);
118
    }
119
120
    /**
121
     * Format the args of the given Frame as a human readable html string
122
     *
123
     * @param  Frame $frame
124
     * @return string the rendered html
125
     */
126
    public function dumpArgs(Frame $frame)
127
    {
128
        // we support frame args only when the optional dumper is available
129
        if (!$this->getDumper()) {
130
            return '';
131
        }
132
133
        $html = '';
134
        $numFrames = count($frame->getArgs());
135
136
        if ($numFrames > 0) {
137
            $html .= '(';
138
            foreach($frame->getArgs() as $j => $frameArg) {
139
                $class = 'frame-arg';
140
                if ($j != $numFrames - 1 ) {
141
                    $class .= ' frame-arg-separated';
142
                }
143
                $html .= '<span class="'. $class .'">'. $this->dump($frameArg) .'</span>';
144
            }
145
            $html .= ')';
146
        }
147
148
        return $html;
149
    }
150
151
    /**
152
     * Convert a string to a slug version of itself
153
     *
154
     * @param  string $original
155
     * @return string
156
     */
157 1
    public function slug($original)
158
    {
159 1
        $slug = str_replace(" ", "-", $original);
160 1
        $slug = preg_replace('/[^\w\d\-\_]/i', '', $slug);
161 1
        return strtolower($slug);
162
    }
163
164
    /**
165
     * Given a template path, render it within its own scope. This
166
     * method also accepts an array of additional variables to be
167
     * passed to the template.
168
     *
169
     * @param string $template
170
     * @param array  $additionalVariables
171
     */
172 1
    public function render($template, array $additionalVariables = null)
173
    {
174 1
        $variables = $this->getVariables();
175
176
        // Pass the helper to the template:
177 1
        $variables["tpl"] = $this;
178
179 1
        if ($additionalVariables !== null) {
180 1
            $variables = array_replace($variables, $additionalVariables);
181 1
        }
182
183 1
        call_user_func(function () {
184 1
            extract(func_get_arg(1));
185 1
            require func_get_arg(0);
186 1
        }, $template, $variables);
187 1
    }
188
189
    /**
190
     * Sets the variables to be passed to all templates rendered
191
     * by this template helper.
192
     *
193
     * @param array $variables
194
     */
195 1
    public function setVariables(array $variables)
196
    {
197 1
        $this->variables = $variables;
198 1
    }
199
200
    /**
201
     * Sets a single template variable, by its name:
202
     *
203
     * @param string $variableName
204
     * @param mixd   $variableValue
205
     */
206 1
    public function setVariable($variableName, $variableValue)
207
    {
208 1
        $this->variables[$variableName] = $variableValue;
209 1
    }
210
211
    /**
212
     * Gets a single template variable, by its name, or
213
     * $defaultValue if the variable does not exist
214
     *
215
     * @param  string $variableName
216
     * @param  mixed  $defaultValue
217
     * @return mixed
218
     */
219 1
    public function getVariable($variableName, $defaultValue = null)
220
    {
221 1
        return isset($this->variables[$variableName]) ?
222 1
            $this->variables[$variableName] : $defaultValue;
223
    }
224
225
    /**
226
     * Unsets a single template variable, by its name
227
     *
228
     * @param string $variableName
229
     */
230 1
    public function delVariable($variableName)
231
    {
232 1
        unset($this->variables[$variableName]);
233 1
    }
234
235
    /**
236
     * Returns all variables for this helper
237
     *
238
     * @return array
239
     */
240 1
    public function getVariables()
241
    {
242 1
        return $this->variables;
243
    }
244
}
245