Shortcoder   A
last analyzed

Complexity

Total Complexity 20

Size/Duplication

Total Lines 174
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 20
c 1
b 0
f 0
lcom 1
cbo 0
dl 0
loc 174
ccs 66
cts 66
cp 1
rs 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
D add() 0 38 9
A formatPattern() 0 20 2
B formatReplacement() 0 25 5
A parse() 0 8 1
A set() 0 4 1
A flush() 0 6 1
1
<?php
2
3
namespace Seiler\Shortcoder;
4
5
class Shortcoder
6
{
7
    /**
8
     * The shortcodes stack
9
     *
10
     * @var array
11
     */
12
    protected $shortcodes = [];
13
14
    /**
15
     * Create a new Shortcoder instance
16
     *
17
     * @param array|null|string $pattern
18
     * @param null|string       $replacement
19
     * @param mixed             $regex
20
     */
21 39
    public function __construct($pattern = null, $replacement = null, $regex = null)
22
    {
23 39
        $this->set($pattern, $replacement, $regex);
24 39
    }
25
26
    /**
27
     * Add shortcodes to the stack
28
     *
29
     * @param  array|null|string $pattern
30
     * @param  null|string       $replacement
31
     * @param  mixed             $regex
32
     *
33
     * @return \Seiler\Shortcoder\Shortcoder
34
     */
35 39
    public function add($pattern = null, $replacement = null, $regex = null)
36
    {
37
        // Called with arguments
38 39
        if (!is_array($pattern)) {
39 24
            $pattern = compact('pattern', 'replacement', 'regex');
40 24
        }
41
42
        // Called with only one shortcode
43 39
        if (!is_array(reset($pattern))) {
44 33
            $pattern = [$pattern];
45 33
        }
46
47 39
        foreach ($pattern as $attributes) {
48 39
            $pattern = array_key_exists('pattern', $attributes) ?
49 39
                $attributes['pattern'] : key($attributes);
50
51 39
            if (empty($pattern)) {
52 9
                continue;
53
            }
54
55 33
            $replacement = array_key_exists('replacement', $attributes) ?
56 33
                $attributes['replacement'] : reset($attributes);
57
58 33
            $regex = array_key_exists('regex', $attributes) ?
59 33
                $attributes['regex'] : null;
60
61
            $shortcode = [
62 33
                'pattern'     => $this->formatPattern($pattern, $regex),
63 33
                'replacement' => $this->formatReplacement($replacement, $regex)
64 33
            ];
65
66 33
            if (!in_array($shortcode, $this->shortcodes, true)) {
67 33
                $this->shortcodes[] = $shortcode;
68 33
            }
69 39
        }
70
71 39
        return $this;
72
    }
73
74
    /**
75
     * Format the given pattern
76
     *
77
     * @param  string $pattern
78
     * @param  mixed  $regex
79
     *
80
     * @return string
81
     */
82 33
    protected function formatPattern($pattern, $regex = null)
83
    {
84 33
        if (!empty($regex)) {
85 6
            return $pattern;
86
        }
87
88 27
        $pattern = preg_quote($pattern, '/');
89
90 27
        $pattern = preg_replace([
91 27
            '/\\\\\*/',        // 1 Replace all '*'...
92 27
            '/\s+/',           // 2 Replace all white-spaces...
93 27
            '/(\(\.\*\?\))$/', // 3 Replace any closing lazy catch-all...
94 27
        ], [
95 27
            '(.*?)',           // 1 ...with a lazy catch-all
96 27
            '\s',              // 2 ...with a 'white-space' regex pattern
97
            '(.*)'             // 3 ...with a greedy one
98 27
        ], $pattern);
99
100 27
        return "/$pattern/s";
101
    }
102
103
    /**
104
     * Format the given replacement
105
     *
106
     * @param  string $replacement
107
     * @param  mixed  $regex
108
     *
109
     * @return string
110
     */
111 33
    protected function formatReplacement($replacement = '', $regex = null)
112
    {
113 33
        if (!empty($regex)) {
114 6
            return $replacement;
115
        }
116
117 27
        $backReferences = [];
118
119 27
        if (preg_match_all('/\$(\d){1,2}/', $replacement, $matches)) {
120 6
            $backReferences = $matches[1];
121 6
        }
122
123 27
        while (strpos($replacement, '*') !== false) {
124 24
            $index = 1;
125
126 24
            while (in_array((string)$index, $backReferences, true)) {
127 18
                $index++;
128 18
            }
129
130 24
            $backReferences[] = (string)$index;
131 24
            $replacement = preg_replace('/\*/', '\$' . $index, $replacement, 1);
132 24
        }
133
134 27
        return $replacement;
135
    }
136
137
    /**
138
     * Parse the given text with stacked shortcodes
139
     *
140
     * @param  string $text
141
     *
142
     * @return string
143
     */
144 6
    public function parse($text = '')
145
    {
146 6
        return preg_replace(
147 6
            array_column($this->shortcodes, 'pattern'),
148 6
            array_column($this->shortcodes, 'replacement'),
149
            $text
150 6
        );
151
    }
152
153
    /**
154
     * Replace the stack with new shortcodes
155
     *
156
     * @param  array|null|string $pattern
157
     * @param  null|string       $replacement
158
     * @param  mixed             $regex
159
     *
160
     * @return \Seiler\Shortcoder\Shortcoder
161
     */
162 39
    public function set($pattern = null, $replacement = null, $regex = null)
163
    {
164 39
        return $this->flush()->add($pattern, $replacement, $regex);
165
    }
166
167
    /**
168
     * Flush the stack
169
     *
170
     * @return \Seiler\Shortcoder\Shortcoder
171
     */
172 39
    public function flush()
173
    {
174 39
        $this->shortcodes = [];
175
176 39
        return $this;
177
    }
178
}
179