Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 114
0.00% covered (danger)
0.00%
0 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
SpecialMathWikibase
0.00% covered (danger)
0.00%
0 / 114
0.00% covered (danger)
0.00%
0 / 7
210
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 execute
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
12
 showForm
0.00% covered (danger)
0.00%
0 / 25
0.00% covered (danger)
0.00%
0 / 1
2
 showError
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
6
 getPlainText
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 buildPageRepresentation
0.00% covered (danger)
0.00%
0 / 48
0.00% covered (danger)
0.00%
0 / 1
30
 createHTMLHeader
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace MediaWiki\Extension\Math;
4
5use Exception;
6use InvalidArgumentException;
7use MediaWiki\Extension\Math\Widget\WikibaseEntitySelector;
8use MediaWiki\Html\Html;
9use MediaWiki\Logger\LoggerFactory;
10use MediaWiki\MainConfigNames;
11use MediaWiki\Message\Message;
12use MediaWiki\Output\OutputPage;
13use MediaWiki\SpecialPage\SpecialPage;
14use OOUI\ButtonInputWidget;
15use OOUI\FormLayout;
16
17class SpecialMathWikibase extends SpecialPage {
18    /**
19     * The parameter for this special page
20     */
21    private const PARAMETER = "qid";
22
23    /**
24     * @var MathWikibaseConnector Wikibase connection
25     */
26    private MathWikibaseConnector $wikibase;
27
28    /**
29     * @var \Psr\Log\LoggerInterface
30     */
31    private $logger;
32
33    public function __construct(
34        MathWikibaseConnector $wikibase
35    ) {
36        parent::__construct( 'MathWikibase' );
37
38        $this->wikibase = $wikibase;
39        $this->logger = LoggerFactory::getInstance( 'Math' );
40    }
41
42    /**
43     * @inheritDoc
44     */
45    public function execute( $par ) {
46        $request = $this->getRequest();
47        $output = $this->getOutput();
48        $output->enableOOUI();
49
50        $this->setHeaders();
51        $output->addModules( [ 'mw.widgets.MathWbEntitySelector' ] );
52
53        $output->setPageTitle(
54            $this->getPlainText( 'math-wikibase-header' )
55        );
56
57        // Get request
58        $requestId = $request->getText( self::PARAMETER, $par );
59
60        // if there is no id requested, show the request form
61        if ( !$requestId ) {
62            $this->showForm();
63        } else {
64            $this->logger->debug( "Request qID: " . $requestId );
65            $languageCode = $this->getConfig()->get( MainConfigNames::LanguageCode );
66            try {
67                $info = $this->wikibase->fetchWikibaseFromId( $requestId, $languageCode );
68                $this->logger->debug( "Successfully fetched information for qID: " . $requestId );
69                $this->buildPageRepresentation( $info, $requestId, $output );
70            } catch ( Exception $e ) {
71                $this->showError( $e );
72            }
73        }
74    }
75
76    /**
77     * Shows the form to request information for a specific Wikibase id
78     */
79    private function showForm() {
80        $actionField = new \OOUI\ActionFieldLayout(
81            new WikibaseEntitySelector( [
82                'name' => self::PARAMETER,
83                'placeholder' => $this->getPlainText( 'math-wikibase-special-form-placeholder' ),
84                'required' => true,
85                'infusable' => true,
86                'id' => 'wbEntitySelector'
87            ] ),
88            new ButtonInputWidget( [
89                'name' => 'request-qid',
90                'label' => $this->getPlainText( 'math-wikibase-special-form-button' ),
91                'type' => 'submit',
92                'flags' => [ 'primary', 'progressive' ],
93                'icon' => 'check',
94            ] ),
95            [
96                'label' => $this->getPlainText( 'math-wikibase-special-form-header' ),
97                'align' => 'top'
98            ]
99        );
100
101        $formLayout = new FormLayout( [
102            'method' => 'POST',
103            'items' => [ $actionField ]
104        ] );
105
106        $this->getOutput()->addHTML( $formLayout );
107    }
108
109    /**
110     * Shows an error message for the user and writes information to $logger
111     * @param Exception $e can potentially be any exception.
112     */
113    private function showError( Exception $e ) {
114        $this->getOutput()->setPageTitle(
115            $this->getPlainText( 'math-wikibase-special-error-header' )
116        );
117
118        if ( $e instanceof InvalidArgumentException ) {
119            $this->logger->warning( "An invalid ID was specified. Reason: " . $e->getMessage() );
120            $this->getOutput()->addHTML(
121                $this->msg( 'math-wikibase-special-error-invalid-argument' )->inContentLanguage()->parse()
122            );
123        } else {
124            $this->logger->error( "An unknown error occurred while fetching data from Wikibase.", [
125                'exception' => $e
126            ] );
127            $this->getOutput()->addHTML(
128                $this->msg( 'math-wikibase-special-error-unknown' )->inContentLanguage()->parse()
129            );
130        }
131    }
132
133    /**
134     * Helper function to shorten i18n text processing
135     * @param string $key
136     * @return string the plain text in current content language
137     */
138    private function getPlainText( $key ) {
139        return $this->msg( $key )->inContentLanguage()->plain();
140    }
141
142    /**
143     * @param MathWikibaseInfo $info
144     * @param string $qid
145     * @param OutputPage $output
146     */
147    public function buildPageRepresentation(
148        MathWikibaseInfo $info,
149        $qid,
150        OutputPage $output
151    ) {
152        $output->setPageTitle( $info->getLabel() );
153
154        // if 'instance of' is specified, it can be found in the description before a colon
155        // FIXME: There are other reasons to have a colon in an Item's description, e.g.
156        // https://www.wikidata.org/wiki/Special:MathWikibase?qid=Q6203
157        if ( preg_match( '/(.*):\s*(.*)/', $info->getDescription(), $matches ) ) {
158            $output->setSubtitle( $matches[1] );
159        }
160
161        // add formula information
162        $header = $this->msg( 'math-wikibase-formula-information' )->inContentLanguage()
163            ->plain();
164        $output->addHTML( self::createHTMLHeader( $header ) );
165
166        if ( $info->getFormattedSymbol() ) {
167            $math = $info->getFormattedSymbol();
168            $formulaInfo = new Message( 'math-wikibase-formula-header-format' );
169            $formulaInfo->rawParams(
170                $this->msg( 'math-wikibase-formula' )->inContentLanguage(),
171                $math
172            );
173            $output->addHTML( Html::rawElement( "p", [], $formulaInfo->inContentLanguage()->parse() ) );
174        }
175
176        $labelName = $this->msg(
177            'math-wikibase-formula-header-format',
178            $this->msg( 'math-wikibase-formula-name' )->inContentLanguage(),
179            $info->getLabel()
180        )->inContentLanguage()->parse();
181        $output->addHTML( Html::rawElement( "p", [], $labelName ) );
182
183        if ( isset( $matches[2] ) ) {
184            $labelType = $this->msg(
185                'math-wikibase-formula-header-format',
186                $this->msg( 'math-wikibase-formula-type' )->inContentLanguage(),
187                $matches[1]
188            )->inContentLanguage()->parse();
189            $output->addHTML( Html::rawElement( "p", [], $labelType ) );
190
191            $description = $matches[2];
192        } else {
193            $description = $info->getDescription();
194        }
195        $labelDesc = $this->msg(
196            'math-wikibase-formula-header-format',
197            $this->msg( 'math-wikibase-formula-description' )->inContentLanguage(),
198            $description
199        )->inContentLanguage()->parse();
200        $output->addHTML( Html::rawElement( "p", [], $labelDesc ) );
201
202        // add parts of formula
203        if ( $info->hasParts() ) {
204            $elementsHeader = $this->msg( 'math-wikibase-formula-elements-header' )
205                ->inContentLanguage()->plain();
206            $output->addHTML( self::createHTMLHeader( $elementsHeader ) );
207            $output->addHTML( $info->generateTableOfParts() );
208        }
209
210        // add link information
211        $wikibaseHeader = $this->msg(
212            'math-wikibase-formula-link-header',
213            $info->getDescription()
214        )->inContentLanguage()->plain();
215
216        $output->addHTML( self::createHTMLHeader( $wikibaseHeader ) );
217
218        $url = $this->wikibase->buildURL( $qid );
219        $link = Html::linkButton( $url, [ "href" => $url ] );
220        $output->addHTML( Html::rawElement( "p", [], $link ) );
221    }
222
223    /**
224     * @param string $header Plain text
225     * @return string Raw HTML
226     */
227    private static function createHTMLHeader( string $header ): string {
228        return Html::element(
229            'h2',
230            [],
231            $header
232        );
233    }
234}