Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
86.67% covered (warning)
86.67%
39 / 45
77.78% covered (warning)
77.78%
7 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
FilePagination
86.67% covered (warning)
86.67%
39 / 45
77.78% covered (warning)
77.78%
7 / 9
24.25
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 getPageNumber
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
6
 getDisplayedPageNumber
40.00% covered (danger)
40.00%
2 / 5
0.00% covered (danger)
0.00%
0 / 1
2.86
 getNumberOfPages
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getPageTitle
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
3
 buildPageTitle
57.14% covered (warning)
57.14%
4 / 7
0.00% covered (danger)
0.00%
0 / 1
5.26
 buildPageTitleFromPageNumber
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 pageNumberExists
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 isValidInterval
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2
3namespace ProofreadPage\Pagination;
4
5use MediaWiki\Title\Title;
6use OutOfBoundsException;
7
8/**
9 * @license GPL-2.0-or-later
10 *
11 * Pagination of a book based on a multipage file
12 */
13class FilePagination extends Pagination {
14
15    /** @var Title */
16    private $indexTitle;
17
18    /**
19     * @var PageList representation of the <pagelist> tag
20     */
21    private $pageList;
22
23    /** @var int */
24    private $numberOfPages;
25
26    /**
27     * @var Title[] cache of build pages of the pagination as $pageNumber => $page array
28     */
29    private $pages = [];
30
31    /** @var int */
32    private $pageNamespaceId;
33
34    /**
35     * @param Title $indexTitle
36     * @param PageList $pageList representation of the <pagelist> tag that configure page numbers
37     * @param int $numberOfPages
38     * @param int $pageNamespaceId
39     */
40    public function __construct(
41        Title $indexTitle, PageList $pageList, int $numberOfPages, int $pageNamespaceId
42    ) {
43        $this->indexTitle = $indexTitle;
44        $this->pageList = $pageList;
45        $this->numberOfPages = $numberOfPages;
46        $this->pageNamespaceId = $pageNamespaceId;
47    }
48
49    /**
50     * @inheritDoc
51     */
52    public function getPageNumber( Title $pageTitle ): int {
53        $parts = explode( '/', $pageTitle->getText() );
54        if ( count( $parts ) !== 2 ) {
55            throw new PageNotInPaginationException(
56                $pageTitle->getFullText() . ' does not have page numbers'
57            );
58        }
59        if ( $parts[0] !== $this->indexTitle->getText() ) {
60            throw new PageNotInPaginationException(
61                $pageTitle->getFullText() . ' does not belong to the pagination'
62            );
63        }
64        $number = $pageTitle->getPageLanguage()->parseFormattedNumber( $parts[1] );
65        if ( ctype_digit( $number ) && $number > 0 && $number < PHP_INT_MAX ) {
66            // Valid page numbers are integer > 0.
67            return (int)$number;
68        } else {
69            throw new PageNotInPaginationException(
70                $pageTitle->getFullText() . ' provides invalid page number ' . $number
71            );
72        }
73    }
74
75    /**
76     * @inheritDoc
77     */
78    public function getDisplayedPageNumber( int $pageNumber ): PageNumber {
79        if ( !$this->pageNumberExists( $pageNumber ) ) {
80            throw new OutOfBoundsException(
81                'There is no page number ' . $pageNumber . ' in the pagination.'
82            );
83        }
84        return $this->pageList->getNumber( $pageNumber );
85    }
86
87    /**
88     * @inheritDoc
89     */
90    public function getNumberOfPages(): int {
91        return $this->numberOfPages;
92    }
93
94    /**
95     * @inheritDoc
96     */
97    public function getPageTitle( int $pageNumber ): Title {
98        if ( !$this->pageNumberExists( $pageNumber ) ) {
99            throw new OutOfBoundsException(
100                'There is no page number ' . $pageNumber . ' in the pagination.'
101            );
102        }
103
104        if ( !array_key_exists( $pageNumber, $this->pages ) ) {
105            $this->pages[$pageNumber] = $this->buildPageTitle( $pageNumber );
106        }
107
108        return $this->pages[$pageNumber];
109    }
110
111    /**
112     * @param int $pageNumber
113     * @return Title
114     */
115    private function buildPageTitle( int $pageNumber ): Title {
116        $i18nNumber = $this->indexTitle->getPageLanguage()->formatNumNoSeparators( $pageNumber );
117        $title = $this->buildPageTitleFromPageNumber( $i18nNumber );
118
119        // fallback to arabic number
120        if ( $i18nNumber !== (string)$pageNumber && !$title->exists() ) {
121            $arabicTitle = $this->buildPageTitleFromPageNumber( (string)$pageNumber );
122            if ( $arabicTitle->exists() ) {
123                return $arabicTitle;
124            }
125        }
126
127        return $title;
128    }
129
130    /**
131     * @param string $pageNumber
132     * @return Title
133     */
134    private function buildPageTitleFromPageNumber( string $pageNumber ): Title {
135        return Title::makeTitle(
136            $this->pageNamespaceId,
137            $this->indexTitle->getText() . '/' . $pageNumber
138        );
139    }
140
141    /**
142     * @inheritDoc
143     */
144    protected function pageNumberExists( int $pageNumber ): bool {
145        return $pageNumber >= 1 && $pageNumber <= $this->numberOfPages;
146    }
147
148    /**
149     * @param int $from
150     * @param int $to
151     * @param int $count
152     * @return bool
153     */
154    public static function isValidInterval( int $from, int $to, int $count ): bool {
155        return $from >= 1 && $from <= $to && $to <= $count;
156    }
157
158}