Mwjames has uploaded a new change for review.

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


Change subject: Split up ParserData responsibility, move store update into 
ParserDataStorage
......................................................................

Split up ParserData responsibility, move store update into ParserDataStorage

ParserData now only handles methods directly involved in
manipulating the ParserOutput/Semenatic Data object while
ParserDataStorage handles the update of the store with
the data coming from the ParserData object.

Change-Id: Iaa1a3d9d08918f33a98792b3ea2e9d7c5747dba5
---
M SemanticMediaWiki.hooks.php
M includes/ParserData.php
A includes/ParserDataStorage.php
M includes/Setup.php
M includes/jobs/SMW_UpdateJob.php
A tests/phpunit/includes/ParserDataStorageTest.php
M tests/phpunit/includes/ParserDataTest.php
M tests/phpunit/includes/parserhooks/AskParserFunctionTest.php
M tests/phpunit/includes/parserhooks/ConceptParserFunctionTest.php
M tests/phpunit/includes/parserhooks/SetParserFunctionTest.php
M tests/phpunit/includes/parserhooks/ShowParserFunctionTest.php
M tests/phpunit/includes/parserhooks/SubobjectParserFunctionTest.php
12 files changed, 495 insertions(+), 353 deletions(-)


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

diff --git a/SemanticMediaWiki.hooks.php b/SemanticMediaWiki.hooks.php
index f0d45a5..27941cd 100644
--- a/SemanticMediaWiki.hooks.php
+++ b/SemanticMediaWiki.hooks.php
@@ -486,12 +486,12 @@
 
                // Separate globals from local state
                // FIXME Do a new SMW\Settings( $GLOBALS );
