Passed
Push — master ( 10c279...479d7b )
by Lawrence
01:27
created

Format   A

Complexity

Total Complexity 33

Size/Duplication

Total Lines 230
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 3
Bugs 1 Features 0
Metric Value
c 3
b 1
f 0
dl 0
loc 230
ccs 78
cts 78
cp 1
rs 9.3999
wmc 33

7 Methods

Rating   Name   Duplication   Size   Complexity  
A HTML() 0 3 1
A parse_comment() 0 8 2
A decrement_tabs() 0 6 2
A parse_inner_inline_tag() 0 8 2
C process() 0 56 15
C parse_tag() 0 22 9
A parse_inner_tag() 0 7 2
1
<?php
2
namespace Roesch;
3
4
/**
5
 * Format HTML class
6
 */
7
class Format
8
{
9
    /*
10
     * @var
11
     */
12
    private $input = null;
13
14
    /*
15
     * @var
16
     */
17
    private $output = null;
18
19
    /*
20
     * @var
21
     */
22
    private $in_tag = false;
23
24
    /*
25
     * @var
26
     */
27
    private $in_comment = false;
28
29
    /*
30
     * @var
31
     */
32
    private $in_content = false;
33
34
    /*
35
     * @var
36
     */
37
    private $inline_tag = false;
38
39
    /*
40
     * @var
41
     */
42
    private $i = 0;
43
44
    /*
45
     * @var
46
     */
47
    private $indent_depth = 0;
48
49
    /*
50
     * @var
51
     */
52
    private $indent_type = "\t";
53
54
    /**
55
     * Static interface
56
     * - Allows you to call the method witout initialising the class first
57
     *
58
     * <code>
59
     *  // use spaces at 4 length
60
     *  echo \Roesch\Format::HTML('Unformatted HTML string');
61
     *
62
     *  // use spaces at 2 length
63
     *  echo \Roesch\Format::HTML('Unformatted HTML string', true, 2);
64
     *
65
     *  // use tabs
66
     *  echo \Roesch\Format::HTML('Unformatted HTML string', false);
67
     * </code>
68
     *
69
     * @param  string $input          HTML which is to be processed
70
     * @param  bool   $use_spaces     Use spaces instead of tabs
71
     * @param  int    $indent_length  Length of indent spacing
72
     * @return string
73
     */
74 10
    public static function HTML($input, $use_spaces = true, $indent_length = 4)
75
    {
76 10
        return (new self)->process($input, $use_spaces, $indent_length);
77
    }
78
79
    /**
80
     * Process/Format HTML
81
     *
82
     * <code>
83
     *  $format = new \Roesch\Format();
84
     *
85
     *  // use spaces at 4 length
86
     *  echo $format->html('Unformatted HTML string');
87
     *
88
     *  // use spaces at 2 length
89
     *  echo $format->html('Unformatted HTML string', true, 2);
90
     *
91
     *  // use tabs
92
     *  echo $format->html('Unformatted HTML string', false);
93
     * </code>
94
     *
95
     * @param  string $input          HTML which is to be processed
96
     * @param  bool   $use_spaces     Use spaces instead of tabs
97
     * @param  int    $indent_length  Length of indent spacing
98
     * @return string
99
     */
100 10
    private function process($input, $use_spaces = true, $indent_length = 4)
101
    {
102 10
        if (!is_string($input)) {
103 1
            throw new \InvalidArgumentException('1st argument must be a string');
104
        }
105
106 9
        if (!is_int($indent_length)) {
107 1
            throw new \InvalidArgumentException('3rd argument must be an integer');
108
        }
109
110 8
        if ($indent_length < 0) {
111 1
            throw new \InvalidArgumentException('3rd argument must be greater or equals 0');
112
        }
113
114 7
        $this->tagtype = new TagType();
115
116 7
        if ($use_spaces) {
117 7
            $this->indent_type = str_repeat(' ', $indent_length);
118
        }
119
120 7
        $this->input = $input;
121 7
        $this->output = null;
122
123 7
        $i = 0;
124
125 7
        if (preg_match('/<\!doctype/i', $this->input)) {
126 2
            $i = strpos($this->input, '>') + 1;
127 2
            $this->output .= substr($this->input, 0, $i);
128
        }
129
130 7
        for ($this->i = $i; $this->i < strlen($this->input); $this->i++) {
131 7
            if ($this->in_comment) {
132 1
                $this->parse_comment();
133 7
            } elseif ($this->in_tag) {
134 6
                $this->parse_inner_tag();
135 7
            } elseif ($this->inline_tag) {
136 3
                $this->parse_inner_inline_tag();
137
            } else {
138 7
                if (preg_match('/[\r\n\t]/', $this->input[$this->i])) {
139 3
                    continue;
140 7
                } elseif ($this->input[$this->i] == '<') {
141 7
                    if (!$this->tagtype->inline_tag($this->i, $this->input)) {
142 5
                        $this->in_content = false;
143
                    }
144 7
                    $this->parse_tag();
145 2
                } elseif (!$this->in_content) {
146 2
                    if (!$this->inline_tag) {
147 2
                        $this->output .= "\n" . str_repeat($this->indent_type, $this->indent_depth);
148
                    }
149 2
                    $this->in_content = true;
150
                }
151 7
                $this->output .= $this->input[$this->i];
152
            }
153
        }
154
155 7
        return trim(preg_replace("/(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+/", "\n", $this->output));
156
    }
157
158
    /**
159
     * @return void
160
     */
161 1
    private function parse_comment()
162
    {
163 1
        if ($this->tagtype->end_comment($this->i, $this->input)) {
164 1
            $this->in_comment = false;
165 1
            $this->output .= '-->';
166 1
            $this->i += 3;
167
        } else {
168 1
            $this->output .= $this->input[$this->i];
169
        }
170 1
    }
171
172
    /**
173
     * @return void
174
     */
175 6
    private function parse_inner_tag()
176
    {
177 6
        if ($this->input[$this->i] == '>') {
178 6
            $this->in_tag = false;
179 6
            $this->output .= '>';
180
        } else {
181 6
            $this->output .= $this->input[$this->i];
182
        }
183 6
    }
184
185
    /**
186
     * @return void
187
     */
188 3
    private function parse_inner_inline_tag()
189
    {
190 3
        if ($this->input[$this->i] == '>') {
191 3
            $this->inline_tag = false;
192 3
            $this->decrement_tabs();
193 3
            $this->output .= '>';
194
        } else {
195 3
            $this->output .= $this->input[$this->i];
196
        }
197 3
    }
198
199
    /**
200
     * @return void
201
     */
202 7
    private function parse_tag()
203
    {
204 7
        if ($this->tagtype->comment($this->i, $this->input)) {
205 1
            $this->output .= "\n" . str_repeat($this->indent_type, $this->indent_depth);
206 1
            $this->in_comment = true;
207 6
        } elseif ($this->tagtype->end_tag($this->i, $this->input)) {
208 4
            $this->in_tag = true;
209 4
            $this->inline_tag = false;
210 4
            $this->decrement_tabs();
211 4
            if (!$this->tagtype->inline_tag($this->i, $this->input) && !$this->tagtype->tag_empty($this->i, $this->input)) {
212 4
                $this->output .= "\n" . str_repeat($this->indent_type, $this->indent_depth);
213
            }
214
        } else {
215 6
            $this->in_tag = true;
216 6
            if (!$this->in_content && !$this->inline_tag) {
217 6
                $this->output .= "\n" . str_repeat($this->indent_type, $this->indent_depth);
218
            }
219 6
            if (!$this->tagtype->closed_tag($this->i, $this->input)) {
220 6
                $this->indent_depth++;
221
            }
222 6
            if ($this->tagtype->inline_tag($this->i, $this->input)) {
223 3
                $this->inline_tag = true;
224
            }
225
        }
226 7
    }
227
228
    /**
229
     * @return void
230
     */
231 6
    private function decrement_tabs()
232
    {
233 6
        $this->indent_depth--;
234 6
        if ($this->indent_depth < 0) {
235
            // @codeCoverageIgnoreStart
236
            $this->indent_depth = 0;
237
            // @codeCoverageIgnoreEnd
238
        }
239 6
    }
240
241
}
242