EBernhardson has uploaded a new change for review.

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

Change subject: Split reusable parts out of ContributionsQuery
......................................................................

Split reusable parts out of ContributionsQuery

Change-Id: I8dac314453d1bdffe076007a57cb8b1aa7242431
---
M Flow.php
M container.php
A includes/Formatter/AbstractQuery.php
M includes/Formatter/ContributionsQuery.php
4 files changed, 270 insertions(+), 247 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Flow 
refs/changes/30/115530/1

diff --git a/Flow.php b/Flow.php
index d9a35ac..d167d42 100755
--- a/Flow.php
+++ b/Flow.php
@@ -136,6 +136,7 @@
 $wgAutoloadClasses['Flow\Log\Formatter'] = $dir . 'includes/Log/Formatter.php';
 $wgAutoloadClasses['Flow\Log\PostModerationLogger'] = $dir . 
'includes/Log/PostModerationLogger.php';
 $wgAutoloadClasses['Flow\Formatter\AbstractFormatter'] = $dir . 
'includes/Formatter/AbstractFormatter.php';
+$wgAutoloadClasses['Flow\Formatter\AbstractQuery'] = $dir . 
'includes/Formatter/AbstractQuery.php';
 $wgAutoloadClasses['Flow\Formatter\CheckUser'] = $dir . 
'includes/Formatter/CheckUser.php';
 $wgAutoloadClasses['Flow\Formatter\ContributionsQuery'] = $dir . 
'includes/Formatter/ContributionsQuery.php';
 $wgAutoloadClasses['Flow\Formatter\Contributions'] = $dir . 
