Completed
Push — master ( 6d20e6...296855 )
by Asif
02:11
created

src/Compilers/ShortcodeCompiler.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php namespace Webwizo\Shortcodes\Compilers;
2
3
use Illuminate\Support\Str;
4
5
class ShortcodeCompiler
6
{
7
8
    /**
9
     * Enabled state
10
     *
11
     * @var boolean
12
     */
13
    protected $enabled = false;
14
15
    /**
16
     * Enable strip state
17
     *
18
     * @var boolean
19
     */
20
    protected $strip = false;
21
22
    /**
23
     * @var
24
     */
25
    protected $matches;
26
27
    /**
28
     * Registered laravel-shortcodes
29
     *
30
     * @var array
31
     */
32
    protected $registered = [];
33
34
    /**
35
     * Enable
36
     *
37
     * @return void
38
     */
39
    public function enable()
40
    {
41
        $this->enabled = true;
42
    }
43
44
    /**
45
     * Disable
46
     *
47
     * @return void
48
     */
49
    public function disable()
50
    {
51
        $this->enabled = false;
52
    }
53
54
    /**
55
     * Add a new shortcode
56
     *
57
     * @param string          $name
58
     * @param callable|string $callback
59
     */
60
    public function add($name, $callback)
61
    {
62
        $this->registered[$name] = $callback;
63
    }
64
65
    /**
66
     * Compile the contents
67
     *
68
     * @param  string $value
69
     *
70
     * @return string
71
     */
72
    public function compile($value)
73
    {
74
        // Only continue is laravel-shortcodes have been registered
75
        if (!$this->enabled || !$this->hasShortcodes()) {
76
            return $value;
77
        }
78
        // Set empty result
79
        $result = '';
80
        // Here we will loop through all of the tokens returned by the Zend lexer and
81
        // parse each one into the corresponding valid PHP. We will then have this
82
        // template as the correctly rendered PHP that can be rendered natively.
83
        foreach (token_get_all($value) as $token) {
84
            $result .= is_array($token) ? $this->parseToken($token) : $token;
85
        }
86
87
        return $result;
88
    }
89
90
    /**
91
     * Check if laravel-shortcodes have been registered
92
     *
93
     * @return boolean
94
     */
95
    public function hasShortcodes()
96
    {
97
        return !empty($this->registered);
98
    }
99
100
    /**
101
     * Parse the tokens from the template.
102
     *
103
     * @param  array $token
104
     *
105
     * @return string
106
     */
107
    protected function parseToken($token)
108
    {
109
        list($id, $content) = $token;
110
        if ($id == T_INLINE_HTML) {
111
            $content = $this->renderShortcodes($content);
112
        }
113
114
        return $content;
115
    }
116
117
    /**
118
     * Render laravel-shortcodes
119
     *
120
     * @param  string $value
121
     *
122
     * @return string
123
     */
124
    protected function renderShortcodes($value)
125
    {
126
        $pattern = $this->getRegex();
127
128
        return preg_replace_callback("/{$pattern}/s", [$this, 'render'], $value);
129
    }
130
131
    /**
132
     * Render the current calld shortcode.
133
     *
134
     * @param  array $matches
135
     *
136
     * @return string
137
     */
138
    public function render($matches)
139
    {
140
        // Compile the shortcode
141
        $compiled = $this->compileShortcode($matches);
142
        $name = $compiled->getName();
143
144
        // Render the shortcode through the callback
145
        return call_user_func_array($this->getCallback($name), [
146
            $compiled,
147
            $compiled->getContent(),
148
            $this,
149
            $name
150
        ]);
151
    }
152
153
    /**
154
     * Get Compiled Attributes.
155
     *
156
     * @param $matches
157
     *
158
     * @return \Webwizo\Shortcodes\Shortcode
159
     */
160
    protected function compileShortcode($matches)
161
    {
162
        // Set matches
163
        $this->setMatches($matches);
164
        // pars the attributes
165
        $attributes = $this->parseAttributes($this->matches[3]);
166
167
        // return shortcode instance
168
        return new Shortcode(
169
            $this->getName(),
170
            $attributes,
171
            $this->getContent()
172
        );
173
    }
174
175
    /**
176
     * Set the matches
177
     *
178
     * @param array $matches
179
     */
180
    protected function setMatches($matches = [])
181
    {
182
        $this->matches = $matches;
183
    }
184
185
    /**
186
     * Return the shortcode name
187
     *
188
     * @return string
189
     */
190
    public function getName()
191
    {
192
        return $this->matches[2];
193
    }
194
195
    /**
196
     * Return the shortcode content
197
     *
198
     * @return string
199
     */
200
    public function getContent()
201
    {
202
        // Compile the content, to support nested laravel-shortcodes
203
        return $this->compile($this->matches[5]);
204
    }
205
206
    /**
207
     * Get the callback for the current shortcode (class or callback)
208
     *
209
     * @param  string $name
210
     *
211
     * @return callable|array
212
     */
213
    public function getCallback($name)
214
    {
215
        // Get the callback from the laravel-shortcodes array
216
        $callback = $this->registered[$name];
217
        // if is a string
218
        if (is_string($callback)) {
219
            // Parse the callback
220
            list($class, $method) = Str::parseCallback($callback, 'register');
221
            // If the class exist
222
            if (class_exists($class)) {
223
                // return class and method
224
                return [
225
                    app($class),
226
                    $method
227
                ];
228
            }
229
        }
230
231
        return $callback;
232
    }
233
234
    /**
235
     * Parse the shortcode attributes
236
     *
237
     * @author Wordpress
238
     * @return array
239
     */
240
    protected function parseAttributes($text)
241
    {
242
        $attributes = [];
243
        // attributes pattern
244
        $pattern = '/(\w+)\s*=\s*"([^"]*)"(?:\s|$)|(\w+)\s*=\s*\'([^\']*)\'(?:\s|$)|(\w+)\s*=\s*([^\s\'"]+)(?:\s|$)|"([^"]*)"(?:\s|$)|(\S+)(?:\s|$)/';
245
        // Match
246
        if (preg_match_all($pattern, preg_replace("/[\x{00a0}\x{200b}]+/u", " ", $text), $match, PREG_SET_ORDER)) {
247
            foreach ($match as $m) {
248
                if (!empty($m[1])) {
249
                    $attributes[strtolower($m[1])] = stripcslashes($m[2]);
250
                } elseif (!empty($m[3])) {
251
                    $attributes[strtolower($m[3])] = stripcslashes($m[4]);
252
                } elseif (!empty($m[5])) {
253
                    $attributes[strtolower($m[5])] = stripcslashes($m[6]);
254
                } elseif (isset($m[7]) && strlen($m[7])) {
255
                    $attributes[] = stripcslashes($m[7]);
256
                } elseif (isset($m[8])) {
257
                    $attributes[] = stripcslashes($m[8]);
258
                }
259
            }
260
        } else {
261
            $attributes = ltrim($text);
262
        }
263
264
        // return attributes
265
        return is_array($attributes) ? $attributes : [$attributes];
266
    }
267
268
    /**
269
     * Get shortcode names
270
     *
271
     * @return string
272
     */
273
    protected function getShortcodeNames()
274
    {
275
        return join('|', array_map('preg_quote', array_keys($this->registered)));
276
    }
277
278
    /**
279
     * Get shortcode regex.
280
     *
281
     * @author Wordpress
282
     * @return string
283
     */
284
    protected function getRegex()
285
    {
286
        // Get shortcode names
287
        $shortcodeNames = $this->getShortcodeNames();
288
289
        // return regex
290
        return "\\[(\\[?)($shortcodeNames)(?![\\w-])([^\\]\\/]*(?:\\/(?!\\])[^\\]\\/]*)*?)(?:(\\/)\\]|\\](?:([^\\[]*+(?:\\[(?!\\/\\2\\])[^\\[]*+)*+)\\[\\/\\2\\])?)(\\]?)";
291
    }
292
293
    /*private function getStripRegex()
0 ignored issues
show
Unused Code Comprehensibility introduced by
44% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
294
    {
295
        // Get shortcode names
296
        $shortcodeNames = $this->getShortcodeNames();
297
298
        return
299
            '\\[(\\[?)('.$shortcodeNames.')(?![\\w-])([^\\]\\/]*(?:\\/(?!\\])[^\\]\\/]*)*?)(?:(\\/)\\]|\\](?:([^\\[]*+(?:\\[(?!\\/\\2\\])[^\\[]*+)*+)\\[\\/\\2\\])?)(\\]?)';
300
    }*/
301
    /**
302
     * Remove all shortcode tags from the given content.
303
     *
304
     * @param string $content Content to remove shortcode tags.
305
     *
306
     * @return string Content without shortcode tags.
307
     */
308
    public function strip($content)
309
    {
310
        if (empty($this->registered)) {
311
            return $content;
312
        }
313
        $pattern = $this->getRegex();
314
315
        return preg_replace_callback("/{$pattern}/s", [$this, 'stripTag'], $content);
316
    }
317
318
    /**
319
     * @return boolean
320
     */
321
    public function getStrip()
322
    {
323
        return $this->strip;
324
    }
325
326
    /**
327
     * @param boolean $strip
328
     */
329
    public function setStrip($strip)
330
    {
331
        $this->strip = $strip;
332
    }
333
334
    /**
335
     * Remove shortcode tag
336
     *
337
     * @param type $m
338
     *
339
     * @return string Content without shortcode tag.
340
     */
341
    protected function stripTag($m)
342
    {
343
        if ($m[1] == '[' && $m[6] == ']') {
344
            return substr($m[0], 1, -1);
345
        }
346
347
        return $m[1] . $m[6];
348
    }
349
}
350