Mwjames has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/54504


Change subject: Final push to eliminate static storageData() in SMW\ParserData
......................................................................

Final push to eliminate static storageData() in SMW\ParserData

* Move stripMagicWords() out of SMW\ParserData and include it in
SMWParserExtensions::stripMagicWords where it is originally used
* Move equalDatavalues() to non-static method

Fixed a general issue in storageData() where an
array( '_MDAT', '_CDAT', '_FOO' ); would have caused a fatal
(due to bogus _FOO) and the creation of a ghost page when that
was redirected/moved.

Split up some scary spaghetti from SMWParserData:storageData() into
smaller helper methods

Double work about special properties (see SMWParserData:storageData()) is
now proper ecapsulate in addSpecialProperties().

Disable update jobs via disableUpdateJobs()

Fixed an issue where a large amount of subobjects embbeded in one page
would trigger a single job for each subobject even though
the ParserOuput and Title object for those subobjects are the same.

Static binding vs. constructor binding
SMWParseData::storeData( $output, $this->title, false ) is replaced by

$parserData = new SMW\ParserData( $title, $parserOutput );
$parserData->disableUpdateJobs();
$parserData->updateStore();

updateStore() is called from
* SMWUpdateJob::run
* SMWHooks::onLinksUpdateConstructed
* SMWHooks::onParserAfterTidy

Change-Id: I54fe629241191e141383c860d839e9e75d258add
---
M SemanticMediaWiki.hooks.php
M SemanticMediaWiki.settings.php
M includes/SMW_ParserExtensions.php
M includes/dataitems/SMW_DI_Property.php
M includes/jobs/SMW_UpdateJob.php
M includes/parserhooks/ParserData.php
6 files changed, 398 insertions(+), 48 deletions(-)


  git pull 
ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/SemanticMediaWiki 
refs/changes/04/54504/1

