Completed
Push — master ( 509c61...616fc2 )
by Vladimir
02:58
created

TableOfContentsFilter   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 96
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 1

Test Coverage

Coverage 5.56%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 14
lcom 0
cbo 1
dl 0
loc 96
ccs 2
cts 36
cp 0.0556
rs 10
c 1
b 0
f 0

2 Methods

Rating   Name   Duplication   Size   Complexity  
C __invoke() 0 74 13
A get() 0 4 1
1
<?php
2
3
namespace allejo\stakx\Twig;
4
5
class TableOfContentsFilter implements StakxTwigFilter
6
{
7
    /**
8
     * @param string      $html  The HTML we'll be parsing
9
     * @param string|null $id    The ID to assign to the generated TOC
10
     * @param string|null $class The class to assign to the generated TOC
11
     * @param int         $hMin  The heading minimum that'll be included
12
     * @param int         $hMax  The heading maximum that'll be included
13
     *
14
     * @link https://git.io/vdnEM Modified from @mattfarina's implementation
15
     *
16
     * @return string
17
     */
18
    public function __invoke($html, $id = null, $class = null, $hMin = 1, $hMax = 6)
19
    {
20
        if (!function_exists('simplexml_load_string'))
21
        {
22
            trigger_error('XML support is not available with the current PHP installation.', E_USER_WARNING);
23
            return '';
24
        }
25
26
        $content = simplexml_load_string('<html>' . $html . '</html>');
27
28
        if ($content === false)
29
        {
30
            trigger_error('The HTML given to generate this Table of Contents was invalid.', E_USER_WARNING);
31
            return '';
32
        }
33
34
        $toc = '';
35
        $curr = $last = 1;
36
37
        $headings = $content->xpath('//h1|//h2|//h3|//h4|//h5|//h6');
38
39
        foreach ($headings as $heading)
40
        {
41
            if (!property_exists($heading->attributes(), 'id'))
42
            {
43
                continue;
44
            }
45
46
            sscanf($heading->getName(), 'h%u', $curr);
47
48
            if (!($hMin <= $curr && $curr <= $hMax)) {
49
                continue;
50
            }
51
52
            $headingID = $heading->attributes()->id;
53
54
            // If the current level is greater than the last level indent one level
55
            if ($curr > $last) {
56
                $toc .= '<ul>';
57
            }
58
            // If the current level is less than the last level go up appropriate amount.
59
            elseif ($curr < $last) {
60
                $toc .= str_repeat('</li></ul>', $last - $curr) . '</li>';
61
            }
62
            // If the current level is equal to the last.
63
            else {
64
                $toc .= '</li>';
65
            }
66
67
            $toc .= '<li><a href="#' . $headingID . '">' . (string)$heading . '</a>';
68
            $last = $curr;
69
        }
70
71
        $toc .= str_repeat('</li></ul>', $last);
72
73
        if ($id !== null || $class !== null)
74
        {
75
            $attributes = [];
76
77
            if ($id !== null)
78
            {
79
                $attributes[] = sprintf('id="%s"', $id);
80
            }
81
82
            if ($class !== null)
83
            {
84
                $attributes[] = sprintf('class="%s"', $class);
85
            }
86
87
            $toc = substr_replace($toc, sprintf('<ul %s', implode(' ', $attributes)), 0, 3);
88
        }
89
90
        return $toc;
91
    }
92
93
    /**
94
     * @return \Twig_SimpleFilter
95
     */
96 14
    public static function get()
97
    {
98 14
        return (new \Twig_SimpleFilter('toc', new self()));
99
    }
100
}
101