GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

Shortcodes::parseRegexAttributes()   B
last analyzed

Complexity

Conditions 9
Paths 2

Size

Total Lines 24
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 18
nc 2
nop 1
dl 0
loc 24
rs 8.0555
c 0
b 0
f 0
1
<?php
2
/**
3
 * This file is part of the O2System Framework package.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 *
8
 * @author         Steeve Andrian Salim
9
 * @copyright      Copyright (c) Steeve Andrian Salim
10
 */
11
12
// ------------------------------------------------------------------------
13
14
namespace O2System\Parser\String\Engines;
15
16
// ------------------------------------------------------------------------
17
18
use O2System\Spl\Patterns\Structural\Provider\AbstractProvider;
19
use O2System\Spl\Patterns\Structural\Provider\ValidationInterface;
20
use O2System\Spl\Traits\Collectors\ConfigCollectorTrait;
21
use O2System\Spl\Traits\Collectors\FileExtensionCollectorTrait;
22
use O2System\Spl\Traits\Collectors\FilePathCollectorTrait;
23
24
/**
25
 * Class Shortcodes
26
 *
27
 * This parser engine is used to parse WordPress "shortcodes".
28
 * The tag and attribute parsing or regular expression code is
29
 * based on the TextPattern tag parser.
30
 *
31
 * A few examples are below:
32
 *
33
 * [shortcode /]
34
 * [shortcode foo="bar" baz="bing" /]
35
 * [shortcode foo="bar"]content[/shortcode]
36
 *
37
 * Shortcode tags support attributes and enclosed content, but does not entirely
38
 * support inline shortcodes in other shortcodes. You will have to call the
39
 * shortcode parser in your function to account for that.
40
 *
41
 * @package O2System\Parser\Template\Engines
42
 */
43
class Shortcodes extends AbstractProvider implements
44
    ValidationInterface
