Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
2 / 2
CRAP
100.00% covered (success)
100.00%
1 / 1
HeadingCounter
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
2 / 2
6
100.00% covered (success)
100.00%
1 / 1
 incrementAndGet
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
4
 incrementAndGetTopLevel
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3namespace MediaWiki\Extension\Collection;
4
5use LogicException;
6
7/**
8 * Helper class for counting sections and displaying current section number.
9 * The numbering is done in a way to avoid showing zeroes in the counter:
10 * e.g. for "<h2/><h4/><h2/><h3/>" the result will be "1 1.1 2 2.1" and not "1 1.0.1 2 2.1".
11 */
12class HeadingCounter {
13
14    /**
15     * List of current numbers, left is highest-level.
16     * @var int[] level => count
17     */
18    private $headingNumbers = [];
19
20    /**
21     * Increment the section counter and get the number of the new section.
22     * @param int $level Level of the current section. Smaller number means higher in the DOM;
23     *   other than that the class is agnostic to what level numbering scheme is used. E.g.
24     *   could be 1 for h1, 2 for h2 etc.
25     * @return string
26     */
27    public function incrementAndGet( $level ) {
28        $top = reset( $this->headingNumbers );
29        $this->headingNumbers = array_filter( $this->headingNumbers,
30            static function ( $l ) use ( $level ) {
31                return $l <= $level;
32            }, ARRAY_FILTER_USE_KEY );
33        if ( !$this->headingNumbers && $top ) {
34            // The new section is higher than all previous ones. Let's inherit the count from the
35            // previous top section. E.g. for "<h3/><h2/>" we want the section numbers to be
36            // "1 2", not "1 1".
37            $this->headingNumbers[$level] = $top;
38        }
39        if ( isset( $this->headingNumbers[$level] ) ) {
40            $this->headingNumbers[$level]++;
41        } else {
42            $this->headingNumbers[$level] = 1;
43        }
44        return implode( '.', $this->headingNumbers );
45    }
46
47    /**
48     * Increment section number for a top-level section and get new value.
49     * Calls to this method must be preceded with at least one incrementAndGet() call.
50     * Intended for the Contributors section the level of which depends on whether the book
51     * has chapters and/or multiple articles.
52     * @return string
53     */
54    public function incrementAndGetTopLevel() {
55        if ( !$this->headingNumbers ) {
56            throw new LogicException( __METHOD__ . ' called with calling increment() first' );
57        }
58        return $this->incrementAndGet( array_keys( $this->headingNumbers )[0] );
59    }
60
61}