Index: trunk/extensions/SemanticMediaWiki/includes/SMW_Hooks.php |
— | — | @@ -15,6 +15,7 @@ |
16 | 16 | function smwfParserHook(&$parser, &$text) { |
17 | 17 | global $smwgStoreAnnotations, $smwgTempStoreAnnotations, $smwgStoreActive; |
18 | 18 | SMWFactbox::initStorage($parser->getTitle()); // be sure we have our title, strange things happen in parsing |
| 19 | + SMWFactbox::setWritelock(true); // disallow changes to the title object by other hooks! |
19 | 20 | |
20 | 21 | // store the results if enabled (we have to parse them in any case, in order to |
21 | 22 | // clean the wiki source for further processing) |
— | — | @@ -58,6 +59,7 @@ |
59 | 60 | 'ExportRDF/' . $parser->getTitle()->getPrefixedText(), 'xmlmime=rdf' |
60 | 61 | )) . "\" />"); |
61 | 62 | |
| 63 | + SMWFactbox::setWritelock(false); // free Factbox again (the hope of course is that it is only reset after the data we just gathered was processed; but this then might be okay, e.g. if some jobs are processed) |
62 | 64 | return true; // always return true, in order not to stop MW's hook processing! |
63 | 65 | } |
64 | 66 | |
— | — | @@ -140,6 +142,7 @@ |
141 | 143 | // The hashes of all values of both arrays are taken, then sorted |
142 | 144 | // and finally concatenated, thus creating one long hash out of each |
143 | 145 | // of the data value arrays. These are compared. |
| 146 | + |
144 | 147 | $values = array(); |
145 | 148 | foreach($dv1 as $v) $values[] = $v->getHash(); |
146 | 149 | sort($values); |
— | — | @@ -148,8 +151,8 @@ |
149 | 152 | foreach($dv2 as $v) $values[] = $v->getHash(); |
150 | 153 | sort($values); |
151 | 154 | $dv2hash = implode("___", $values); |
152 | | - |
153 | | - return ($dv1hash == $dv2hash); |
| 155 | + |
| 156 | + return ($dv1hash == $dv2hash); |
154 | 157 | } |
155 | 158 | |
156 | 159 | /** |
— | — | @@ -159,7 +162,7 @@ |
160 | 163 | * conversion factors have changed. If so, it triggers SMWUpdateJobs for the relevant articles, |
161 | 164 | * which then asynchronously update the semantic data in the database. |
162 | 165 | * |
163 | | - * Known Bug -- TODO |
| 166 | + * Known bug/limitation -- TODO |
164 | 167 | * Updatejobs are triggered when a property or type definition has |
165 | 168 | * changed, so that all affected pages get updated. However, if a page |
166 | 169 | * uses a property but the given value caused an error, then there is |
— | — | @@ -169,43 +172,49 @@ |
170 | 173 | function smwfSaveDataForTitle($title) { |
171 | 174 | global $smwgEnableUpdateJobs; |
172 | 175 | $namespace = $title->getNamespace(); |
| 176 | + $processSemantics = smwfIsSemanticsProcessed($namespace); |
| 177 | + if ($processSemantics) { |
| 178 | + $newdata = SMWFactbox::$semdata; |
| 179 | + } else { // nothing stored, use empty container |
| 180 | + $dv = SMWDataValueFactory::newTypeIDValue('_wpg'); |
| 181 | + $dv->setValues($title->getDBkey(), $title->getNamespace()); |
| 182 | + $newdata = new SMWSemanticData($dv); |
| 183 | + } |
173 | 184 | |
174 | 185 | // Check if the semantic data has been changed. |
175 | 186 | // Sets the updateflag to true if so. |
| 187 | + // Careful: storage access must happen *before* the storage update; |
| 188 | + // even finding uses of a property fails after its type was changed. |
176 | 189 | $updatejobflag = false; |
| 190 | + $jobs = array(); |
177 | 191 | if ($smwgEnableUpdateJobs && ($namespace == SMW_NS_PROPERTY) ) { |
178 | 192 | // if it is a property, then we need to check if the type or |
179 | | - // the allowed values have been changed |
| 193 | + // the allowed values have been changed |
180 | 194 | $oldtype = smwfGetStore()->getSpecialValues($title, SMW_SP_HAS_TYPE); |
181 | | - $newtype = SMWFactbox::$semdata->getPropertyValues(SMW_SP_HAS_TYPE); |
182 | | - |
183 | | - if (smwfEqualDatavalues($oldtype, $newtype)) { |
| 195 | + $newtype = $newdata->getPropertyValues(SMW_SP_HAS_TYPE); |
| 196 | + |
| 197 | + if (!smwfEqualDatavalues($oldtype, $newtype)) { |
184 | 198 | $updatejobflag = true; |
185 | 199 | } else { |
186 | 200 | $oldvalues = smwfGetStore()->getSpecialValues($title, SMW_SP_POSSIBLE_VALUE); |
187 | | - $newvalues = SMWFactbox::$semdata->getPropertyValues(SMW_SP_POSSIBLE_VALUE); |
188 | | - $updatejobflag = smwfEqualDatavalues($oldvalues, $newvalues); |
| 201 | + $newvalues = $newdata->getPropertyValues(SMW_SP_POSSIBLE_VALUE); |
| 202 | + $updatejobflag = !smwfEqualDatavalues($oldvalues, $newvalues); |
189 | 203 | } |
190 | | - } elseif ($smwgEnableUpdateJobs && ($namespace == SMW_NS_TYPE) ) { |
191 | | - // if it is a type we need to check if the conversion factors have been changed |
192 | | - $oldfactors = smwfGetStore()->getSpecialValues($title, SMW_SP_CONVERSION_FACTOR); |
193 | | - $newfactors = SMWFactbox::$semdata->getPropertyValues(SMW_SP_CONVERSION_FACTOR); |
194 | | - $updatejobflag = smwfEqualDatavalues($oldfactors, $newfactors); |
195 | | - } |
196 | 204 | |
197 | | - // Actually store semantic data |
198 | | - SMWFactbox::storeData(smwfIsSemanticsProcessed($title->getNamespace())); |
199 | | - |
200 | | - // Trigger relevant Updatejobs if necessary |
201 | | - if ($updatejobflag) { |
202 | | - $jobs = array(); |
203 | | - $store = smwfGetStore(); |
204 | | - if ($namespace == SMW_NS_PROPERTY) { |
205 | | - $subjects = $store->getAllPropertySubjects($title); |
| 205 | + if ($updatejobflag) { |
| 206 | + $subjects = smwfGetStore()->getAllPropertySubjects($title); |
206 | 207 | foreach ($subjects as $subject) { |
207 | 208 | $jobs[] = new SMWUpdateJob($subject); |
208 | 209 | } |
209 | | - } elseif ($namespace == SMW_NS_TYPE) { |
| 210 | + } |
| 211 | + } elseif ($smwgEnableUpdateJobs && ($namespace == SMW_NS_TYPE) ) { |
| 212 | + // if it is a type we need to check if the conversion factors have been changed |
| 213 | + $oldfactors = smwfGetStore()->getSpecialValues($title, SMW_SP_CONVERSION_FACTOR); |
| 214 | + $newfactors = $newdata->getPropertyValues(SMW_SP_CONVERSION_FACTOR); |
| 215 | + $updatejobflag = !smwfEqualDatavalues($oldfactors, $newfactors); |
| 216 | + if ($updatejobflag) { |
| 217 | + $store = smwfGetStore(); |
| 218 | + /// FIXME: this would kill large wikis! Use incremental updates! |
210 | 219 | $dv = SMWDataValueFactory::newSpecialValue(SMW_SP_HAS_TYPE,$title->getDBkey()); |
211 | 220 | $subjects = $store->getSpecialSubjects(SMW_SP_HAS_TYPE, $dv); |
212 | 221 | foreach ($subjects as $valueofpropertypagestoupdate) { |
— | — | @@ -216,6 +225,13 @@ |
217 | 226 | } |
218 | 227 | } |
219 | 228 | } |
| 229 | + } |
| 230 | + |
| 231 | + // Actually store semantic data |
| 232 | + SMWFactbox::storeData($processSemantics); |
| 233 | + |
| 234 | + // Trigger relevant Updatejobs if necessary |
| 235 | + if ($updatejobflag) { |
220 | 236 | Job::batchInsert($jobs); ///NOTE: this only happens if $smwgEnableUpdateJobs was true above |
221 | 237 | } |
222 | 238 | return true; |
Index: trunk/extensions/SemanticMediaWiki/includes/SMW_Factbox.php |
— | — | @@ -36,12 +36,19 @@ |
37 | 37 | static protected $m_blocked = false; |
38 | 38 | |
39 | 39 | /** |
| 40 | + * True *while* the Factbox is used for writing, prevents |
| 41 | + * broken submethods of MW and extensions to screw up our |
| 42 | + * subject title due to illegal $wgTitle uses in parsing. |
| 43 | + */ |
| 44 | + static protected $m_writelock = false; |
| 45 | + |
| 46 | + /** |
40 | 47 | * Initialisation method. Must be called before anything else happens. |
41 | 48 | */ |
42 | 49 | static function initStorage($title) { |
43 | 50 | // reset only if title exists, is new and is not the notorious |
44 | 51 | // NO TITLE thing the MW parser creates |
45 | | - if ( $title === NULL || $title->getText() == 'NO TITLE' ) return; |
| 52 | + if ( SMWFactbox::$m_writelock || $title === NULL || $title->getText() == 'NO TITLE' ) return; |
46 | 53 | if ( (SMWFactbox::$semdata === NULL) || |
47 | 54 | (SMWFactbox::$semdata->getSubject()->getDBkey() != $title->getDBkey()) || |
48 | 55 | (SMWFactbox::$semdata->getSubject()->getNamespace() != $title->getNamespace()) ) { |
— | — | @@ -64,7 +71,7 @@ |
65 | 72 | SMWFactbox::$m_printed = false; |
66 | 73 | } |
67 | 74 | } |
68 | | - |
| 75 | + |
69 | 76 | /** |
70 | 77 | * Blocks the next rendering of the Factbox |
71 | 78 | */ |
— | — | @@ -73,6 +80,15 @@ |
74 | 81 | } |
75 | 82 | |
76 | 83 | /** |
| 84 | + * Set the writlock (true while the Factbox is used for writing, |
| 85 | + * ensures that our title object cannot be changed by cross-firing |
| 86 | + * hooks). |
| 87 | + */ |
| 88 | + static function setWriteLock($value) { |
| 89 | + SMWFactbox::$m_writelock = $value; |
| 90 | + } |
| 91 | + |
| 92 | + /** |
77 | 93 | * True if the respective article is newly created, but always false until |
78 | 94 | * an article is actually saved. |
79 | 95 | */ |
Index: trunk/extensions/SemanticMediaWiki/includes/storage/SMW_SQLStore.php |
— | — | @@ -930,6 +930,11 @@ |
931 | 931 | if (count($up_nary_longstrings) > 0) { |
932 | 932 | $db->insert( 'smw_nary_longstrings', $up_nary_longstrings, 'SMW::updateNAryLongData'); |
933 | 933 | } |
| 934 | + |
| 935 | + if ($subject->getNamespace() == SMW_NS_PROPERTY) { // be sure that this is not invalid after update |
| 936 | + SMWDataValueFactory::clearTypeCache($subject); |
| 937 | + } |
| 938 | + |
934 | 939 | wfProfileOut("SMWSQLStore::updateData (SMW)"); |
935 | 940 | } |
936 | 941 | |
Index: trunk/extensions/SemanticMediaWiki/includes/storage/SMW_SQLStore2.php |
— | — | @@ -675,6 +675,7 @@ |
676 | 676 | ///FIXME: if a property page is deleted, more pages may need to be updated by jobs! |
677 | 677 | ///TODO: who is responsible for these updates? Some update jobs are currently created in SMW_Hooks, some internally in the store |
678 | 678 | ///TODO: Possibly delete ID here (at least for non-properties/categories, if not used in any place in rels2) |
| 679 | + ///FIXME: clean internal caches here |
679 | 680 | wfProfileOut('SMWSQLStore2::deleteSubject (SMW)'); |
680 | 681 | } |
681 | 682 | |
— | — | @@ -838,6 +839,12 @@ |
839 | 840 | $db->insert( 'smw_conc2', $up_conc2, 'SMW::updateConc2Data'); |
840 | 841 | } |
841 | 842 | |
| 843 | + $this->m_semdata[$sid] = clone $data; // update cache, important if jobs are directly following this call |
| 844 | + $this->m_sdstate[$sid] = 0xFFFFFFFF; // everything that one can know |
| 845 | + if ($subject->getNamespace() == SMW_NS_PROPERTY) { // be sure that this is not invalid after update |
| 846 | + SMWDataValueFactory::clearTypeCache($subject->getTitle()); |
| 847 | + } |
| 848 | + |
842 | 849 | wfProfileOut("SMWSQLStore2::updateData (SMW)"); |
843 | 850 | } |
844 | 851 | |
Index: trunk/extensions/SemanticMediaWiki/includes/SMW_DataValueFactory.php |
— | — | @@ -225,6 +225,17 @@ |
226 | 226 | } |
227 | 227 | |
228 | 228 | /** |
| 229 | + * Signal the class that the type of some property has changed. Clearing this |
| 230 | + * is crucial to let subsequent jobs work properly. |
| 231 | + */ |
| 232 | + static public function clearTypeCache(Title $property) { |
| 233 | + $propertyname = $property->getText(); |
| 234 | + if (array_key_exists($propertyname, SMWDataValueFactory::$m_typebyproperty)) { |
| 235 | + unset(SMWDataValueFactory::$m_typebyproperty[$propertyname]); |
| 236 | + } |
| 237 | + } |
| 238 | + |
| 239 | + /** |
229 | 240 | * Gather all available datatypes and label<=>id<=>datatype associations. This method |
230 | 241 | * is called before most methods of this factory. |
231 | 242 | */ |
Index: trunk/extensions/SemanticMediaWiki/includes/jobs/SMW_UpdateJob.php |
— | — | @@ -56,7 +56,7 @@ |
57 | 57 | wfProfileOut( __METHOD__.'-parse' ); |
58 | 58 | wfProfileIn( __METHOD__.'-update' ); |
59 | 59 | |
60 | | - SMWFactbox::storeData(true); /// FIXME: why is this just fixed to "true"? |
| 60 | + SMWFactbox::storeData(smwfIsSemanticsProcessed($this->title->getNamespace())); |
61 | 61 | wfProfileOut( __METHOD__.'-update' ); |
62 | 62 | wfProfileOut('SMWUpdateJob::run (SMW)'); |
63 | 63 | return true; |