diff --git a/SemanticMediaWiki.hooks.php b/SemanticMediaWiki.hooks.php
index 49346c3..fcb4f89 100644
--- a/SemanticMediaWiki.hooks.php
+++ b/SemanticMediaWiki.hooks.php
@@ -438,27 +438,26 @@
         * @return true
         */
        public static function onParserAfterTidy( &$parser, &$text ) {
+               $cache = ObjectCache::getInstance( $GLOBALS['smwgCacheType'] );
 
                // Separate globals from local state
+               // FIXME Do a new SMW\Settings( $GLOBALS );
                $options = array(
                        'smwgUseCategoryHierarchy' => 
$GLOBALS['smwgUseCategoryHierarchy'],
                        'smwgCategoriesAsInstances' => 
$GLOBALS['smwgCategoriesAsInstances'],
                );
 
                $parserData = new SMW\ParserData( $parser->getTitle(), 
$parser->getOutput(), $options );
-
-               if ( !( $parserData->getData() instanceof SMWSemanticData ) ) {
-                       return true;
-               }
-
                $parserData->addCategories( 
$parser->getOutput()->getCategoryLinks() );
                $parserData->addDefaultSort( $parser->getDefaultSort() );
 
-               // If an article was was marked ensure that the store is 
updated as well
-               if( wfGetMainCache()->get( 'smw:autorefresh:' . 
$parser->getTitle()->getPrefixedDBkey() ) ){
-                       $parserData->storeData( true );
+               // If an article was was manually purged/moved ensure that the 
store is
+               // updated as well for all other cases onLinksUpdateConstructed 
will
+               // initiate the store update
+               if( $cache->get( 'smw:autorefresh:' . 
$parser->getTitle()->getPrefixedDBkey() ) ){
+                       $parserData->updateStore();
                }
-               wfGetMainCache()->delete( 'smw:autorefresh:' . 
$parser->getTitle()->getPrefixedDBkey() );
+               $cache->delete( 'smw:autorefresh:' . 
$parser->getTitle()->getPrefixedDBkey() );
 
                return true;
        }
@@ -479,7 +478,7 @@
         */
        public static function onLinksUpdateConstructed( $linksUpdate ) {
                $parserData = new SMW\ParserData( $linksUpdate->getTitle(), 
$linksUpdate->getParserOutput() );
-               $parserData->storeData( true );
+               $parserData->updateStore();
                return true;
        }
 
@@ -522,7 +521,7 @@
         * @return true
         */
        public static function onArticlePurge( &$wikiPage ) {
-               wfGetMainCache()->set(
+               ObjectCache::getInstance( $GLOBALS['smwgCacheType'] )->set(
                        'smw:autorefresh:' . 
$wikiPage->getTitle()->getPrefixedDBkey(),
                        $GLOBALS['smwgAutoRefreshOnPurge']
                );
@@ -549,7 +548,7 @@
         * @return true
         */
        public static function onTitleMoveComplete( &$oldTitle, &$newTitle, 
&$user, $oldId, $newId ) {
-               wfGetMainCache()->set(
+               ObjectCache::getInstance( $GLOBALS['smwgCacheType'] )->set(
                        'smw:autorefresh:' . $newTitle->getPrefixedDBkey(),
                        $GLOBALS['smwgAutoRefreshOnPageMove']
                );
@@ -565,6 +564,8 @@
         * Fetch additional information that is related to the saving that has 
just happened,
         * e.g. regarding the last edit date. In runs where this hook is not 
triggered, the
         * last DB entry (of MW) will be used to fill such properties.
+        *
+        * Called from LocalFile.php, SpecialImport.php, Article.php, Title.php
         *
         * @see 
http://www.mediawiki.org/wiki/Manual:Hooks/NewRevisionFromEditComplete
         *
@@ -587,6 +588,7 @@
                        return true;
                }
 
+               // FIXME Do a new SMW\Settings( $GLOBALS );
                $options = array(
                        'smwgPageSpecialProperties' => 
$GLOBALS['smwgPageSpecialProperties']
                );
diff --git a/SemanticMediaWiki.settings.php b/SemanticMediaWiki.settings.php
index 793dcd7..36fc19c 100644
--- a/SemanticMediaWiki.settings.php
+++ b/SemanticMediaWiki.settings.php
@@ -530,8 +530,19 @@
 ##
 
 ###
+# Sets Semantic MediaWiki object cache and is used to track temporary
+# changes in SMW
+#
+# @see http://www.mediawiki.org/wiki/$wgMainCacheType
+#
+# @since 1.9
+##
+$smwgCacheType = CACHE_ANYTHING;
+##
+
+###
 # Sets whether or not to refresh semantic data in the store when a page is
-# manually purged (requires $wgMainCacheType to be set)
+# manually purged (requires $smwgCacheType be set)
 #
 # @since 1.9
 ##
@@ -540,7 +551,7 @@
 
 ###
 # Sets whether or not to refresh semantic data in the store when a page was
-# moved (requires $wgMainCacheType to be set)
+# moved (requires $smwgCacheType be set)
 #
 # @since 1.9
 ##
diff --git a/includes/SMW_ParserExtensions.php 
b/includes/SMW_ParserExtensions.php
index 4fe2c73..989ce6b 100644
--- a/includes/SMW_ParserExtensions.php
+++ b/includes/SMW_ParserExtensions.php
@@ -2,10 +2,10 @@
 /**
  * Static class to collect all functions related to parsing wiki text in SMW.
  * It includes all parser function declarations and hooks.
- * 
+ *
  * @file SMW_ParserExtensions.php
  * @ingroup SMW
- * 
+ *
  * @author Markus Krötzsch
  * @author Denny Vrandecic
  */
@@ -29,7 +29,7 @@
        static public function onInternalParseBeforeLinks( Parser &$parser, 
&$text ) {
                global $smwgStoreAnnotations, $smwgLinksInValues;
 
-               SMWParseData::stripMagicWords( $text, $parser );
+               SMWParserExtensions::stripMagicWords( $text, $parser );
 
                // Store the results if enabled (we have to parse them in any 
case,
                // in order to clean the wiki source for further processing).
@@ -39,7 +39,7 @@
                // Process redirects, if any (it seems that there is indeed no 
more direct way of getting this info from MW)
                if ( $smwgStoreAnnotations ) {
                        $rt = Title::newFromRedirect( $text );
-                       
+
                        if ( !is_null( $rt ) ) {
                                $p = new SMWDIProperty( '_REDI' );
                                $di = SMWDIWikiPage::newFromTitle( $rt, '__red' 
);
@@ -178,4 +178,35 @@
                return $result;
        }
 
+       /**
+        * Remove relevant SMW magic words from the given text and return
+        * an array of the names of all discovered magic words. Moreover,
+        * store this array in the current parser output, using the variable
+        * mSMWMagicWords.
+        *
+        * @note moved from SMWParseData::stripMagicWords as it is only used
+        * in here
+        *
+        * @since  1.9
+        */
+       static public function stripMagicWords( &$text, Parser $parser ) {
+               $words = array();
+               $mw = MagicWord::get( 'SMW_NOFACTBOX' );
+
+               if ( $mw->matchAndRemove( $text ) ) {
+                       $words[] = 'SMW_NOFACTBOX';
+               }
+
+               $mw = MagicWord::get( 'SMW_SHOWFACTBOX' );
+
+               if ( $mw->matchAndRemove( $text ) ) {
+                       $words[] = 'SMW_SHOWFACTBOX';
+               }
+
+               $output = $parser->getOutput();
+               $output->mSMWMagicWords = $words;
+
+               return $words;
+       }
+
 }
diff --git a/includes/dataitems/SMW_DI_Property.php 
b/includes/dataitems/SMW_DI_Property.php
index f011e92..47f5337 100644
--- a/includes/dataitems/SMW_DI_Property.php
+++ b/includes/dataitems/SMW_DI_Property.php
@@ -23,7 +23,7 @@
        // Property improper value data item ID
        const TYPE_ERROR      = '_ERRP';
        // Property instance of a category
-       const TYPE_CATEGORY_INSTANCE = '_INST';
+       const TYPE_CATEGORY = '_INST';
        // Property "subcategory of"
        const TYPE_SUBCATEGORY = '_SUBC';
        // Property sort key of a page
@@ -36,6 +36,10 @@
        const TYPE_LAST_EDITOR = '_LEDT';
        // Property "is a new page"
        const TYPE_NEW_PAGE = '_NEWP';
+       // Property "has type"
+       const TYPE_HAS_TYPE = '_TYPE';
+       // Property "corresponds to"
+       const TYPE_CONVERSION = '_CONV';
 
        /**
         * Array for assigning types to predefined properties. Each
@@ -373,12 +377,12 @@
                // Properties without translation cannot be entered by or
                // displayed to users, whatever their "show" value below.
                SMWDIProperty::$m_prop_types = array(
-                               '_TYPE'  =>  array( '__typ', true ), // "has 
type"
+                               self::TYPE_HAS_TYPE =>  array( '__typ', true ), 
// "has type"
                                '_URI'   =>  array( '__spu', true ), // 
"equivalent URI"
-                               self::TYPE_CATEGORY_INSTANCE =>  array( 
'__sin', false ), // instance of a category
+                               self::TYPE_CATEGORY =>  array( '__sin', false 
), // instance of a category
                                '_UNIT'  =>  array( '__sps', true ), // 
"displays unit"
                                '_IMPO'  =>  array( '__imp', true ), // 
"imported from"
-                               '_CONV'  =>  array( '__sps', true ), // 
"corresponds to"
+                               self::TYPE_CONVERSION =>  array( '__sps', true 
), // "corresponds to"
                                '_SERV'  =>  array( '__sps', true ), // 
"provides service"
                                '_PVAL'  =>  array( '__sps', true ), // "allows 
value"
                                '_REDI'  =>  array( '__red', true ), // 
redirects to some page
diff --git a/includes/jobs/SMW_UpdateJob.php b/includes/jobs/SMW_UpdateJob.php
index 361732e..42693b4 100644
--- a/includes/jobs/SMW_UpdateJob.php
+++ b/includes/jobs/SMW_UpdateJob.php
@@ -28,6 +28,17 @@
        }
 
        /**
+        * Returns Title object
+        *
+        * @since 1.9
+        *
+        * @return \Title
+        */
+       public function getTitle() {
+               return $this->title;
+       }
+
+       /**
         * Run job
         * @return boolean success
         */
@@ -61,11 +72,15 @@
                wfProfileOut( __METHOD__ . '-parse' );
                wfProfileIn( __METHOD__ . '-update' );
 
-               SMWParseData::storeData( $output, $this->title, false );
-               
+               // @since 1.9
+               // SMWParseData::storeData( $output, $this->title, false );
+               $parserData = new SMW\ParserData( $this->title, $output );
+               $parserData->disableUpdateJobs();
+               $parserData->updateStore();
+
                wfProfileOut( __METHOD__ . '-update' );
                wfProfileOut( 'SMWUpdateJob::run (SMW)' );
-               
+
                return true;
        }
 
@@ -81,5 +96,5 @@
                        parent::insert();
                }
        }
-       
+
 }
