Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 47
0.00% covered (danger)
0.00%
0 / 11
CRAP
0.00% covered (danger)
0.00%
0 / 1
SpecialFindComment
0.00% covered (danger)
0.00%
0 / 47
0.00% covered (danger)
0.00%
0 / 11
380
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getFormFields
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
2
 getSubpageField
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDisplayFormat
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 requiresPost
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getShowAlways
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 alterForm
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 onSubmit
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 onSuccess
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
42
 displayItems
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
20
 getDescription
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace MediaWiki\Extension\DiscussionTools;
4
5use MediaWiki\Html\Html;
6use MediaWiki\HTMLForm\HTMLForm;
7use MediaWiki\SpecialPage\FormSpecialPage;
8use MediaWiki\SpecialPage\SpecialPage;
9
10class SpecialFindComment extends FormSpecialPage {
11
12    private const LIST_LIMIT = 50;
13
14    public function __construct(
15        private readonly ThreadItemStore $threadItemStore,
16        private readonly ThreadItemFormatter $threadItemFormatter,
17    ) {
18        parent::__construct( 'FindComment' );
19    }
20
21    /**
22     * @inheritDoc
23     */
24    protected function getFormFields() {
25        return [
26            'idorname' => [
27                'label-message' => 'discussiontools-findcomment-label-idorname',
28                'name' => 'idorname',
29                'type' => 'text',
30                'required' => true,
31            ],
32        ];
33    }
34
35    /**
36     * @inheritDoc
37     */
38    protected function getSubpageField() {
39        return 'idorname';
40    }
41
42    /**
43     * @inheritDoc
44     */
45    protected function getDisplayFormat() {
46        return 'ooui';
47    }
48
49    /**
50     * @inheritDoc
51     */
52    public function requiresPost() {
53        return false;
54    }
55
56    /**
57     * @inheritDoc
58     */
59    protected function getShowAlways() {
60        return true;
61    }
62
63    /**
64     * @inheritDoc
65     */
66    protected function alterForm( HTMLForm $form ) {
67        $form->setWrapperLegend( true );
68        $form->setSubmitTextMsg( 'discussiontools-findcomment-label-search' );
69    }
70
71    private string $idOrName;
72
73    /**
74     * @inheritDoc
75     */
76    public function onSubmit( array $data ) {
77        // They are correctly written with underscores, but allow spaces too for consistency with
78        // the behavior of internal wiki links.
79        $this->idOrName = str_replace( ' ', '_', $data['idorname'] );
80        return true;
81    }
82
83    /**
84     * @inheritDoc
85     */
86    public function onSuccess() {
87        $out = $this->getOutput();
88        $results = false;
89
90        if ( $this->idOrName ) {
91            $byId = $this->threadItemStore->findNewestRevisionsById( $this->idOrName, static::LIST_LIMIT + 1 );
92            if ( $byId ) {
93                $this->displayItems( $byId, 'discussiontools-findcomment-results-id' );
94                $results = true;
95            }
96
97            $byName = $this->threadItemStore->findNewestRevisionsByName( $this->idOrName, static::LIST_LIMIT + 1 );
98            if ( $byName ) {
99                $this->displayItems( $byName, 'discussiontools-findcomment-results-name' );
100                $results = true;
101            }
102        }
103
104        if ( $results ) {
105            // (T389741) Comment IDs/names may use characters that are not valid in page titles, like '<'.
106            // Omit the message with the wikilink to Special:GoToComment/… if the link would be invalid.
107            // They can only be linked to using external links to Special:FindComment?idorname=…
108            // or wikilinks to the target page with a fragment identifier, for example Talk:Foo#….
109            // It's a pity we haven't realized this before deciding on this linking scheme. Oops.
110            $specialPageTitle = SpecialPage::getSafeTitleFor( 'GoToComment', $this->idOrName );
111            if ( $specialPageTitle !== null ) {
112                $out->addHTML(
113                    $this->msg( 'discussiontools-findcomment-gotocomment', $this->idOrName )->parseAsBlock() );
114            }
115        } else {
116            $out->addHTML(
117                $this->msg( 'discussiontools-findcomment-noresults' )->parseAsBlock() );
118        }
119    }
120
121    private function displayItems( array $threadItems, string $msgKey ) {
122        $out = $this->getOutput();
123
124        $list = [];
125        foreach ( $threadItems as $item ) {
126            if ( count( $list ) === static::LIST_LIMIT ) {
127                break;
128            }
129            $line = $this->threadItemFormatter->formatLine( $item, $this );
130            $list[] = Html::rawElement( 'li', [], $line );
131        }
132
133        $out->addHTML( $this->msg( $msgKey, count( $list ) )->parseAsBlock() );
134        $out->addHTML( Html::rawElement( 'ul', [], implode( '', $list ) ) );
135        if ( count( $threadItems ) > static::LIST_LIMIT ) {
136            $out->addHTML( $this->msg( 'morenotlisted' )->parseAsBlock() );
137        }
138    }
139
140    /**
141     * @inheritDoc
142     */
143    public function getDescription() {
144        return $this->msg( 'discussiontools-findcomment-title' );
145    }
146}