* Fixed unclosed <p> tag
[lhc/web/wiklou.git] / includes / LinksUpdate.php
1 <?php
2 /**
3 * See deferred.txt
4 * @package MediaWiki
5 */
6
7 /**
8 * @todo document
9 * @package MediaWiki
10 */
11 class LinksUpdate {
12
13 /**#@+
14 * @access private
15 */
16 var $mId, $mTitle;
17 /**#@-*/
18
19 /**
20 * Constructor
21 * Initialize private variables
22 * @param integer $id
23 * @param string $title
24 */
25 function LinksUpdate( $id, $title ) {
26 $this->mId = $id;
27 $this->mTitle = $title;
28 }
29
30 /**
31 * Update link tables with outgoing links from an updated article
32 * Relies on the 'link cache' to be filled out.
33 */
34
35 function doUpdate() {
36 global $wgUseDumbLinkUpdate, $wgLinkCache, $wgDBtransactions;
37 global $wgUseCategoryMagic;
38
39 if ( $wgUseDumbLinkUpdate ) {
40 $this->doDumbUpdate();
41 return;
42 }
43
44 $fname = 'LinksUpdate::doUpdate';
45 wfProfileIn( $fname );
46
47 $del = array();
48 $add = array();
49
50 $dbw =& wfGetDB( DB_MASTER );
51 $pagelinks = $dbw->tableName( 'pagelinks' );
52 $imagelinks = $dbw->tableName( 'imagelinks' );
53 $categorylinks = $dbw->tableName( 'categorylinks' );
54
55 #------------------------------------------------------------------------------
56 # Good links
57
58 if ( $wgLinkCache->incrementalSetup( LINKCACHE_PAGE, $del, $add ) ) {
59 # Delete where necessary
60 if ( count( $del ) ) {
61 $batch = new LinkBatch( $del );
62 $set = $batch->constructSet( 'pl', $dbw );
63 if ( $set ) {
64 $sql = "DELETE FROM $pagelinks WHERE pl_from={$this->mId} AND ($set)";
65 $dbw->query( $sql, $fname );
66 }
67 }
68 } else {
69 # Delete everything
70 $dbw->delete( 'pagelinks', array( 'pl_from' => $this->mId ), $fname );
71
72 # Get the addition list
73 $add = $wgLinkCache->getPageLinks();
74 }
75
76 # Do the insertion
77 if( 0 != count( $add ) ) {
78 $arr = array();
79 foreach( $add as $lt => $target ) {
80 array_push( $arr, array(
81 'pl_from' => $this->mId,
82 'pl_namespace' => $target->getNamespace(),
83 'pl_title' => $target->getDbKey() ) );
84 }
85
86 # The link cache was constructed without FOR UPDATE, so there may be collisions
87 # Ignoring for now, I'm not sure if that causes problems or not, but I'm fairly
88 # sure it's better than without IGNORE
89 $dbw->insert( 'pagelinks', $arr, $fname, array( 'IGNORE' ) );
90 }
91
92 #------------------------------------------------------------------------------
93 # Image links
94 $dbw->delete('imagelinks',array('il_from'=>$this->mId),$fname);
95
96 # Get addition list
97 $add = $wgLinkCache->getImageLinks();
98
99 # Do the insertion
100 $sql = '';
101 $image = NS_IMAGE;
102 if ( 0 != count ( $add ) ) {
103 $arr = array();
104 foreach ($add as $iname => $val ) {
105 $nt = Title::makeTitle( $image, $iname );
106 if( !$nt ) continue;
107 $nt->invalidateCache();
108 array_push( $arr, array(
109 'il_from' => $this->mId,
110 'il_to' => $iname ) );
111 }
112 $dbw->insert('imagelinks', $arr, $fname, array('IGNORE'));
113 }
114
115 #------------------------------------------------------------------------------
116 # Category links
117 if( $wgUseCategoryMagic ) {
118 global $messageMemc, $wgDBname;
119
120 # Get addition list
121 $add = $wgLinkCache->getCategoryLinks();
122
123 # select existing catlinks for this page
124 $res = $dbw->select( 'categorylinks',
125 array( 'cl_to', 'cl_sortkey' ),
126 array( 'cl_from' => $this->mId ),
127 $fname,
128 'FOR UPDATE' );
129
130 $del = array();
131 if( 0 != $dbw->numRows( $res ) ) {
132 while( $row = $dbw->fetchObject( $res ) ) {
133 if( !isset( $add[$row->cl_to] ) || $add[$row->cl_to] != $row->cl_sortkey ) {
134 // in the db, but no longer in the page
135 // or sortkey has changed -> delete
136 $del[] = $row->cl_to;
137 } else {
138 // remove already existing category memberships
139 // from the add array
140 unset( $add[$row->cl_to] );
141 }
142 }
143 }
144
145 // delete any removed categorylinks
146 if( count( $del ) > 0) {
147 // delete old ones
148 $dbw->delete( 'categorylinks',
149 array(
150 'cl_from' => $this->mId,
151 'cl_to' => $del ),
152 $fname );
153 foreach( $del as $cname ){
154 $nt = Title::makeTitle( NS_CATEGORY, $cname );
155 $nt->invalidateCache();
156 // update the timestamp which indicates when the last article
157 // was added or removed to/from this article
158 $key = $wgDBname . ':Category:' . md5( $nt->getDBkey() ) . ':adddeltimestamp';
159 $messageMemc->set( $key , wfTimestamp( TS_MW ), 24*3600 );
160 }
161 }
162
163 // add any new category memberships
164 if( count( $add ) > 0 ) {
165 $arr = array();
166 foreach( $add as $cname => $sortkey ) {
167 $nt = Title::makeTitle( NS_CATEGORY, $cname );
168 $nt->invalidateCache();
169 // update the timestamp which indicates when the last article
170 // was added or removed to/from this article
171 $key = $wgDBname . ':Category:' . md5( $nt->getDBkey() ) . ':adddeltimestamp';
172 $messageMemc->set( $key , wfTimestamp( TS_MW ), 24*3600 );
173 array_push( $arr, array(
174 'cl_from' => $this->mId,
175 'cl_to' => $cname,
176 'cl_sortkey' => $sortkey ) );
177 }
178 // do the actual sql insertion
179 $dbw->insert( 'categorylinks', $arr, $fname, array( 'IGNORE' ) );
180 }
181 }
182
183 wfProfileOut( $fname );
184 }
185
186 /**
187 * Link update which clears the previous entries and inserts new ones
188 * May be slower or faster depending on level of lock contention and write speed of DB
189 * Also useful where link table corruption needs to be repaired, e.g. in refreshLinks.php
190 */
191 function doDumbUpdate() {
192 global $wgLinkCache, $wgDBtransactions, $wgUseCategoryMagic;
193 $fname = 'LinksUpdate::doDumbUpdate';
194 wfProfileIn( $fname );
195
196
197 $dbw =& wfGetDB( DB_MASTER );
198 $pagelinks = $dbw->tableName( 'pagelinks' );
199 $imagelinks = $dbw->tableName( 'imagelinks' );
200 $categorylinks = $dbw->tableName( 'categorylinks' );
201
202 $dbw->delete('pagelinks', array('pl_from'=>$this->mId),$fname);
203
204 $a = $wgLinkCache->getPageLinks();
205 if ( 0 != count( $a ) ) {
206 $arr = array();
207 foreach( $a as $lt => $target ) {
208 array_push( $arr, array(
209 'pl_from' => $this->mId,
210 'pl_namespace' => $target->getNamespace(),
211 'pl_title' => $target->getDBkey() ) );
212 }
213 $dbw->insert( 'pagelinks', $arr, $fname, array( 'IGNORE' ) );
214 }
215
216 $dbw->delete('imagelinks', array('il_from'=>$this->mId),$fname);
217
218 $a = $wgLinkCache->getImageLinks();
219 $sql = '';
220 if ( 0 != count ( $a ) ) {
221 $arr = array();
222 foreach( $a as $iname => $val )
223 array_push( $arr, array(
224 'il_from' => $this->mId,
225 'il_to' => $iname ) );
226 $dbw->insert( 'imagelinks', $arr, $fname, array( 'IGNORE' ) );
227 }
228
229 if( $wgUseCategoryMagic ) {
230 $dbw->delete('categorylinks', array('cl_from'=>$this->mId),$fname);
231
232 # Get addition list
233 $add = $wgLinkCache->getCategoryLinks();
234
235 # Do the insertion
236 $sql = '';
237 if ( 0 != count ( $add ) ) {
238 $arr = array();
239 foreach( $add as $cname => $sortkey ) {
240 # FIXME: Change all this to avoid unnecessary duplication
241 $nt = Title::makeTitle( NS_CATEGORY, $cname );
242 if( !$nt ) continue;
243 $nt->invalidateCache();
244 array_push( $arr, array(
245 'cl_from' => $this->mId,
246 'cl_to' => $cname,
247 'cl_sortkey' => $sortkey ) );
248 }
249 $dbw->insert( 'categorylinks', $arr, $fname, array( 'IGNORE' ) );
250 }
251 }
252 wfProfileOut( $fname );
253 }
254 }
255 ?>