diff --git a/includes/parserhooks/ParserData.php 
b/includes/parserhooks/ParserData.php
index 0ce28e0..c5d6106 100644
--- a/includes/parserhooks/ParserData.php
+++ b/includes/parserhooks/ParserData.php
@@ -6,7 +6,9 @@
 use WikiPage;
 use ParserOutput;
 use MWException;
+use Job;
 
+use SMWStore;
 use SMWDIWikiPage;
 use SMWPropertyValue;
 use SMWSemanticData;
@@ -15,6 +17,7 @@
 use SMWDIBlob;
 use SMWDIBoolean;
 use SMWDITime;
+use SMWUpdateJob;
 
 /**
  * Interface handling semantic data storage to a ParserOutput instance
@@ -90,11 +93,11 @@
        public function clearData();
 
        /**
-        * Stores semantic data to the database
+        * Updates the store with semantic data fetched from a ParserOutput 
object
         *
         * @since 1.9
         */
-       public function storeData( $runAsJob );
+       public function updateStore();
 
        /**
         * Returns an report about activities that occurred during processing
@@ -150,6 +153,12 @@
        protected $options;
 
        /**
+        * Represents invoked $smwgEnableUpdateJobs
+        * @var $updateJobs
+        */
+       protected $updateJobs = true;
+
+       /**
         * Allows explicitly to switch storage method, MW 1.21 comes with a new
         * method setExtensionData/getExtensionData in how the ParserOutput
         * stores arbitrary data
@@ -174,6 +183,7 @@
                $this->title = $title;
                $this->parserOutput = $parserOutput;
                $this->options = $options;
+               $this->updateJobs = $GLOBALS['smwgEnableUpdateJobs'];
                $this->setData();
        }
 
@@ -255,6 +265,16 @@
        }
 
        /**
+        * Explicitly disable update jobs (e.g when running store update
+        * in the job queue)
+        *
+        * @since 1.9
+        */
+       public function disableUpdateJobs() {
+               $this->updateJobs = false;
+       }
+
+       /**
         * Returns instantiated semanticData container
         *
         * @since 1.9
@@ -284,18 +304,6 @@
         */
        public function clearData() {
                $this->semanticData = new SMWSemanticData( $this->getSubject() 
);
-       }
-
-       /**
-        * Stores semantic data to the database
-        *
-        * @since 1.9
-        *
-        * @param boolean $runAsJob
-        */
-       public function storeData( $runAsJob = true ) {
-               // FIXME get rid of the static method
-               \SMWParseData::storeData( $this->getOutput(), 
$this->getTitle(), $runAsJob );
        }
 
        /**
@@ -388,6 +396,8 @@
         * from parser output, so that they are also replicated in SMW for more
         * efficient querying.
         *
+        * @see SMWHooks::onParserAfterTidy
+        *
         * @since 1.9
         *
         * @param array $categoryLinks
@@ -403,7 +413,7 @@
                foreach ( $categoryLinks as $catname ) {
                        if ( $this->options['smwgCategoriesAsInstances'] && ( 
$this->getTitle()->getNamespace() !== NS_CATEGORY ) ) {
                                $this->semanticData->addPropertyObjectValue(
-                                       new SMWDIProperty( 
SMWDIProperty::TYPE_CATEGORY_INSTANCE ),
+                                       new SMWDIProperty( 
SMWDIProperty::TYPE_CATEGORY ),
                                        new SMWDIWikiPage( $catname, 
NS_CATEGORY, '' )
                                );
                        }
@@ -419,6 +429,8 @@
 
        /**
         * Add default sort
+        *
+        * @see SMWHooks::onParserAfterTidy
         *
         * @since 1.9
         *
@@ -455,15 +467,15 @@
                        return true;
                }
 
-               // Keeps temporary account on processed properties
+               // Keeps temporary account over processed properties
                $processedProperty = array();
 
                foreach ( $this->options['smwgPageSpecialProperties'] as 
$propertyId ) {
 
                        // Ensure that only special properties are added that 
are registered
                        // and only added once
-                       if ( SMWDIProperty::getPredefinedPropertyTypeId( 
$propertyId ) === '' &&
-                               array_key_exists( $propertyId, 
$processedProperty ) ) {
+                       if ( ( SMWDIProperty::getPredefinedPropertyTypeId( 
$propertyId ) === '' ) ||
+                               ( array_key_exists( $propertyId, 
$processedProperty ) ) ) {
                                continue;
                        }
 
@@ -472,7 +484,6 @@
                        // Don't do a double round
                        if ( $this->semanticData->getPropertyValues( 
$propertyDI ) !== array() ) {
                                $processedProperty[ $propertyId ] = true;
-                               //var_dump( __METHOD__, 'check double', 
$propertyDI->getLabel() );
                                continue;
                        }
 
@@ -491,16 +502,292 @@
                                        $dataValue = new SMWDIBoolean( 
$revision->getParentId() !== '' );
                                        break;
                                case SMWDIProperty::TYPE_LAST_EDITOR :
-                                       //$revision = Revision::newFromTitle( 
$title );
-                                       //$user = User::newFromId( 
$revision->getUser() );
                                        $dataValue = 
SMWDIWikiPage::newFromTitle( $user->getUserPage() );
                                        break;
                        }
 
-                       if ( $dataValue instanceof SMWDataItem ) {
+                       if ( is_a( $dataValue, 'SMWDataItem' ) ) {
                                $processedProperty[ $propertyId ] = true;
                                $this->semanticData->addPropertyObjectValue( 
$propertyDI, $dataValue );
                        }
                }
        }
+
+       /**
+        * Updates the store with semantic data attached to a ParserOutput 
object
+        *
+        * This function takes care of storing the collected semantic data and 
takes
+        * care of clearing out any outdated entries for the processed page. It 
assume that
+        * parsing has happened and that all relevant data is contained in the 
provided parser
+        * output.
+        *
+        * Optionally, this function also takes care of triggering indirect 
updates that might be
+        * needed for overall database consistency. If the saved page describes 
a property or data type,
+        * the method checks whether the property type, the data type, the 
allowed values, or the
+        * conversion factors have changed. If so, it triggers SMWUpdateJobs 
for the relevant articles,
+        * which then asynchronously update the semantic data in the database.
+        *
+        * @todo FIXME: Some job generations here might create too many jobs at 
once
+        * on a large wiki. Use incremental jobs instead.
+        *
+        * To disable jobs either set $smwgEnableUpdateJobs = false or invoke
+        * SMW\ParserData::disableUpdateJobs()
+        *
+        * Called from SMWUpdateJob::run, SMWHooks::onLinksUpdateConstructed,
+        * SMWHooks::onParserAfterTidy
+        *
+        * @since 1.9
+        *
+        * @return boolean
+        */
+       public function updateStore() {
+               wfProfileIn( __METHOD__ );
+
+               // FIXME get rid of globals and use options array instead while
+               // invoking the constructor
+               $this->options = array(
+                       'smwgDeclarationProperties' => 
$GLOBALS['smwgDeclarationProperties'],
+                       'smwgPageSpecialProperties' => 
$GLOBALS['smwgPageSpecialProperties']
+               );
+
+               $namespace = $this->title->getNamespace();
+               $wikiPage = WikiPage::factory( $this->title );
+               $revision = $wikiPage->getRevision();
+               $store    = smwfGetStore();
+               $jobs     = array();
+
+               // Make sure to have a valid revision (null means delete etc.)
+               // Check if semantic data should be processed and displayed for 
a page in
+               // the given namespace
+               $processSemantics = $revision !== null ? 
smwfIsSemanticsProcessed( $namespace ) : false;
+
+               if ( $processSemantics ) {
+                       $user = \User::newFromId( $revision->getUser() );
+                       $this->addSpecialProperties( $wikiPage, $revision, 
$user );
+               } else {
+                       // data found, but do all operations as if it was empty
+                       $this->semanticData = new SMWSemanticData( 
$this->getSubject() );
+               }
+
+               // Careful: storage access must happen *before* the storage 
update;
+               // even finding uses of a property fails after its type was 
changed.
+               if ( $this->updateJobs && ( $namespace === SMW_NS_PROPERTY ) ) {
+                       $this->getDiffPropertyTypes( $store, $jobs );
+               } else if ( $this->updateJobs && ( $namespace === SMW_NS_TYPE ) 
) {
+                       $this->getDiffConversionFactors( $store, $jobs );
+               }
+
+               // Actually store semantic data, or at least clear it if needed
+               if ( $processSemantics ) {
+                       $store->updateData( $this->semanticData );
+               } else {
+                       $store->clearData( $this->semanticData->getSubject() );
+               }
+
+               // Job::batchInsert was deprecated in MW 1.21
+               // @see JobQueueGroup::singleton()->push( $job );
+               if ( $jobs !== array() ) {
+                       Job::batchInsert( $jobs );
+               }
+
+               wfProfileOut( __METHOD__ );
+
+               return true;
+       }
+
+       /**
+        * Helper method to handle diff/change in type property pages
+        *
+        * @note If it is a property, then we need to check if the type or the
+        * allowed values have been changed.
+        *
+        * @since 1.9
+        *
+        * @param SMWStore $store
+        * @param array &$jobs
+        */
+       protected function getDiffPropertyTypes( SMWStore $store, array &$jobs 
) {
+               wfProfileIn( __METHOD__ );
+
+               $updatejobflag = false;
+               $ptype = new SMWDIProperty( SMWDIProperty::TYPE_HAS_TYPE );
+
+               // Get values from the store
+               $oldtype = $store->getPropertyValues(
+                       $this->semanticData->getSubject(),
+                       $ptype
+               );
+
+               // Get values currently hold by the semantic container
+               $newtype = $this->semanticData->getPropertyValues( $ptype );
+
+               // Compare old and new type
+               if ( !$this->equalDatavalues( $oldtype, $newtype ) ) {
+                       $updatejobflag = true;
+               } else {
+                       // Compare values (in case of _PVAL (allowed values) 
for a
+                       // property change must be processed again)
+                       foreach ( $this->options['smwgDeclarationProperties'] 
as $prop ) {
+
+                               $dataItem = new SMWDIProperty( $prop );
+                               $oldValues = $store->getPropertyValues(
+                                       $this->semanticData->getSubject(),
+                                       $dataItem
+                               );
+                               $newValues = 
$this->semanticData->getPropertyValues( $dataItem );
+                               $updatejobflag = !$this->equalDatavalues( 
$oldValues, $newValues );
+                       }
+               }
+
+               // Job generation
+               if ( $updatejobflag ) {
+                       $prop = new SMWDIProperty( $this->title->getDBkey() );
+
+                       // Array of all subjects that have some value for the 
given property
+                       $subjects = $store->getAllPropertySubjects( $prop );
+
+                       // Add jobs
+                       $this->addJobs( $subjects, $jobs );
+
+                       // Hook
+                       wfRunHooks( 'smwUpdatePropertySubjects', array( &$jobs 
) );
+
+                       // Fetch all those that have an error property attached 
and
+                       // re-run it through the job-queue
+                       $subjects = $store->getPropertySubjects(
+                               new SMWDIProperty( SMWDIProperty::TYPE_ERROR ),
+                               $this->semanticData->getSubject()
+                       );
+
+                       // Add jobs
+                       $this->addJobs( $subjects, $jobs );
+               }
+
+               wfProfileOut( __METHOD__ );
+       }
+
+       /**
+        * Helper method to handle diff/change of conversion related properties
+        *
+        * @note if it is a type we need to check if the conversion factors
+        * have been changed
+        *
+        * @since 1.9
+        *
+        * @param SMWStore $store
+        * @param array &$jo
+        */
+       protected function getDiffConversionFactors( SMWStore $store, array 
&$jobs ) {
+               wfProfileIn( __METHOD__ );
+
+               $updatejobflag = false;
+               $pconv = new SMWDIProperty( SMWDIProperty::TYPE_CONVERSION );
+               $ptype = new SMWDIProperty( SMWDIProperty::TYPE_HAS_TYPE );
+
+               $oldfactors = smwfGetStore()->getPropertyValues(
+                       $this->semanticData->getSubject(),
+                       $pconv
+               );
+               $newfactors = $this->semanticData->getPropertyValues( $pconv );
+
+               // Compare
+               $updatejobflag = !$this->equalDatavalues( $oldfactors, 
$newfactors );
+
+               // Job generation
+               if ( $updatejobflag ) {
+
+                       /// FIXME: this will kill large wikis! Use incremental 
updates!
+                       $dataValue = SMWDataValueFactory::newTypeIdValue( 
'__typ', $title->getDBkey() );
+                       $propertyPages = $store->getPropertySubjects( $ptype, 
$dataValue );
+
+                       foreach ( $propertyPages as $propertyPage ) {
+                               // Add jobs
+                               $this->addJobs( array( $propertyPage ), $jobs );
+
+                               $prop = new SMWDIProperty( 
$propertyPage->getDBkey() );
+                               $subjects = $store->getAllPropertySubjects( 
$prop );
+
+                               // Add jobs
+                               $this->addJobs( $subjects, $jobs );
+
+                               $subjects = $store->getPropertySubjects(
+                                       new SMWDIProperty( 
SMWDIProperty::TYPE_ERROR  ),
+                                       $prop->getWikiPageValue()
+                               );
+
+                               // Add jobs
+                               $this->addJobs( $subjects, $jobs );
+                       }
+               }
+
+               wfProfileOut( __METHOD__ );
+       }
+
+       /**
+        * Helper method to iterate over an array of SMWDIWikiPage and return 
and
+        * array of SMWUpdateJob jobs
+        *
+        * Check whether a job with the same getPrefixedDBkey string (prefixed 
title,
+        * with underscores and any interwiki and namespace prefixes) is already
+        * registered and if so don't insert a new job. This is particular 
important
+        * for pages that include a large amount of subobjects where the same 
Title
+        * and ParserOutput object is used (subobjects are included using the 
same
+        * WikiPage which means the resulting ParserOutput object is the same)
+        *
+        * @since 1.9
+        *
+        * @param SMWDIWikiPage[] $subjects
+        * @param array &$jobs
+        */
+       protected function addJobs( array $subjects, &$jobs ) {
+
+               foreach ( $subjects as $subject ) {
+                       $duplicate = false;
+                       $subjectTitle = $subject->getTitle();
+
+                       if ( $subjectTitle instanceof Title ) {
+
+                               // Avoid duplicate jobs for the same title 
object
+                               foreach ( $jobs as $job ) {
+                                       if ( 
$job->getTitle()->getPrefixedDBkey() === $subjectTitle->getPrefixedDBkey() ){
+                                               $duplicate = true;
+                                               break;
+                                       }
+                               }
+                               if ( !$duplicate ) {
+                                       $jobs[] = new SMWUpdateJob( 
$subjectTitle );
+                               }
+                       }
+               }
+       }
+
+       /**
+        * Helper function that compares two arrays of data values to check 
whether
+        * they contain the same content. Returns true if the two arrays 
contain the
+        * same data values (irrespective of their order), false otherwise.
+        *
+        * @since  1.9
+        */
+       protected function equalDatavalues( $oldDataValue, $newDataValue ) {
+               // The hashes of all values of both arrays are taken, then 
sorted
+               // and finally concatenated, thus creating one long hash out of 
each
+               // of the data value arrays. These are compared.
+               $values = array();
+               foreach ( $oldDataValue as $v ) {
+                       $values[] = $v->getHash();
+               }
+
+               sort( $values );
+               $oldDataValueHash = implode( '___', $values );
+
+               $values = array();
+               foreach ( $newDataValue as $v ) {
+                       $values[] = $v->getHash();
+               }
+
+               sort( $values );
+               $newDataValueHash = implode( '___', $values );
+
+               return ( $oldDataValueHash == $newDataValueHash );
+       }
 }

-- 
To view, visit https://gerrit.wikimedia.org/r/54504
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I54fe629241191e141383c860d839e9e75d258add
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/SemanticMediaWiki
Gerrit-Branch: master
Gerrit-Owner: Mwjames <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to