-               $options = array(
+               $settings = array(
                        'smwgUseCategoryHierarchy' => 
$GLOBALS['smwgUseCategoryHierarchy'],
                        'smwgCategoriesAsInstances' => 
$GLOBALS['smwgCategoriesAsInstances'],
                );
 
-               $parserData = new SMW\ParserData( $parser->getTitle(), 
$parser->getOutput(), $options );
+               $parserData = new SMW\ParserData( $parser->getTitle(), 
$parser->getOutput(), $settings );
                $parserData->addCategories( 
$parser->getOutput()->getCategoryLinks() );
                $parserData->addDefaultSort( $parser->getDefaultSort() );
 
@@ -499,7 +499,8 @@
                // updated as well for all other cases onLinksUpdateConstructed 
will
                // initiate the store update
                if( $cache->get( 'smw:autorefresh:' . 
$parser->getTitle()->getPrefixedDBkey() ) ){
-                       $parserData->updateStore();
+                       $parserDataStorage = new SMW\ParserDataStorage( 
$parserData );
+                       $parserDataStorage->updateStore();
                }
                $cache->delete( 'smw:autorefresh:' . 
$parser->getTitle()->getPrefixedDBkey() );
 
@@ -521,8 +522,11 @@
         * @return true
         */
        public static function onLinksUpdateConstructed( $linksUpdate ) {
-               $parserData = new SMW\ParserData( $linksUpdate->getTitle(), 
$linksUpdate->getParserOutput() );
-               $parserData->updateStore();
+               $parserDataStorage = new SMW\ParserDataStorage( new 
SMW\ParserData(
+                       $linksUpdate->getTitle(),
+                       $linksUpdate->getParserOutput() )
+               );
+               $parserDataStorage->updateStore();
                return true;
        }
 
diff --git a/includes/ParserData.php b/includes/ParserData.php
index f77b365..4dcd8a1 100644
--- a/includes/ParserData.php
+++ b/includes/ParserData.php
@@ -6,9 +6,7 @@
 use WikiPage;
 use ParserOutput;
 use MWException;
-use Job;
 
-use SMWStore;
 use SMWDIWikiPage;
 use SMWPropertyValue;
 use SMWSemanticData;
@@ -17,7 +15,6 @@
 use SMWDIBlob;
 use SMWDIBoolean;
 use SMWDITime;
-use SMWUpdateJob;
 
 /**
  * Interface handling semantic data storage to a ParserOutput instance
@@ -93,13 +90,6 @@
        public function clearData();
 
        /**
-        * Updates the store with semantic data fetched from a ParserOutput 
object
-        *
-        * @since 1.9
-        */
-       public function updateStore();
-
-       /**
         * Returns an report about activities that occurred during processing
         *
         * @since 1.9
@@ -132,39 +122,28 @@
 
        /**
         * Represents Title object
-        * @var $title
         */
        protected $title;
 
        /**
         * Represents ParserOutput object
-        * @var $parserOutput
         */
        protected $parserOutput;
 
        /**
         * Represents SMWSemanticData object
-        * @var $semanticData
         */
        protected $semanticData;
 
        /**
         * Represents collected errors
-        * @var $errors
         */
        protected $errors = array();
 
        /**
         * Represents invoked GLOBALS
-        * @var $options
         */
-       protected $options;
-
-       /**
-        * Represents invoked $smwgEnableUpdateJobs
-        * @var $updateJobs
-        */
-       protected $updateJobs = true;
+       protected $settings;
 
        /**
         * Allows explicitly to switch storage method, MW 1.21 comes with a new
@@ -185,13 +164,12 @@
         *
         * @param \Title $title
         * @param \ParserOutput $parserOutput
-        * @param array $options
+        * @param array $settings
         */
-       public function __construct( Title $title, ParserOutput $parserOutput, 
array $options = array() ) {
+       public function __construct( Title $title, ParserOutput $parserOutput, 
array $settings = array() ) {
                $this->title = $title;
                $this->parserOutput = $parserOutput;
-               $this->options = $options;
-               $this->updateJobs = $GLOBALS['smwgEnableUpdateJobs'];
+               $this->settings = $settings;
                $this->setData();
        }
 
@@ -273,16 +251,6 @@
        }
 
        /**
-        * 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
@@ -290,18 +258,6 @@
         * @return \SMWSemanticData
         */
        public function getData() {
-               return $this->semanticData;
-       }
-
-       /**
-        * FIXME use getData() instead
-        * AskParserFunctionTest
-        *
-        * @since 1.9
-        *
-        * @return \SMWSemanticData
-        */
-       public function getSemanticData() {
                return $this->semanticData;
        }
 
@@ -420,14 +376,14 @@
 
                // Iterate over available categories
                foreach ( $categoryLinks as $catname ) {
-                       if ( $this->options['smwgCategoriesAsInstances'] && ( 
$this->getTitle()->getNamespace() !== NS_CATEGORY ) ) {
+                       if ( $this->settings['smwgCategoriesAsInstances'] && ( 
$this->getTitle()->getNamespace() !== NS_CATEGORY ) ) {
                                $this->semanticData->addPropertyObjectValue(
                                        new SMWDIProperty( 
SMWDIProperty::TYPE_CATEGORY ),
                                        new SMWDIWikiPage( $catname, 
NS_CATEGORY, '' )
                                );
                        }
 
-                       if ( $this->options['smwgUseCategoryHierarchy'] && ( 
$this->getTitle()->getNamespace() === NS_CATEGORY ) ) {
+                       if ( $this->settings['smwgUseCategoryHierarchy'] && ( 
$this->getTitle()->getNamespace() === NS_CATEGORY ) ) {
                                $this->semanticData->addPropertyObjectValue(
                                        new SMWDIProperty( 
SMWDIProperty::TYPE_SUBCATEGORY ),
                                        new SMWDIWikiPage( $catname, 
NS_CATEGORY, '' )
@@ -479,7 +435,7 @@
                // Keeps temporary account over processed properties
                $processedProperty = array();
 
-               foreach ( $this->options['smwgPageSpecialProperties'] as 
$propertyId ) {
+               foreach ( $GLOBALS['smwgPageSpecialProperties'] as $propertyId 
) {
 
                        // Ensure that only special properties are added that 
are registered
                        // and only added once
@@ -522,281 +478,4 @@
                }
        }
 
-       /**
-        * 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 );
-       }
 }
diff --git a/includes/ParserDataStorage.php b/includes/ParserDataStorage.php
new file mode 100644
index 0000000..7077030
--- /dev/null
+++ b/includes/ParserDataStorage.php
@@ -0,0 +1,375 @@
+<?php
+
+namespace SMW;
+
+use WikiPage;
+use Job;
+use Title;
+
+use SMWStore;
+use SMWDIWikiPage;
+use SMWDataValueFactory;
+use SMWDIProperty;
+use SMWUpdateJob;
+
+/**
+ * Update the store with the processed semantic data container provided by
+ * the ParserData object
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @since 1.9
+ *
+ * @file
+ * @ingroup SMW
+ * @ingroup ParserHooks
+ *
+ * @author Markus Krötzsch
+ * @author mwjames
+ */
+
+/**
+ * Class is responsible to update the store with the processed semantic data
+ * container provided by the ParserData object
+ *
+ * @ingroup SMW
+ * @ingroup ParserHooks
+ */
+class ParserDataStorage {
+
+       /**
+        * Represents IParserData object
+        */
+       protected $parserData;
+
+       /**
+        * Represents SMWSemanticData object
+        */
+       protected $semanticData;
+
+       /**
+        * Represents SMWStore object
+        */
+       protected $store;
+
+       /**
+        * Represents invoked GLOBALS
+        */
+       protected $settings;
+
+       /**
+        * Represents invoked $smwgEnableUpdateJobs
+        */
+       protected $updateJobs = true;
+
+       /**
+        * Constructor
+        *
+        * @since 1.9
+        *
+        * @param IParserData $parserData
+        * @param array $settings
+        */
+       public function __construct( IParserData $parserData, array $settings = 
array() ) {
+               $this->parserData = $parserData;
+               $this->store    = smwfGetStore();
+               $this->settings = $settings;
+               $this->updateJobs = $GLOBALS['smwgEnableUpdateJobs'];
+       }
+
+       /**
+        * Explicitly disable update jobs (e.g when running store update
+        * in the job queue)
+        *
+        * @since 1.9
+        */
+       public function disableUpdateJobs() {
+               $this->updateJobs = false;
+       }
+
+       /**
+        * 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__ );
+
+               $subject = $this->parserData->getSubject();
+               $namespace = $subject->getTitle()->getNamespace();
+               $wikiPage = WikiPage::factory( $subject->getTitle() );
+               $revision = $wikiPage->getRevision();
+               $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->parserData->addSpecialProperties( $wikiPage, 
$revision, $user );
+               } else {
+                       // data found, but do all operations as if it was empty
+                       $this->parserData->clearData();
+               }
+
+               // 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( $jobs );
+               } else if ( $this->updateJobs && ( $namespace === SMW_NS_TYPE ) 
) {
+                       $this->getDiffConversionFactors( $jobs );
+               }
+
+               // Actually store semantic data, or at least clear it if needed
+               if ( $processSemantics ) {
+                       $this->store->updateData( $this->parserData->getData() 
);
+               } else {
+                       $this->store->clearData( $subject );
+               }
+
+               // 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 array &$jobs
+        */
+       protected function getDiffPropertyTypes( array &$jobs ) {
+               wfProfileIn( __METHOD__ );
+
+               $updatejobflag = false;
+               $subject = $this->parserData->getSubject();
+               $ptype = new SMWDIProperty( SMWDIProperty::TYPE_HAS_TYPE );
+
+               // Get values from the store
+               $oldtype = $this->store->getPropertyValues(
+                       $subject,
+                       $ptype
+               );
+
+               // Get values currently hold by the semantic container
+               $newtype = $this->parserData->getData()->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 ( $GLOBALS['smwgDeclarationProperties'] as 
$prop ) {
+
+                               $dataItem = new SMWDIProperty( $prop );
+                               $oldValues = $this->store->getPropertyValues(
+                                       $subject,
+                                       $dataItem
+                               );
+                               $newValues = 
$this->parserData->getData()->getPropertyValues( $dataItem );
+                               $updatejobflag = !$this->equalDatavalues( 
$oldValues, $newValues );
+                       }
+               }
+
+               // Job generation
+               if ( $updatejobflag ) {
+                       $prop = new SMWDIProperty( $subject->getDBkey() );
+
+                       // Array of all subjects that have some value for the 
given property
+                       $subjects = $this->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 = $this->store->getPropertySubjects(
+                               new SMWDIProperty( SMWDIProperty::TYPE_ERROR ),
+                               $subject
+                       );
+
+                       // 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 SMWDIWikiPage $subject
+        * @param array &$jo
+        */
+       protected function getDiffConversionFactors( array &$jobs ) {
+               wfProfileIn( __METHOD__ );
+
+               $updatejobflag = false;
+               $subject = $this->parserData->getSubject();
+               $pconv = new SMWDIProperty( SMWDIProperty::TYPE_CONVERSION );
+               $ptype = new SMWDIProperty( SMWDIProperty::TYPE_HAS_TYPE );
+
+               $oldfactors = $this->store->getPropertyValues(
+                       $subject,
+                       $pconv
+               );
+               $newfactors = $this->parserData->getData()->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', $subject->getDBkey() );
+                       $propertyPages = $this->store->getPropertySubjects( 
$ptype, $dataValue );
+
+                       foreach ( $propertyPages as $propertyPage ) {
+                               // Add jobs
+                               $this->addJobs( array( $propertyPage ), $jobs );
+
+                               $prop = new SMWDIProperty( 
$propertyPage->getDBkey() );
+                               $subjects = 
$this->store->getAllPropertySubjects( $prop );
+
+                               // Add jobs
+                               $this->addJobs( $subjects, $jobs );
+
+                               $subjects = $this->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 );
+       }
+}
diff --git a/includes/Setup.php b/includes/Setup.php
index 3e71a40..70aeedc 100644
--- a/includes/Setup.php
+++ b/includes/Setup.php
@@ -132,6 +132,7 @@
        $wgAutoloadClasses['SMWParseData']              = $incDir . 
'SMW_ParseData.php';
        $wgAutoloadClasses['SMW\IParserData']           = $incDir . 
'ParserData.php';
        $wgAutoloadClasses['SMW\ParserData']            = $incDir . 
'ParserData.php';
+       $wgAutoloadClasses['SMW\ParserDataStorage']     = $incDir . 
'ParserDataStorage.php';
 
        // Article pages
        $apDir = $smwgIP . 'includes/articlepages/';
diff --git a/includes/jobs/SMW_UpdateJob.php b/includes/jobs/SMW_UpdateJob.php
index 42693b4..4ac2e22 100644
--- a/includes/jobs/SMW_UpdateJob.php
+++ b/includes/jobs/SMW_UpdateJob.php
@@ -74,9 +74,12 @@
 
                // @since 1.9
                // SMWParseData::storeData( $output, $this->title, false );
-               $parserData = new SMW\ParserData( $this->title, $output );
-               $parserData->disableUpdateJobs();
-               $parserData->updateStore();
+               $parserDataStorage = new SMW\ParserDataStorage( new 
SMW\ParserData(
+                       $this->title,
+                       $output )
+               );
+               $parserDataStorage->disableUpdateJobs();
+               $parserDataStorage->updateStore();
 
                wfProfileOut( __METHOD__ . '-update' );
                wfProfileOut( 'SMWUpdateJob::run (SMW)' );
diff --git a/tests/phpunit/includes/ParserDataStorageTest.php 
b/tests/phpunit/includes/ParserDataStorageTest.php
new file mode 100644
index 0000000..5448ab7
--- /dev/null
+++ b/tests/phpunit/includes/ParserDataStorageTest.php
@@ -0,0 +1,80 @@
+<?php
+
+namespace SMW\Test;
+
+use SMW\ParserDataStorage;
+use SMW\ParserData;
+
+use ParserOutput;
+use Title;
+
+/**
+ * Tests for the SMW\ParserDataStorage class
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @since 1.9
+ *
+ * @ingroup SMW
+ * @ingroup Test
+ *
+ * @group SMW
+ * @group SMWExtension
+ *
+ * @licence GNU GPL v2+
+ * @author mwjames
+ */
+class ParserDataStorageTest extends \MediaWikiTestCase {
+
+       /**
+        * Helper method to get title object
+        *
+        * @return Title
+        */
+       private function getTitle( $title ){
+               return Title::newFromText( $title );
+       }
+
+       /**
+        * Helper method to get ParserOutput object
+        *
+        * @return ParserOutput
+        */
+       private function getParserOutput(){
+               return new ParserOutput();
+       }
+
+       /**
+        * Helper method
+        *
+        * @return SMW\ParserData
+        */
+       private function getInstance( $titleName, ParserOutput $parserOutput ) {
+               $parserData = new ParserData( $this->getTitle( $titleName ), 
$parserOutput );
+               return new ParserDataStorage( $parserData );
+       }
+
+       /**
+        * Test instance
+        *
+        */
+       public function testConstructor() {
+               $instance = $this->getInstance( 'Foo', $this->getParserOutput() 
);
+               $this->assertInstanceOf( 'SMW\ParserDataStorage', $instance );
+       }
+
+}
diff --git a/tests/phpunit/includes/ParserDataTest.php 
b/tests/phpunit/includes/ParserDataTest.php
index 3c2df8a..689c506 100644
--- a/tests/phpunit/includes/ParserDataTest.php
+++ b/tests/phpunit/includes/ParserDataTest.php
@@ -105,17 +105,17 @@
                $instance->addPropertyValueString( $propertyName, $value );
 
                // Check the returned instance
-               $this->assertInstanceOf( 'SMWSemanticData', 
$instance->getSemanticData() );
+               $this->assertInstanceOf( 'SMWSemanticData', 
$instance->getData() );
                $this->assertCount( $error, $instance->getErrors() );
 
                // Check added properties
-               foreach ( $instance->getSemanticData()->getProperties() as $key 
=> $diproperty ){
+               foreach ( $instance->getData()->getProperties() as $key => 
$diproperty ){
 
                        $this->assertInstanceOf( 'SMWDIProperty', $diproperty );
                        $this->assertContains( $propertyName, 
$diproperty->getLabel() );
 
                        // Check added property values
-                       foreach ( 
$instance->getSemanticData()->getPropertyValues( $diproperty ) as $dataItem ){
+                       foreach ( $instance->getData()->getPropertyValues( 
$diproperty ) as $dataItem ){
                                $dataValue = 
SMWDataValueFactory::newDataItemValue( $dataItem, $diproperty );
                                if ( $dataValue->getDataItem()->getDIType() === 
SMWDataItem::TYPE_WIKIPAGE ){
                                        $this->assertContains( $value, 
$dataValue->getWikiValue() );
diff --git a/tests/phpunit/includes/parserhooks/AskParserFunctionTest.php 
b/tests/phpunit/includes/parserhooks/AskParserFunctionTest.php
index ddd3fa4..ea38f6e 100644
--- a/tests/phpunit/includes/parserhooks/AskParserFunctionTest.php
+++ b/tests/phpunit/includes/parserhooks/AskParserFunctionTest.php
@@ -215,10 +215,10 @@
                $parserData = new ParserData( $this->getTitle( $title ), 
$parserOutput );
 
                // Check the returned instance
-               $this->assertInstanceOf( 'SMWSemanticData', 
$parserData->getSemanticData() );
+               $this->assertInstanceOf( 'SMWSemanticData', 
$parserData->getData() );
 
                // Confirm subSemanticData objects for the SemanticData instance
-               foreach ( $parserData->getSemanticData()->getSubSemanticData() 
as $containerSemanticData ){
+               foreach ( $parserData->getData()->getSubSemanticData() as 
$containerSemanticData ){
                        $this->assertInstanceOf( 'SMWContainerSemanticData', 
$containerSemanticData );
                        $this->assertCount( $expected['queryCount'], 
$containerSemanticData->getProperties() );
 
diff --git a/tests/phpunit/includes/parserhooks/ConceptParserFunctionTest.php 
b/tests/phpunit/includes/parserhooks/ConceptParserFunctionTest.php
index b1dc488..670849e 100644
--- a/tests/phpunit/includes/parserhooks/ConceptParserFunctionTest.php
+++ b/tests/phpunit/includes/parserhooks/ConceptParserFunctionTest.php
@@ -192,16 +192,16 @@
                $parserData = new ParserData( $this->getTitle( $title ), 
$parserOutput );
 
                // Check the returned instance
-               $this->assertInstanceOf( 'SMWSemanticData', 
$parserData->getSemanticData() );
-               $this->assertCount( $expected['propertyCount'], 
$parserData->getSemanticData()->getProperties() );
+               $this->assertInstanceOf( 'SMWSemanticData', 
$parserData->getData() );
+               $this->assertCount( $expected['propertyCount'], 
$parserData->getData()->getProperties() );
 
                // Confirm concept property
-               foreach ( $parserData->getSemanticData()->getProperties() as 
$key => $diproperty ){
+               foreach ( $parserData->getData()->getProperties() as $key => 
$diproperty ){
                        $this->assertInstanceOf( 'SMWDIProperty', $diproperty );
                        $this->assertEquals( '_CONC' , $diproperty->getKey() );
 
                        // Confirm concept property values
-                       foreach ( 
$parserData->getSemanticData()->getPropertyValues( $diproperty ) as $dataItem ){
+                       foreach ( $parserData->getData()->getPropertyValues( 
$diproperty ) as $dataItem ){
                                $this->assertEquals( $expected['conceptQuery'], 
$dataItem->getConceptQuery() );
                                $this->assertEquals( $expected['conceptDocu'], 
$dataItem->getDocumentation() );
                                $this->assertEquals( $expected['conceptSize'], 
$dataItem->getSize() );
diff --git a/tests/phpunit/includes/parserhooks/SetParserFunctionTest.php 
b/tests/phpunit/includes/parserhooks/SetParserFunctionTest.php
index a286fbd..9a73b88 100644
--- a/tests/phpunit/includes/parserhooks/SetParserFunctionTest.php
+++ b/tests/phpunit/includes/parserhooks/SetParserFunctionTest.php
@@ -202,16 +202,16 @@
                $parserData = new ParserData( $this->getTitle( $title ), 
$parserOutput );
 
                // Check the returned instance
-               $this->assertInstanceOf( 'SMWSemanticData', 
$parserData->getSemanticData() );
-               $this->assertCount( $expected['propertyCount'], 
$parserData->getSemanticData()->getProperties() );
+               $this->assertInstanceOf( 'SMWSemanticData', 
$parserData->getData() );
+               $this->assertCount( $expected['propertyCount'], 
$parserData->getData()->getProperties() );
 
                // Check added properties
-               foreach ( $parserData->getSemanticData()->getProperties() as 
$key => $diproperty ){
+               foreach ( $parserData->getData()->getProperties() as $key => 
$diproperty ){
                        $this->assertInstanceOf( 'SMWDIProperty', $diproperty );
                        $this->assertContains( $diproperty->getLabel(), 
$expected['propertyLabel'] );
 
                        // Check added property values
-                       foreach ( 
$parserData->getSemanticData()->getPropertyValues( $diproperty ) as $dataItem ){
+                       foreach ( $parserData->getData()->getPropertyValues( 
$diproperty ) as $dataItem ){
                                $dataValue = 
SMWDataValueFactory::newDataItemValue( $dataItem, $diproperty );
                                if ( $dataValue->getDataItem()->getDIType() === 
SMWDataItem::TYPE_WIKIPAGE ){
                                        $this->assertContains( 
$dataValue->getWikiValue(), $expected['value'] );
diff --git a/tests/phpunit/includes/parserhooks/ShowParserFunctionTest.php 
b/tests/phpunit/includes/parserhooks/ShowParserFunctionTest.php
index d2daab8..188bed7 100644
--- a/tests/phpunit/includes/parserhooks/ShowParserFunctionTest.php
+++ b/tests/phpunit/includes/parserhooks/ShowParserFunctionTest.php
@@ -181,10 +181,10 @@
                $parserData = new ParserData( $this->getTitle( $title ), 
$parserOutput );
 
                // Check the returned instance
-               $this->assertInstanceOf( 'SMWSemanticData', 
$parserData->getSemanticData() );
+               $this->assertInstanceOf( 'SMWSemanticData', 
$parserData->getData() );
 
                // Confirm subSemanticData objects for the SemanticData instance
-               foreach ( $parserData->getSemanticData()->getSubSemanticData() 
as $containerSemanticData ){
+               foreach ( $parserData->getData()->getSubSemanticData() as 
$containerSemanticData ){
                        $this->assertInstanceOf( 'SMWContainerSemanticData', 
$containerSemanticData );
                        $this->assertCount( $expected['queryCount'], 
$containerSemanticData->getProperties() );
 
diff --git a/tests/phpunit/includes/parserhooks/SubobjectParserFunctionTest.php 
b/tests/phpunit/includes/parserhooks/SubobjectParserFunctionTest.php
index 228fb9c..8cff23a 100644
--- a/tests/phpunit/includes/parserhooks/SubobjectParserFunctionTest.php
+++ b/tests/phpunit/includes/parserhooks/SubobjectParserFunctionTest.php
@@ -267,10 +267,10 @@
                $parserData = new ParserData( $this->getTitle( $title ), 
$parserOutput );
 
                // Check the returned instance
-               $this->assertInstanceOf( 'SMWSemanticData', 
$parserData->getSemanticData() );
+               $this->assertInstanceOf( 'SMWSemanticData', 
$parserData->getData() );
 
                // Confirm subSemanticData objects for the SemanticData instance
-               foreach ( $parserData->getSemanticData()->getSubSemanticData() 
as $containerSemanticData ){
+               foreach ( $parserData->getData()->getSubSemanticData() as 
$containerSemanticData ){
                        $this->assertInstanceOf( 'SMWContainerSemanticData', 
$containerSemanticData );
                        $this->assertCount( $expected['propertyCount'], 
$containerSemanticData->getProperties() );
 

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: Iaa1a3d9d08918f33a98792b3ea2e9d7c5747dba5
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