45
{
46
    use FileExtensionCollectorTrait;
47
    use FilePathCollectorTrait;
48
    use ConfigCollectorTrait;
49
50
    /**
51
     * Shortcodes::$config
52
     *
53
     * Shortcodes engine configurations.
54
     *
55
     * @var array
56
     */
57
    protected $config;
58
59
    // ------------------------------------------------------------------------
60
61
    /**
62
     * Shortcodes::__construct
63
     *
64
     * @param array $config
65
     */
66
    public function __construct(array $config = [])
67
    {
68
        $this->config = array_merge($this->config, $config);
69
    }
70
71
    // ------------------------------------------------------------------------
72
73
    /**
74
     * Shortcodes::parseFile
75
     *
76
     * @param string $filePath
77
     * @param array  $vars
78
     *
79
     * @return string
80
     */
81
    public function parseFile($filePath, array $vars = [])
82
    {
83
        if (is_file($filePath)) {
84
            return $this->parseString(file_get_contents($filePath), $vars);
85
        }
86
87
        // Try to find from filePaths
88
        if (count($this->filePaths)) {
89
            foreach ($this->filePaths as $fileDirectory) {
90
                if (is_file($fileDirectory . $filePath)) {
91
                    return $this->parseString(file_get_contents($fileDirectory . $filePath), $vars);
92
                    break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
93
                }
94
            }
95
        }
96
97
        return null;
98
    }
99
100
    // ------------------------------------------------------------------------
101
102
    /**
103
     * Shortcodes::parseString
104
     *
105
     * @param string $source
106
     * @param array  $vars
107
     *
108
     * @return mixed
109
     */
110
    public function parseString($source, array $vars = [])
111
    {
112
        if (count($vars)) {
113
            foreach ($vars as $offset => $shortcode) {
114
                $this->register($shortcode, $offset);
115
            }
116
        }
117
118
        $pattern = $this->getRegex();
119
120
        return preg_replace_callback('/' . $pattern . '/s', [&$this, 'parseRegex'], $source);
121
    }
122
123
    // ------------------------------------------------------------------------
124
125
    /**
126
     * Shortcodes::getRegex
127
     *
128
     * Retrieve the shortcode regular expression for searching.
129
     *
130
     * The regular expression combines the shortcode tags in the regular expression
131
     * in a regex class.
132
     *
133
     * The regular expresion contains 6 different sub matches to help with parsing.
134
     *
135
     * 1/6 - An extra [ or ] to allow for escaping shortcodes with double [[]]
136
     * 2 - The shortcode name
137
     * 3 - The shortcode argument list
138
     * 4 - The self closing /
139
     * 5 - The content of a shortcode when it wraps some content.
140
     *
141
     * @return string The shortcode search regular expression
142
     */
143
    private function getRegex()
144
    {
145
        $shortcodes = $this->getIterator();
146
147
        $offsetKeys = $shortcodes->getKeys();
148
        $offsetRegex = join('|', array_map('preg_quote', $offsetKeys));
149
150
        // WARNING! Do not change this regex
151
        return '(.?)\[(' . $offsetRegex . ')\b(.*?)(?:(\/))?\](?:(.+?)\[\/\2\])?(.?)';
152
    }
153
154
    // ------------------------------------------------------------------------
155
156
    /**
157
     * Shortcodes::validate
158
     *
159
     * @param mixed $value
160
     *
161
     * @return bool
162
     */
163
    public function validate($value)
164
    {
165
        return (bool)is_callable($value);
166
    }
167
168
    // ------------------------------------------------------------------------
169
170
    /**
171
     * Shortcodes::parseRegex
172
     *
173
     * Regular Expression callable for Shortcodes::parseString for calling shortcode hook.
174
     *
175
     * @see    Shortcodes::getRegex for details of the match array contents.
176
     *
177
     * @since  1.0
178
     * @access private
179
     * @uses   $shortcode_tags
180
     *
181
     * @param array $match Regular expression match array
182
     *
183
     * @return mixed False on failure.
184
     */
185
    private function parseRegex($match)
186
    {
187
        // allow [[foo]] syntax for escaping a tag
188
        if ($match[ 1 ] == '[' && $match[ 6 ] == ']') {
189
            return substr($match[ 0 ], 1, -1);
190
        }
191
192
        $offset = $match[ 2 ];
193
        $attr = $this->parseRegexAttributes($match[ 3 ]);
194
195
        if ($this->exists($offset)) {
196
            if (isset($match[ 5 ])) {
197
                // enclosing tag - extra parameter
198
                return $match[ 1 ] . call_user_func(
199
                        $this->__get($offset),
200
                        $attr,
201
                        $match[ 5 ],
202
                        $offset
203
                    ) . $match[ 6 ];
204
            } else {
205
                // self-closing tag
206
                return $match[ 1 ] . call_user_func($this->__get($offset), $attr, null, $offset) . $match[ 6 ];
207
            }
208
        }
209
    }
210
211
    // ------------------------------------------------------------------------
212
213
    /**
214
     * Shortcodes::parseRegexAttr
215
     *
216
     * Retrieve all attributes from the shortcodes tag.
217
     *
218
     * The attributes list has the attribute name as the key and the value of the
219
     * attribute as the value in the key/value pair. This allows for easier
220
     * retrieval of the attributes, since all attributes have to be known.
221
     *
222
     * @since 1.0
223
     *
224
     * @param string $string
225
     *
226
     * @return array List of attributes and their value.
227
     */
228
    private function parseRegexAttributes($string)
229
    {
230
        $attr = [];
231
        $pattern = '/(\w+)\s*=\s*"([^"]*)"(?:\s|$)|(\w+)\s*=\s*\'([^\']*)\'(?:\s|$)|(\w+)\s*=\s*([^\s\'"]+)(?:\s|$)|"([^"]*)"(?:\s|$)|(\S+)(?:\s|$)/';
232
        $string = preg_replace("/[\x{00a0}\x{200b}]+/u", " ", $string);
233
        if (preg_match_all($pattern, $string, $match, PREG_SET_ORDER)) {
234
            foreach ($match as $m) {
235
                if ( ! empty($m[ 1 ])) {
236
                    $attr[ strtolower($m[ 1 ]) ] = stripcslashes($m[ 2 ]);
237
                } elseif ( ! empty($m[ 3 ])) {
238
                    $attr[ strtolower($m[ 3 ]) ] = stripcslashes($m[ 4 ]);
239
                } elseif ( ! empty($m[ 5 ])) {
240
                    $attr[ strtolower($m[ 5 ]) ] = stripcslashes($m[ 6 ]);
241
                } elseif (isset($m[ 7 ]) and strlen($m[ 7 ])) {
242
                    $attr[] = stripcslashes($m[ 7 ]);
243
                } elseif (isset($m[ 8 ])) {
244
                    $attr[] = stripcslashes($m[ 8 ]);
245
                }
246
            }
247
        } else {
248
            $attr = ltrim($string);
249
        }
250
251
        return $attr;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $attr also could return the type string which is incompatible with the documented return type array.
Loading history...
252
    }
253
}