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