Replace ugly abuse of log pages to store cached results of query pages
[lhc/web/wiklou.git] / includes / QueryPage.php
1 <?php
2
3 require_once ( "Feed.php" );
4
5 # This is a class for doing query pages; since they're almost all the same,
6 # we factor out some of the functionality into a superclass, and let
7 # subclasses derive from it.
8
9 class QueryPage {
10 # Subclasses return their name here. Make sure the name is also
11 # specified in Language.php, both in the $wgValidSpecialPagesEn
12 # variable, and as a language message param.
13
14 function getName() {
15 return "";
16 }
17
18 # Subclasses return an SQL query here.
19 #
20 # Note that the query itself should return the following three columns:
21 # 'type' (your special page's name), 'namespace, 'title', and 'value'
22 # (numeric) *in that order*. These may be stored in the querycache table
23 # for expensive queries, and that cached data will be returned sometimes,
24 # so the presence of extra fields can't be relied on.
25 #
26 # Don't include an ORDER or LIMIT clause, this will be added.
27
28 function getSQL() {
29 return "SELECT 'sample' as type, 0 as namespace, 'Sample result' as title, 42 as value";
30 }
31
32 # Override to sort by increasing values
33 function sortDescending() {
34 return true;
35 }
36
37 # Don't override this unless you're darn sure.
38 function getOrderLimit( $offset, $limit ) {
39 return " ORDER BY value " .
40 ($this->sortDescending() ? "DESC" : "")
41 . " LIMIT {$offset}, {$limit}";
42 }
43
44 # Is this query expensive (for some definition of expensive)? Then we
45 # don't let it run in miser mode. $wgDisableQueryPages causes all query
46 # pages to be declared expensive. Some query pages are always expensive.
47 function isExpensive( ) {
48 global $wgDisableQueryPages;
49 return $wgDisableQueryPages;
50 }
51
52 # Formats the results of the query for display. The skin is the current
53 # skin; you can use it for making links. The result is a single row of
54 # result data. You should be able to grab SQL results off of it.
55
56 function formatResult( $skin, $result ) {
57 return "";
58 }
59
60 # This is the actual workhorse. It does everything needed to make a
61 # real, honest-to-gosh query page.
62
63 function doQuery( $offset, $limit ) {
64 global $wgUser, $wgOut, $wgLang, $wgRequest;
65 global $wgMiserMode;
66
67 $sname = $this->getName();
68 $fname = get_class($this) . "::doQuery";
69 $sql = $this->getSQL( $offset, $limit );
70
71 $wgOut->setSyndicated( true );
72
73 if ( $this->isExpensive() ) {
74 $type = wfStrencode( $sname );
75 $recache = $wgRequest->getBool( "recache" );
76 if( $recache ) {
77 # Clear out any old cached data
78 $res = wfQuery( "DELETE FROM querycache WHERE qc_type='$type'", DB_WRITE, $fname );
79
80 # Save results into the querycache table
81 $maxstored = 1000;
82 $res = wfQuery(
83 "INSERT INTO querycache(qc_type,qc_namespace,qc_title,qc_value) " .
84 $this->getSQL() .
85 $this->getOrderLimit( 0, $maxstored ),
86 DB_WRITE, $fname );
87 }
88 if( $wgMiserMode || $recache ) {
89 $sql =
90 "SELECT qc_type as type, qc_namespace as namespace,qc_title as title, qc_value as value
91 FROM querycache WHERE qc_type='$type'";
92 }
93 if( $wgMiserMode ) {
94 $wgOut->addWikiText( wfMsg( "perfcached" ) );
95 }
96 }
97
98 $res = wfQuery( $sql . $this->getOrderLimit( $offset, $limit ), DB_READ, $fname );
99
100 $num = wfNumRows($res);
101
102 $sk = $wgUser->getSkin( );
103
104 $top = wfShowingResults( $offset, $num);
105 $wgOut->addHTML( "<p>{$top}\n" );
106
107 # often disable 'next' link when we reach the end
108 if($num < $limit) { $atend = true; } else { $atend = false; }
109
110 $sl = wfViewPrevNext( $offset, $limit , $wgLang->specialPage( $sname ), "" ,$atend );
111 $wgOut->addHTML( "<br />{$sl}</p>\n" );
112
113 $s = "<ol start='" . ( $offset + 1 ) . "'>";
114 while ( $obj = wfFetchObject( $res ) ) {
115 $format = $this->formatResult( $sk, $obj );
116 $s .= "<li>{$format}</li>\n";
117 }
118 wfFreeResult( $res );
119 $s .= "</ol>";
120 $wgOut->addHTML( $s );
121 $wgOut->addHTML( "<p>{$sl}</p>\n" );
122 }
123
124 # Similar to above, but packaging in a syndicated feed instead of a web page
125 function doFeed( $class = "" ) {
126 global $wgFeedClasses;
127 global $wgOut, $wgLanguageCode, $wgLang;
128 if( isset($wgFeedClasses[$class]) ) {
129 $feed = new $wgFeedClasses[$class](
130 $this->feedTitle(),
131 $this->feedDesc(),
132 $this->feedUrl() );
133 $feed->outHeader();
134
135 $sql = $this->getSQL( 0, 50 );
136 $res = wfQuery( $sql, DB_READ, "QueryPage::doFeed" );
137 while( $obj = wfFetchObject( $res ) ) {
138 $item = $this->feedResult( $obj );
139 if( $item ) $feed->outItem( $item );
140 }
141 wfFreeResult( $res );
142
143 $feed->outFooter();
144 return true;
145 } else {
146 return false;
147 }
148 }
149
150 # Override for custom handling. If the titles/links are ok, just do feedItemDesc()
151 function feedResult( $row ) {
152 if( !isset( $row->title ) ) {
153 return NULL;
154 }
155 $title = Title::MakeTitle( IntVal( $row->namespace ), $row->title );
156 if( $title ) {
157 if( isset( $row->timestamp ) ) {
158 $date = $row->timestamp;
159 } else {
160 $date = "";
161 }
162
163 $comments = "";
164 if( $title ) {
165 $talkpage = $title->getTalkPage();
166 $comments = $talkpage->getFullURL();
167 }
168
169 return new FeedItem(
170 $title->getText(),
171 $this->feedItemDesc( $row ),
172 $title->getFullURL(),
173 $date,
174 $this->feedItemAuthor( $row ),
175 $comments);
176 } else {
177 return NULL;
178 }
179 }
180
181 function feedItemDesc( $row ) {
182 $text = "";
183 if( isset( $row->comment ) ) {
184 $text = htmlspecialchars( $row->comment );
185 } else {
186 $text = "";
187 }
188
189 if( isset( $row->text ) ) {
190 $text = "<p>" . htmlspecialchars( wfMsg( "summary" ) ) . ": " . $text . "</p>\n<hr />\n<div>" .
191 nl2br( htmlspecialchars( $row->text ) ) . "</div>";;
192 }
193 return $text;
194 }
195
196 function feedItemAuthor( $row ) {
197 if( isset( $row->user_text ) ) {
198 return $row->user_text;
199 } else {
200 return "";
201 }
202 }
203
204 function feedTitle() {
205 global $wgLanguageCode, $wgSitename, $wgLang;
206 $pages = $wgLang->getValidSpecialPages();
207 $title = $pages[$this->getName()];
208 return "$wgSitename - $title [$wgLanguageCode]";
209 }
210
211 function feedDesc() {
212 return wfMsg( "fromwikipedia" );
213 }
214
215 function feedUrl() {
216 global $wgLang;
217 $title = Title::MakeTitle( NS_SPECIAL, $this->getName() );
218 return $title->getFullURL();
219 }
220 }
221
222 # This is a subclass for very simple queries that are just looking for page
223 # titles that match some criteria. It formats each result item as a link to
224 # that page.
225
226 class PageQueryPage extends QueryPage {
227
228 function formatResult( $skin, $result ) {
229 $nt = Title::makeTitle( $result->namespace, $result->title );
230 return $skin->makeKnownLinkObj( $nt, "" );
231 }
232 }
233
234 ?>