1<?php
2
3use MediaWiki\MediaWikiServices;
4use MediaWiki\Revision\RevisionLookup;
5use MediaWiki\Revision\RevisionRecord;
6use MediaWiki\Revision\SlotRecord;
7
8/**
9 * Transitional trait used to share the methods between SearchResult and RevisionSearchResult.
10 * All the content of this trait can be moved to RevisionSearchResult once SearchResult is finally
11 * refactored into an abstract class.
12 * NOTE: This trait MUST NOT be used by something else than SearchResult and RevisionSearchResult.
13 * It will be removed without deprecation period once SearchResult
14 */
15trait RevisionSearchResultTrait {
16	/**
17	 * @var RevisionRecord
18	 */
19	protected $mRevisionRecord = null;
20
21	/**
22	 * @var File
23	 */
24	protected $mImage = null;
25
26	/**
27	 * @var Title|null
28	 */
29	protected $mTitle;
30
31	/**
32	 * @var string
33	 */
34	protected $mText;
35
36	/**
37	 * Initialize from a Title and if possible initializes a corresponding
38	 * RevisionRecord and File.
39	 *
40	 * @param Title|null $title
41	 */
42	protected function initFromTitle( $title ) {
43		$this->mTitle = $title;
44		if ( $title !== null ) {
45			$services = MediaWikiServices::getInstance();
46			$id = false;
47			Hooks::runner()->onSearchResultInitFromTitle( $title, $id );
48
49			$this->mRevisionRecord = $services->getRevisionLookup()->getRevisionByTitle(
50				$title,
51				$id,
52				RevisionLookup::READ_NORMAL
53			);
54			if ( $title->getNamespace() === NS_FILE ) {
55				$this->mImage = $services->getRepoGroup()->findFile( $title );
56			}
57		}
58	}
59
60	/**
61	 * Check if this is result points to an invalid title
62	 *
63	 * @return bool
64	 */
65	public function isBrokenTitle() {
66		return $this->mTitle === null;
67	}
68
69	/**
70	 * Check if target page is missing, happens when index is out of date
71	 *
72	 * @return bool
73	 */
74	public function isMissingRevision() {
75		return !$this->mRevisionRecord && !$this->mImage;
76	}
77
78	/**
79	 * @return Title|null
80	 */
81	public function getTitle() {
82		return $this->mTitle;
83	}
84
85	/**
86	 * Get the file for this page, if one exists
87	 * @return File|null
88	 */
89	public function getFile() {
90		return $this->mImage;
91	}
92
93	/**
94	 * Lazy initialization of article text from DB
95	 */
96	protected function initText() {
97		if ( !isset( $this->mText ) ) {
98			if ( $this->mRevisionRecord != null ) {
99				$content = $this->mRevisionRecord->getContent( SlotRecord::MAIN );
100				$this->mText = $content !== null ? $content->getTextForSearchIndex() : '';
101			} else { // TODO: can we fetch raw wikitext for commons images?
102				$this->mText = '';
103			}
104		}
105	}
106
107	/**
108	 * @param string[] $terms Terms to highlight (this parameter is deprecated and ignored)
109	 * @return string Highlighted text snippet, null (and not '') if not supported
110	 */
111	public function getTextSnippet( $terms = [] ) {
112		return '';
113	}
114
115	/**
116	 * @return string Highlighted title, '' if not supported
117	 */
118	public function getTitleSnippet() {
119		return '';
120	}
121
122	/**
123	 * @return string Highlighted redirect name (redirect to this page), '' if none or not supported
124	 */
125	public function getRedirectSnippet() {
126		return '';
127	}
128
129	/**
130	 * @return Title|null Title object for the redirect to this page, null if none or not supported
131	 */
132	public function getRedirectTitle() {
133		return null;
134	}
135
136	/**
137	 * @return string Highlighted relevant section name, null if none or not supported
138	 */
139	public function getSectionSnippet() {
140		return '';
141	}
142
143	/**
144	 * @return Title|null Title object (pagename+fragment) for the section,
145	 *  null if none or not supported
146	 */
147	public function getSectionTitle() {
148		return null;
149	}
150
151	/**
152	 * @return string Highlighted relevant category name or '' if none or not supported
153	 */
154	public function getCategorySnippet() {
155		return '';
156	}
157
158	/**
159	 * @return string Timestamp
160	 */
161	public function getTimestamp() {
162		if ( $this->mRevisionRecord ) {
163			return $this->mRevisionRecord->getTimestamp();
164		} elseif ( $this->mImage ) {
165			return $this->mImage->getTimestamp();
166		}
167		return '';
168	}
169
170	/**
171	 * @return int Number of words
172	 */
173	public function getWordCount() {
174		$this->initText();
175		return str_word_count( $this->mText );
176	}
177
178	/**
179	 * @return int Size in bytes
180	 */
181	public function getByteSize() {
182		$this->initText();
183		return strlen( $this->mText );
184	}
185
186	/**
187	 * @return string Interwiki prefix of the title (return iw even if title is broken)
188	 */
189	public function getInterwikiPrefix() {
190		return '';
191	}
192
193	/**
194	 * @return string Interwiki namespace of the title (since we likely can't resolve it locally)
195	 */
196	public function getInterwikiNamespaceText() {
197		return '';
198	}
199
200	/**
201	 * Did this match file contents (eg: PDF/DJVU)?
202	 * @return bool
203	 */
204	public function isFileMatch() {
205		return false;
206	}
207}
208