'includes/Formatter/Contributions.php';
diff --git a/container.php b/container.php
index f9632cb..daa00ab 100644
--- a/container.php
+++ b/container.php
@@ -472,8 +472,8 @@
 $c['contributions.query'] = $c->share( function( $c ) {
        return new Flow\Formatter\ContributionsQuery(
                $c['storage'],
-               $c['memcache'],
-               $c['repository.tree']
+               $c['repository.tree'],
+               $c['memcache']
        );
 } );
 $c['contributions.formatter'] = $c->share( function( $c ) {
diff --git a/includes/Formatter/AbstractQuery.php 
b/includes/Formatter/AbstractQuery.php
new file mode 100644
index 0000000..94ac671
--- /dev/null
+++ b/includes/Formatter/AbstractQuery.php
@@ -0,0 +1,253 @@
+<?php
+
+namespace Flow\Formatter;
+
+use Flow\Model\AbstractRevision;
+use Flow\Model\PostRevision;
+use Flow\Model\Header;
+use Flow\Model\Workflow;
+use Flow\Data\ManagerGroup;
+use Flow\Model\UUID;
+use Flow\Repository\TreeRepository;
+
+/**
+ * Base class that collects the data necessary to utilize AbstractFormatter
+ * based on a list of revisions. In some cases formatters will not utilize
+ * this query and will instead receive data from a table such as the core
+ * recentchanges.
+ */
+abstract class AbstractQuery {
+       /**
+        * @var ManagerGroup
+        */
+       protected $storage;
+
+       /**
+        * @var TreeRepository
+        */
+       protected $treeRepo;
+
+       /**
+        * @var UUID[] Associative array of post ID to root post's UUID object.
+        */
+       protected $rootPostIdCache = array();
+
+       /**
+        * @var PostRevision[] Associative array of post ID to PostRevision 
object.
+        */
+       protected $postCache = array();
+
+       /**
+        * @var Workflow[] Associative array of workflow ID to Workflow object.
+        */
+       protected $workflowCache = array();
+
+       /**
+        * @param ManagerGroup $storage
+        * @param TreeRepository $treeRepo
+        */
+       public function __construct( ManagerGroup $storage, TreeRepository 
$treeRepo ) {
+               $this->storage = $storage;
+               $this->treeRepo = $treeRepo;
+       }
+
+       protected function loadMetadataBatch( $results ) {
+               // Batch load data related to a list of revisions
+               $postIds = array();
+               $workflowIds = array();
+               $previousRevisionIds = array();
+               foreach( $results as $result ) {
+                       if ( $result instanceof PostRevision ) {
+                               // If top-level, then just get the workflow.
+                               // Otherwise we need to find the root post.
+                               if ( $result->isTopicTitle() ) {
+                                       $workflowIds[] = $result->getPostId();
+                               } else {
+                                       $postIds[] = $result->getPostId();
+                               }
+                       } elseif ( $result instanceof Header ) {
+                               $workflowIds[] = $result->getWorkflowId();
+                       }
+
+                       $previousRevisionIds[get_class( $result )][] = 
$result->getPrevRevisionId();
+               }
+
+               // map from post Id to the related root post id
+               $rootPostIds = array_filter( $this->treeRepo->findRoots( 
$postIds ) );
+
+               $rootPostRequests = array();
+               foreach( $rootPostIds as $postId ) {
+                       $rootPostRequests[] = array( 'tree_rev_descendant_id' 
=> $postId );
+               }
+
+               $rootPostResult = $this->storage->findMulti(
+                       'PostRevision',
+                       $rootPostRequests,
+                       array(
+                               'SORT' => 'rev_id',
+                               'ORDER' => 'DESC',
+                               'LIMIT' => 1,
+                       )
+               );
+
+               $rootPosts = array();
+               if ( count( $rootPostResult ) > 0 ) {
+                       foreach ( $rootPostResult as $found ) {
+                               $root = reset( $found );
+                               
$rootPosts[$root->getPostId()->getAlphadecimal()] = $root;
+                       }
+               }
+
+               // Workflow IDs are the same as root post IDs
+               // So any post IDs that *are* root posts + found root post IDs 
+ header workflow IDs
+               // should cover the lot.
+               $workflows = $this->storage->getMulti( 'Workflow', array_merge( 
$rootPostIds, $workflowIds ) );
+
+               // preload all previous revisions
+               $previousRevisions = array();
+               foreach ( $previousRevisionIds as $revisionType => $ids ) {
+                       // get rid of null-values (for original revisions, 
without previous revision)
+                       $ids = array_filter( $ids );
+                       foreach ( $this->storage->getMulti( $revisionType, $ids 
) as $rev ) {
+                               
$previousRevisions[$rev->getRevisionId()->getAlphadecimal()] = $rev;
+                       }
+               }
+
+               $this->postCache = array_merge( $this->postCache, $rootPosts, 
$previousRevisions, $results );
+               $this->rootPostIdCache = array_merge( $this->rootPostIdCache, 
$rootPostIds );
+               $this->workflowCache = array_merge( $this->workflowCache, 
$workflows );
+       }
+
+       /*
+        * @param AbstractRevision $revision
+        * @param string $blockType Block name (e.g. "topic", "header")
+        * @param string $indexField The field used for pagination
+        * @return \stdClass
+        */
+       protected function buildResult( AbstractRevision $revision, $blockType, 
$indexField ) {
+               $uuid = $revision->getRevisionId();
+               $timestamp = $uuid->getTimestamp();
+               $fakeRow = array();
+
+               $workflow = $this->getWorkflow( $revision );
+               if ( !$workflow ) {
+                       wfWarn( __METHOD__ . ": could not locate workflow for 
revision " . $revision->getRevisionId()->getAlphadecimal() );
+                       return false;
+               }
+
+               // other contributions entries
+               $fakeRow[$indexField] = $timestamp; // used for navbar
+               $fakeRow['page_namespace'] = 
$workflow->getArticleTitle()->getNamespace();
+               $fakeRow['page_title'] = 
$workflow->getArticleTitle()->getDBkey();
+               $fakeRow['revision'] = $revision;
+               $fakeRow['previous_revision'] = $this->getPreviousRevision( 
$revision );
+               $fakeRow['workflow'] = $workflow;
+               $fakeRow['blocktype'] = $blockType;
+
+               if ( $revision instanceof PostRevision ) {
+                       $fakeRow['root_post'] = $this->getRootPost( $revision );
+                       if ( $fakeRow['root_post'] === null ) {
+                               wfWarn( __METHOD__ . ': no root post loaded for 
' . $revision->getRevisionId()->getAlphadecimal() );
+                       } else {
+                               $revision->setRootPost( $fakeRow['root_post'] );
+                       }
+               }
+
+               return (object) $fakeRow;
+       }
+
+       /**
+        * @param AbstractRevision $revision
+        * @return Workflow
+        * @throws \MWException
+        */
+       protected function getWorkflow( AbstractRevision $revision ) {
+               if ( $revision instanceof PostRevision ) {
+                       $rootPostId = $this->getRootPostId( $revision );
+
+                       return $this->getWorkflowById( $rootPostId );
+               } elseif ( $revision instanceof Header ) {
+                       return $this->getWorkflowById( 
$revision->getWorkflowId() );
+               } else {
+                       throw new \MWException( 'Unsupported revision type ' . 
get_class( $revision ) );
+               }
+       }
+
+       /**
+        * Retrieves the previous revision for a given AbstractRevision
+        * @param  AbstractRevision $revision The revision to retrieve the 
previous revision for.
+        * @return AbstractRevision|null      AbstractRevision of the previous 
revision or null if no previous revision.
+        */
+       protected function getPreviousRevision( AbstractRevision $revision ) {
+               $previousRevisionId = $revision->getPrevRevisionId();
+
+               // original post; no previous revision
+               if ( $previousRevisionId === null ) {
+                       return null;
+               }
+
+               if ( !isset( 
$this->postCache[$previousRevisionId->getAlphadecimal()] ) ) {
+                       
$this->postCache[$previousRevisionId->getAlphadecimal()] =
+                               $this->storage->get( 'PostRevision', 
$previousRevisionId );
+               }
+
+               return $this->postCache[$previousRevisionId->getAlphadecimal()];
+       }
+
+       /**
+        * Retrieves the root post for a given PostRevision
+        * @param  PostRevision $revision The revision to retrieve the root 
post for.
+        * @return PostRevision           PostRevision of the root post.
+        * @throws \MWException
+        */
+       protected function getRootPost( PostRevision $revision ) {
+               if ( $revision->isTopicTitle() ) {
+                       return $revision;
+               }
+               $rootPostId = $this->getRootPostId( $revision );
+
+               if ( !isset( $this->postCache[$rootPostId->getAlphadecimal()] ) 
) {
+                       throw new \MwException( 'Did not load root post ' . 
$rootPostId->getAlphadecimal() );
+               }
+
+               $rootPost = $this->postCache[$rootPostId->getAlphadecimal()];
+               if ( !$rootPost ) {
+                       throw new \MWException( 'Did not locate root post ' . 
$rootPostId->getAlphadecimal() );
+               }
+               if ( !$rootPost->isTopicTitle() ) {
+                       throw new \MWException( "Not a topic title: " . 
$rootPost->getRevisionId() );
+               }
+
+               return $rootPost;
+       }
+
+       /**
+        * Gets the root post ID for a given PostRevision
+        * @param  PostRevision $revision The revision to get the root post ID 
for.
+        * @return UUID                   The UUID for the root post.
+        * @throws \MWException
+        */
+       protected function getRootPostId( PostRevision $revision ) {
+               $postId = $revision->getPostId();
+               if ( $revision->isTopicTitle() ) {
+                       return $postId;
+               } elseif ( isset( 
$this->rootPostIdCache[$postId->getAlphadecimal()] ) ) {
+                       return 
$this->rootPostIdCache[$postId->getAlphadecimal()];
+               } else {
+                       throw new \MWException( "Unable to find root post ID 
for post $postId" );
+               }
+       }
+
+       /**
+        * Gets a Workflow object given its ID
+        * @param  UUID   $workflowId The Workflow ID to retrieve.
+        * @return Workflow           The Workflow.
+        */
+       protected function getWorkflowById( UUID $workflowId ) {
+               if ( isset( 
$this->workflowCache[$workflowId->getAlphadecimal()] ) ) {
+                       return 
$this->workflowCache[$workflowId->getAlphadecimal()];
+               } else {
+                       return 
$this->workflowCache[$workflowId->getAlphadecimal()] = $this->storage->get( 
'Workflow', $workflowId );
+               }
+       }
+}
diff --git a/includes/Formatter/ContributionsQuery.php 
b/includes/Formatter/ContributionsQuery.php
index 43f3209..fe7a3c8 100644
--- a/includes/Formatter/ContributionsQuery.php
+++ b/includes/Formatter/ContributionsQuery.php
@@ -2,60 +2,26 @@
 
 namespace Flow\Formatter;
 
-use ContribsPager;
-use Flow\Model\AbstractRevision;
-use Flow\Model\PostRevision;
-use Flow\Model\Header;
-use Flow\Model\Workflow;
-use Flow\Data\RawSql;
+use Flow\Container;
 use Flow\Data\ManagerGroup;
+use Flow\Data\RawSql;
+use Flow\Exception\FlowException;
 use Flow\Model\UUID;
 use Flow\Repository\TreeRepository;
-use Flow\Exception\FlowException;
-use User;
 use BagOStuff;
-use Flow\Container;
+use ContribsPager;
+use User;
 
-class ContributionsQuery {
-       /**
-        * @var ManagerGroup
-        */
-       protected $storage;
+class ContributionsQuery extends AbstractQuery {
 
        /**
         * @var BagOStuff
         */
        protected $cache;
 
-       /**
-        * @var TreeRepository
-        */
-       protected $treeRepo;
-
-       /**
-        * @var UUID[] Associative array of post ID to root post's UUID object.
-        */
-       protected $rootPostIdCache = array();
-
-       /**
-        * @var PostRevision[] Associative array of post ID to PostRevision 
object.
-        */
-       protected $postCache = array();
-
-       /**
-        * @var Workflow[] Associative array of workflow ID to Workflow object.
-        */
-       protected $workflowCache = array();
-
-       /**
-        * @param ManagerGroup $storage
-        * @param BagOStuff $cache
-        * @param TreeRepository $treeRepo
-        */
-       public function __construct( ManagerGroup $storage, BagOStuff $cache, 
TreeRepository $treeRepo ) {
-               $this->storage = $storage;
+       public function __construct( ManagerGroup $storage, TreeRepository 
$treeRepository, BagOStuff $cache ) {
+               parent::__construct( $storage, $treeRepository );
                $this->cache = $cache;
-               $this->treeRepo = $treeRepo;
        }
 
        /**
@@ -77,7 +43,7 @@
                        if ( $excludeUserIds ) {
                                // better safe than sorry - make sure 
everything's an int
                                $excludeUserIds = array_map( 'intval', 
$excludeUserIds );
-                               $conditions[] = new RawSql( 'rev_user_id NOT IN 
(' . implode( ',', $excludeUserIds ) .')' );
+                               $conditions[] = new RawSql( 'rev_user_id NOT IN 
( ' . implode( ',', $excludeUserIds ) . ' )' );
                        }
                } else {
                        $uid = User::idFromName( $target );
@@ -106,11 +72,14 @@
 
                $results = array();
                foreach ( $types as $revisionClass => $blockType ) {
-                       $revisions = $this->findRevisions( $pager, $conditions, 
$limit, $revisionClass );
+                       $revisions = $this->storage->find( $revisionClass, 
$conditions, array(
+                               'LIMIT' => $limit,
+                       ) );
                        $this->loadMetadataBatch( $revisions );
                        foreach ( $revisions as $revision ) {
                                try {
-                                       $result = $this->buildResult( $pager, 
$revision, $blockType );
+                                       $result = $this->buildResult( 
$revision, $blockType, $pager->getIndexField() );
+                                       $result->flow_contribution = 'flow';
                                } catch ( FlowException $e ) {
                                        $result = false;
                                        \MWExceptionHandler::logException( $e );
@@ -122,206 +91,6 @@
                }
 
                return $results;
-       }
-
-       protected function loadMetadataBatch( $results ) {
-               // Batch load data related to a list of revisions
-               $postIds = array();
-               $workflowIds = array();
-               $previousRevisionIds = array();
-               foreach( $results as $result ) {
-                       if ( $result instanceof PostRevision ) {
-                               // If top-level, then just get the workflow.
-                               // Otherwise we need to find the root post.
-                               if ( $result->isTopicTitle() ) {
-                                       $workflowIds[] = $result->getPostId();
-                               } else {
-                                       $postIds[] = $result->getPostId();
-                               }
-                       } elseif ( $result instanceof Header ) {
-                               $workflowIds[] = $result->getWorkflowId();
-                       }
-
-                       $previousRevisionIds[get_class( $result )][] = 
$result->getPrevRevisionId();
-               }
-
-               $rootPostIds = array_filter( $this->treeRepo->findRoots( 
$postIds ) );
-               $rootPostRequests = array();
-               foreach( $rootPostIds as $postId ) {
-                       $rootPostRequests[] = array( 'tree_rev_descendant_id' 
=> $postId );
-               }
-
-               $rootPostResult = $this->storage->findMulti(
-                       'PostRevision',
-                       $rootPostRequests,
-                       array(
-                               'SORT' => 'rev_id',
-                               'ORDER' => 'DESC',
-                               'LIMIT' => 1,
-                       )
-               );
-
-               if ( count( $rootPostResult ) > 0 ) {
-                       $rootPosts = call_user_func_array( 'array_merge', 
$rootPostResult ); // Muahaha
-               } else {
-                       $rootPosts = array();
-               }
-
-               // Workflow IDs are the same as root post IDs
-               // So any post IDs that *are* root posts + found root post IDs 
+ header workflow IDs
-               // should cover the lot.
-               $workflows = $this->storage->getMulti( 'Workflow', array_merge( 
$rootPostIds, $workflowIds ) );
-
-               // preload all previous revisions
-               $previousRevisions = array();
-               foreach ( $previousRevisionIds as $revisionType => $ids ) {
-                       // get rid of null-values (for original revisions, 
without previous revision)
-                       $ids = array_filter( $ids );
-                       $previousRevisions = $this->storage->getMulti( 
$revisionType, $ids );
-               }
-
-               $this->postCache = array_merge( $this->postCache, $rootPosts, 
$previousRevisions, $results );
-               $this->rootPostIdCache = array_merge( $this->rootPostIdCache, 
$rootPostIds );
-               $this->workflowCache = array_merge( $this->workflowCache, 
$workflows );
-       }
-
-       /**
-        * @param ContribsPager $pager
-        * @param array $conditions
-        * @param int $limit
-        * @param string $revisionClass Storage type (e.g. "PostRevision", 
"Header")
-        * @return mixed
-        */
-       protected function findRevisions( ContribsPager $pager, $conditions, 
$limit, $revisionClass ) {
-               return $this->storage->find( $revisionClass, $conditions, array(
-                       'LIMIT' => $limit,
-               ) );
-       }
-
-       /**
-        * @param ContribsPager $pager
-        * @param AbstractRevision $revision
-        * @param string $blockType Block name (e.g. "topic", "header")
-        * @return \stdClass
-        */
-       protected function buildResult( ContribsPager $pager, AbstractRevision 
$revision, $blockType ) {
-               $uuid = $revision->getRevisionId();
-               $timestamp = $uuid->getTimestamp();
-               $fakeRow = array();
-
-               $workflow = $this->getWorkflow( $revision );
-               if ( !$workflow ) {
-                       wfWarn( __METHOD__ . ": could not locate workflow for 
revision " . $revision->getRevisionId()->getAlphadecimal() );
-                       return false;
-               }
-
-               // other contributions entries
-               $fakeRow[$pager->getIndexField()] = $timestamp; // used for 
navbar
-               $fakeRow['page_namespace'] = 
$workflow->getArticleTitle()->getNamespace();
-               $fakeRow['page_title'] = 
$workflow->getArticleTitle()->getDBkey();
-               $fakeRow['revision'] = $revision;
-               $fakeRow['previous_revision'] = $this->getPreviousRevision( 
$revision );
-               $fakeRow['workflow'] = $workflow;
-               $fakeRow['blocktype'] = $blockType;
-
-               if ( $blockType == 'topic' && $revision instanceof PostRevision 
) {
-                       $fakeRow['root_post'] = $this->getRootPost( $revision );
-               }
-
-               // just to make sure entries will never be confused with 
anything else
-               $fakeRow['flow_contribution'] = 'flow';
-
-               return (object) $fakeRow;
-       }
-
-       /**
-        * @param AbstractRevision $revision
-        * @return Workflow
-        * @throws \MWException
-        */
-       protected function getWorkflow( AbstractRevision $revision ) {
-               if ( $revision instanceof PostRevision ) {
-                       $rootPostId = $this->getRootPostId( $revision );
-
-                       return $this->getWorkflowById( $rootPostId );
-               } elseif ( $revision instanceof Header ) {
-                       return $this->getWorkflowById( 
$revision->getWorkflowId() );
-               } else {
-                       throw new \MWException( 'Unsupported revision type ' . 
get_class( $revision ) );
-               }
-       }
-
-       /**
-        * Retrieves the previous revision for a given AbstractRevision
-        * @param  AbstractRevision $revision The revision to retrieve the 
previous revision for.
-        * @return AbstractRevision|null      AbstractRevision of the previous 
revision or null if no previous revision.
-        */
-       protected function getPreviousRevision( AbstractRevision $revision ) {
-               $previousRevisionId = $revision->getPrevRevisionId();
-
-               // original post; no previous revision
-               if ( $previousRevisionId === null ) {
-                       return null;
-               }
-
-               if ( !isset( 
$this->postCache[$previousRevisionId->getAlphadecimal()] ) ) {
-                       
$this->postCache[$previousRevisionId->getAlphadecimal()] =
-                               $this->storage->get( 'PostRevision', 
$previousRevisionId );
-               }
-
-               return $this->postCache[$previousRevisionId->getAlphadecimal()];
-       }
-
-       /**
-        * Retrieves the root post for a given PostRevision
-        * @param  PostRevision $revision The revision to retrieve the root 
post for.
-        * @return PostRevision           PostRevision of the root post.
-        * @throws \MWException
-        */
-       protected function getRootPost( PostRevision $revision ) {
-               $rootPostId = $this->getRootPostId( $revision );
-
-               if ( !isset( $this->postCache[$rootPostId->getAlphadecimal()] ) 
) {
-                       $this->postCache[$rootPostId->getAlphadecimal()] =
-                               $this->storage->get( 'PostRevision', 
$rootPostId );
-               }
-
-               $rootPost = $this->postCache[$rootPostId->getAlphadecimal()];
-               if ( $rootPost && !$rootPost->isTopicTitle() ) {
-                       throw new \MWException( "Not a topic title: " . 
$rootPost->getRevisionId() );
-               }
-
-               return $rootPost;
-       }
-
-       /**
-        * Gets the root post ID for a given PostRevision
-        * @param  PostRevision $revision The revision to get the root post ID 
for.
-        * @return UUID                   The UUID for the root post.
-        * @throws \MWException
-        */
-       protected function getRootPostId( PostRevision $revision ) {
-               $postId = $revision->getPostId();
-               if ( $revision->isTopicTitle() ) {
-                       return $postId;
-               } elseif ( isset( 
$this->rootPostIdCache[$postId->getAlphadecimal()] ) ) {
-                       return 
$this->rootPostIdCache[$postId->getAlphadecimal()];
-               } else {
-                       throw new \MWException( "Unable to find root post ID 
for post $postId" );
-               }
-       }
-
-       /**
-        * Gets a Workflow object given its ID
-        * @param  UUID   $workflowId The Workflow ID to retrieve.
-        * @return Workflow           The Workflow.
-        */
-       protected function getWorkflowById( UUID $workflowId ) {
-               if ( isset( 
$this->workflowCache[$workflowId->getAlphadecimal()] ) ) {
-                       return 
$this->workflowCache[$workflowId->getAlphadecimal()];
-               } else {
-                       return 
$this->workflowCache[$workflowId->getAlphadecimal()] = $this->storage->get( 
'Workflow', $workflowId );
-               }
        }
 
        /**

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: I8dac314453d1bdffe076007a57cb8b1aa7242431
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/Flow
Gerrit-Branch: master
Gerrit-Owner: EBernhardson <[email protected]>

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

Reply via email to