| Current File : /home/jvzmxxx/wiki/extensions/Flow/container.php |
<?php
$c = new Flow\Container;
// MediaWiki
if ( defined( 'RUN_MAINTENANCE_IF_MAIN' ) ) {
$c['user'] = new User;
} else {
$c['user'] = isset( $GLOBALS['wgUser'] ) ? $GLOBALS['wgUser'] : new User;
}
$c['output'] = $GLOBALS['wgOut'];
$c['request'] = $GLOBALS['wgRequest'];
$c['memcache'] = function( $c ) {
global $wgFlowUseMemcache, $wgMemc;
if ( $wgFlowUseMemcache ) {
return $wgMemc;
} else {
return new \HashBagOStuff();
}
};
$c['cache.version'] = $GLOBALS['wgFlowCacheVersion'];
// This lets the index handle the initial query from HistoryPager,
// even when the UI limit is 500. An extra item is requested
// so we know whether to link the pagination.
$c['history_index_limit'] = 501;
// 501 * OVERFETCH_FACTOR from HistoryQuery + 1
// Basically, this is so we can try to fetch enough extra to handle
// exclude_from_history without retrying.
$c['board_topic_history_post_index_limit'] = 682;
// Flow config
$c['flow_actions'] = function( $c ) {
global $wgFlowActions;
return new Flow\FlowActions( $wgFlowActions );
};
// Always returns the correct database for flow storage
$c['db.factory'] = function( $c ) {
global $wgFlowDefaultWikiDb, $wgFlowCluster;
return new Flow\DbFactory( $wgFlowDefaultWikiDb, $wgFlowCluster );
};
// Database Access Layer external from main implementation
$c['repository.tree'] = function( $c ) {
return new Flow\Repository\TreeRepository(
$c['db.factory'],
$c['memcache.local_buffered']
);
};
$c['url_generator'] = function( $c ) {
return new Flow\UrlGenerator(
$c['storage.workflow.mapper']
);
};
$c['watched_items'] = function( $c ) {
return new Flow\WatchedTopicItems(
$c['user'],
wfGetDB( DB_SLAVE, 'watchlist' )
);
};
$c['link_batch'] = function() {
return new LinkBatch;
};
$c['wiki_link_fixer'] = function( $c ) {
return new Flow\Parsoid\Fixer\WikiLinkFixer( $c['link_batch'] );
};
$c['bad_image_remover'] = function( $c ) {
return new Flow\Parsoid\Fixer\BadImageRemover( 'wfIsBadImage' );
};
$c['base_href_fixer'] = function( $c ) {
global $wgArticlePath;
return new Flow\Parsoid\Fixer\BaseHrefFixer( $wgArticlePath );
};
$c['ext_link_fixer'] = function ( $c ) {
return new Flow\Parsoid\Fixer\ExtLinkFixer();
};
$c['content_fixer'] = function( $c ) {
return new Flow\Parsoid\ContentFixer(
$c['wiki_link_fixer'],
$c['bad_image_remover'],
$c['base_href_fixer'],
$c['ext_link_fixer']
);
};
$c['permissions'] = function( $c ) {
return new Flow\RevisionActionPermissions( $c['flow_actions'], $c['user'] );
};
$c['lightncandy.template_dir'] = __DIR__ . '/handlebars';
$c['lightncandy'] = function( $c ) {
global $wgFlowServerCompileTemplates;
return new Flow\TemplateHelper(
$c['lightncandy.template_dir'],
$wgFlowServerCompileTemplates
);
};
$c['templating'] = function( $c ) {
return new Flow\Templating(
$c['repository.username'],
$c['url_generator'],
$c['output'],
$c['content_fixer'],
$c['permissions']
);
};
// New Storage Impl
use Flow\Data\BufferedCache;
use Flow\Data\Mapper\BasicObjectMapper;
use Flow\Data\Mapper\CachingObjectMapper;
use Flow\Data\Storage\BasicDbStorage;
use Flow\Data\Storage\TopicListStorage;
use Flow\Data\Storage\TopicListLastUpdatedStorage;
use Flow\Data\Storage\PostRevisionBoardHistoryStorage;
use Flow\Data\Storage\PostRevisionStorage;
use Flow\Data\Storage\HeaderRevisionStorage;
use Flow\Data\Storage\PostSummaryRevisionBoardHistoryStorage;
use Flow\Data\Storage\PostSummaryRevisionStorage;
use Flow\Data\Index\UniqueFeatureIndex;
use Flow\Data\Index\TopKIndex;
use Flow\Data\Index\TopicListTopKIndex;
use Flow\Data\Storage\PostRevisionTopicHistoryStorage;
use Flow\Data\Index\PostRevisionBoardHistoryIndex;
use Flow\Data\Index\PostRevisionTopicHistoryIndex;
use Flow\Data\Index\PostSummaryRevisionBoardHistoryIndex;
use Flow\Data\ObjectManager;
use Flow\Data\ObjectLocator;
// This currently never clears $this->bag, which makes it unusuable for long-running batch.
// Use 'memcache.non_local_buffered' for those instead.
$c['memcache.local_buffered'] = function( $c ) {
global $wgFlowCacheTime;
// This is the real buffered cached that will allow transactional-like cache.
// It also caches all reads in-memory.
$bufferedCache = new Flow\Data\BagOStuff\LocalBufferedBagOStuff( $c['memcache'] );
// This is Flow's wrapper around it, to have a fixed cache expiry time
return new BufferedCache( $bufferedCache, $wgFlowCacheTime );
};
$c['memcache.non_local_buffered'] = function( $c ) {
global $wgFlowCacheTime;
// This is the real buffered cached that will allow transactional-like cache
$bufferedCache = new Flow\Data\BagOStuff\BufferedBagOStuff( $c['memcache'] );
// This is Flow's wrapper around it, to have a fixed cache expiry time
return new BufferedCache( $bufferedCache, $wgFlowCacheTime );
};
// Batched username loader
$c['repository.username.query'] = function( $c ) {
return new Flow\Repository\UserName\TwoStepUserNameQuery(
$c['db.factory']
);
};
$c['repository.username'] = function( $c ) {
return new Flow\Repository\UserNameBatch(
$c['repository.username.query']
);
};
$c['collection.cache'] = function( $c ) {
return new Flow\Collection\CollectionCache();
};
// Individual workflow instances
$c['storage.workflow.class'] = 'Flow\Model\Workflow';
$c['storage.workflow.table'] = 'flow_workflow';
$c['storage.workflow.primary_key'] = array( 'workflow_id' );
$c['storage.workflow.mapper'] = function( $c ) {
return CachingObjectMapper::model(
$c['storage.workflow.class'],
$c['storage.workflow.primary_key']
);
};
$c['storage.workflow.backend'] = function( $c ) {
return new BasicDbStorage(
$c['db.factory'],
$c['storage.workflow.table'],
$c['storage.workflow.primary_key']
);
};
$c['storage.workflow.indexes.primary'] = function( $c ) {
return new UniqueFeatureIndex(
$c['memcache.local_buffered'],
$c['storage.workflow.backend'],
$c['storage.workflow.mapper'],
'flow_workflow:v2:pk',
$c['storage.workflow.primary_key']
);
};
$c['storage.workflow.indexes.title_lookup'] = function( $c ) {
return new TopKIndex(
$c['memcache.local_buffered'],
$c['storage.workflow.backend'],
$c['storage.workflow.mapper'],
'flow_workflow:title:v2:',
array( 'workflow_wiki', 'workflow_namespace', 'workflow_title_text', 'workflow_type' ),
array(
'shallow' => $c['storage.workflow.indexes.primary'],
'limit' => 1,
'sort' => 'workflow_id'
)
);
};
$c['storage.workflow.indexes'] = function( $c ) {
return array(
$c['storage.workflow.indexes.primary'],
$c['storage.workflow.indexes.title_lookup']
);
};
$c['storage.workflow.listeners.topiclist'] = function( $c ) {
return new Flow\Data\Listener\WorkflowTopicListListener(
$c['storage.topic_list'],
$c['storage.topic_list.indexes.last_updated']
);
};
$c['storage.workflow.listeners'] = function( $c ) {
return array(
'listener.topicpagecreation' => $c['listener.topicpagecreation'],
// The storage.topic_list.indexes are primarily for TopicListEntry insertions, but they
// also listen for discussion workflow insertions so they can initialize for new boards.
'storage.topic_list.indexes.reverse_lookup' => $c['storage.topic_list.indexes.reverse_lookup'],
'storage.topic_list.indexes.last_updated' => $c['storage.topic_list.indexes.last_updated'],
'storage.workflow.listeners.topiclist' => $c['storage.workflow.listeners.topiclist'],
);
};
$c['storage.workflow'] = function( $c ) {
return new ObjectManager(
$c['storage.workflow.mapper'],
$c['storage.workflow.backend'],
$c['db.factory'],
$c['storage.workflow.indexes'],
$c['storage.workflow.listeners']
);
};
$c['listener.recentchanges'] = function( $c ) {
// Recent change listeners go out to external services and
// as such must only be run after the transaction is commited.
return new Flow\Data\Listener\DeferredInsertLifecycleHandler(
$c['deferred_queue'],
new Flow\Data\Listener\RecentChangesListener(
$c['flow_actions'],
$c['repository.username'],
new Flow\Data\Utils\RecentChangeFactory,
$c['formatter.irclineurl']
)
);
};
$c['listener.topicpagecreation'] = function( $c ) {
return new Flow\Data\Listener\TopicPageCreationListener(
$c['occupation_controller'],
$c['deferred_queue']
);
};
$c['listeners.notification'] = function( $c ) {
// Defer notifications triggering till end of request so we could get
// article_id in the case of a new topic
return new Flow\Data\Listener\DeferredInsertLifecycleHandler(
$c['deferred_queue'],
new Flow\Data\Listener\NotificationListener(
$c['controller.notification']
)
);
};
$c['storage.post_board_history.backend'] = function( $c ) {
return new PostRevisionBoardHistoryStorage( $c['db.factory'] );
};
$c['storage.post_board_history.indexes.primary'] = function( $c ) {
return new PostRevisionBoardHistoryIndex(
$c['memcache.local_buffered'],
// backend storage
$c['storage.post_board_history.backend'],
// data mapper
$c['storage.post.mapper'],
// key prefix
'flow_revision:topic_list_history:post:v2',
// primary key
array( 'topic_list_id' ),
// index options
array(
'limit' => $c['board_topic_history_post_index_limit'],
'sort' => 'rev_id',
'order' => 'DESC'
),
$c['storage.topic_list']
);
};
$c['storage.post_board_history.indexes'] = function( $c ) {
return array( $c['storage.post_board_history.indexes.primary'] );
};
$c['storage.post_board_history'] = function( $c ) {
return new ObjectLocator(
$c['storage.post.mapper'],
$c['storage.post_board_history.backend'],
$c['db.factory'],
$c['storage.post_board_history.indexes']
);
};
$c['storage.post_summary_board_history.backend'] = function( $c ) {
return new PostSummaryRevisionBoardHistoryStorage( $c['db.factory'] );
};
$c['storage.post_summary_board_history.indexes.primary'] = function( $c ) {
return new PostSummaryRevisionBoardHistoryIndex(
$c['memcache.local_buffered'],
// backend storage
$c['storage.post_summary_board_history.backend'],
// data mapper
$c['storage.post_summary.mapper'],
// key prefix
'flow_revision:topic_list_history:post_summary:v2',
// primary key
array( 'topic_list_id' ),
// index options
array(
'limit' => $c['history_index_limit'],
'sort' => 'rev_id',
'order' => 'DESC'
),
$c['storage.topic_list']
);
};
$c['storage.post_summary_board_history.indexes'] = function( $c ) {
return array( $c['storage.post_summary_board_history.indexes.primary'] );
};
$c['storage.post_summary_board_history'] = function( $c ) {
return new ObjectLocator(
$c['storage.post_summary.mapper'],
$c['storage.post_summary_board_history.backend'],
$c['db.factory'],
$c['storage.post_summary_board_history.indexes']
);
};
$c['storage.header.listeners.username'] = function( $c ) {
return new Flow\Data\Listener\UserNameListener(
$c['repository.username'],
array(
'rev_user_id' => 'rev_user_wiki',
'rev_mod_user_id' => 'rev_mod_user_wiki',
'rev_edit_user_id' => 'rev_edit_user_wiki'
)
);
};
$c['storage.header.listeners'] = function( $c ) {
return array(
'reference.recorder' => $c['reference.recorder'],
'storage.header.listeners.username' => $c['storage.header.listeners.username'],
'listeners.notification' => $c['listeners.notification'],
'listener.recentchanges' => $c['listener.recentchanges'],
'listener.editcount' => $c['listener.editcount'],
);
};
$c['storage.header.primary_key'] = array( 'rev_id' );
$c['storage.header.mapper'] = function( $c ) {
return CachingObjectMapper::model( 'Flow\\Model\\Header', array( 'rev_id' ) );
};
$c['storage.header.backend'] = function( $c ) {
global $wgFlowExternalStore;
return new HeaderRevisionStorage(
$c['db.factory'],
$wgFlowExternalStore
);
};
$c['storage.header.indexes.primary'] = function( $c ) {
return new UniqueFeatureIndex(
$c['memcache.local_buffered'],
$c['storage.header.backend'],
$c['storage.header.mapper'],
'flow_header:v2:pk',
$c['storage.header.primary_key']
);
};
$c['storage.header.indexes.header_lookup'] = function( $c ) {
return new TopKIndex(
$c['memcache.local_buffered'],
$c['storage.header.backend'],
$c['storage.header.mapper'],
'flow_header:workflow:v3',
array( 'rev_type_id' ),
array(
'limit' => $c['history_index_limit'],
'sort' => 'rev_id',
'order' => 'DESC',
'shallow' => $c['storage.header.indexes.primary'],
'create' => function( array $row ) {
return $row['rev_parent_id'] === null;
},
)
);
};
$c['storage.header.indexes'] = function( $c ) {
return array(
$c['storage.header.indexes.primary'],
$c['storage.header.indexes.header_lookup']
);
};
$c['storage.header'] = function( $c ) {
return new ObjectManager(
$c['storage.header.mapper'],
$c['storage.header.backend'],
$c['db.factory'],
$c['storage.header.indexes'],
$c['storage.header.listeners']
);
};
$c['storage.post_summary.class'] = 'Flow\Model\PostSummary';
$c['storage.post_summary.primary_key'] = array( 'rev_id' );
$c['storage.post_summary.mapper'] = function( $c ) {
return CachingObjectMapper::model(
$c['storage.post_summary.class'],
$c['storage.post_summary.primary_key']
);
};
$c['storage.post_summary.listeners.username'] = function( $c ) {
return new Flow\Data\Listener\UserNameListener(
$c['repository.username'],
array(
'rev_user_id' => 'rev_user_wiki',
'rev_mod_user_id' => 'rev_mod_user_wiki',
'rev_edit_user_id' => 'rev_edit_user_wiki'
)
);
};
$c['storage.post_summary.listeners'] = function( $c ) {
return array(
'listener.recentchanges' => $c['listener.recentchanges'],
'storage.post_summary.listeners.username' => $c['storage.post_summary.listeners.username'],
'listeners.notification' => $c['listeners.notification'],
'storage.post_summary_board_history.indexes.primary' => $c['storage.post_summary_board_history.indexes.primary'],
'listener.editcount' => $c['listener.editcount'],
'reference.recorder' => $c['reference.recorder'],
);
};
$c['storage.post_summary.backend'] = function( $c ) {
global $wgFlowExternalStore;
return new PostSummaryRevisionStorage(
$c['db.factory'],
$wgFlowExternalStore
);
};
$c['storage.post_summary.indexes.primary'] = function( $c ) {
return new UniqueFeatureIndex(
$c['memcache.local_buffered'],
$c['storage.post_summary.backend'],
$c['storage.post_summary.mapper'],
'flow_post_summary:v2:pk',
$c['storage.post_summary.primary_key']
);
};
$c['storage.post_summary.indexes.topic_lookup'] = function( $c ) {
return new TopKIndex(
$c['memcache.local_buffered'],
$c['storage.post_summary.backend'],
$c['storage.post_summary.mapper'],
'flow_post_summary:workflow:v3',
array( 'rev_type_id' ),
array(
'limit' => $c['history_index_limit'],
'sort' => 'rev_id',
'order' => 'DESC',
'shallow' => $c['storage.post_summary.indexes.primary'],
'create' => function( array $row ) {
return $row['rev_parent_id'] === null;
},
)
);
};
$c['storage.post_summary.indexes'] = function( $c ) {
return array(
$c['storage.post_summary.indexes.primary'],
$c['storage.post_summary.indexes.topic_lookup'],
);
};
$c['storage.post_summary'] = function( $c ) {
return new ObjectManager(
$c['storage.post_summary.mapper'],
$c['storage.post_summary.backend'],
$c['db.factory'],
$c['storage.post_summary.indexes'],
$c['storage.post_summary.listeners']
);
};
$c['storage.topic_list.class'] = 'Flow\Model\TopicListEntry';
$c['storage.topic_list.table'] = 'flow_topic_list';
$c['storage.topic_list.primary_key'] = array( 'topic_list_id', 'topic_id' );
$c['storage.topic_list.indexes.last_updated.backend'] = function( $c ) {
return new TopicListLastUpdatedStorage(
$c['db.factory'],
$c['storage.topic_list.table'],
$c['storage.topic_list.primary_key']
);
};
$c['storage.topic_list.mapper'] = function( $c ) {
// Must be BasicObjectMapper, due to variance in when
// we have workflow_last_update_timestamp
return BasicObjectMapper::model(
$c['storage.topic_list.class'],
$c['storage.topic_list.primary_key']
);
};
$c['storage.topic_list.backend'] = function( $c ) {
return new TopicListStorage(
// factory and table
$c['db.factory'],
$c['storage.topic_list.table'],
$c['storage.topic_list.primary_key']
);
};
// Lookup from topic_id to its owning board id
$c['storage.topic_list.indexes.primary'] = function( $c ) {
return new UniqueFeatureIndex(
$c['memcache.local_buffered'],
$c['storage.topic_list.backend'],
$c['storage.topic_list.mapper'],
'flow_topic_list:topic',
array( 'topic_id' )
);
};
// Lookup from board to contained topics
/// In reverse order by topic_id
$c['storage.topic_list.indexes.reverse_lookup'] = function( $c ) {
return new TopicListTopKIndex(
$c['memcache.local_buffered'],
$c['storage.topic_list.backend'],
$c['storage.topic_list.mapper'],
'flow_topic_list:list',
array( 'topic_list_id' ),
array( 'sort' => 'topic_id' )
);
};
/// In reverse order by topic last_updated
$c['storage.topic_list.indexes.last_updated'] = function( $c ) {
return new TopicListTopKIndex(
$c['memcache.local_buffered'],
$c['storage.topic_list.indexes.last_updated.backend'],
$c['storage.topic_list.mapper'],
'flow_topic_list_last_updated:list',
array( 'topic_list_id' ),
array(
'sort' => 'workflow_last_update_timestamp',
'order' => 'desc'
)
);
};
$c['storage.topic_list.indexes'] = function( $c ) {
return array(
$c['storage.topic_list.indexes.primary'],
$c['storage.topic_list.indexes.reverse_lookup'],
$c['storage.topic_list.indexes.last_updated'],
);
};
$c['storage.topic_list'] = function( $c ) {
return new ObjectManager(
$c['storage.topic_list.mapper'],
$c['storage.topic_list.backend'],
$c['db.factory'],
$c['storage.topic_list.indexes']
);
};
$c['storage.post.class'] = 'Flow\Model\PostRevision';
$c['storage.post.primary_key'] = array( 'rev_id' );
$c['storage.post.mapper'] = function( $c ) {
return CachingObjectMapper::model(
$c['storage.post.class'],
$c['storage.post.primary_key']
);
};
$c['storage.post.backend'] = function( $c ) {
global $wgFlowExternalStore;
return new PostRevisionStorage(
$c['db.factory'],
$wgFlowExternalStore,
$c['repository.tree']
);
};
$c['storage.post.listeners.moderation_logging'] = function( $c ) {
return new Flow\Data\Listener\ModerationLoggingListener(
$c['logger.moderation']
);
};
$c['storage.post.listeners.username'] = function( $c ) {
return new Flow\Data\Listener\UserNameListener(
$c['repository.username'],
array(
'rev_user_id' => 'rev_user_wiki',
'rev_mod_user_id' => 'rev_mod_user_wiki',
'rev_edit_user_id' => 'rev_edit_user_wiki',
'tree_orig_user_id' => 'tree_orig_user_wiki'
)
);
};
$c['storage.post.listeners.watch_topic'] = function( $c ) {
// Auto-subscribe users to the topic after performing specific actions
return new Flow\Data\Listener\ImmediateWatchTopicListener(
$c['watched_items']
);
};
$c['storage.post.listeners'] = function( $c ) {
return array(
'reference.recorder' => $c['reference.recorder'],
'collection.cache' => $c['collection.cache'],
'storage.post.listeners.username' => $c['storage.post.listeners.username'],
'storage.post.listeners.watch_topic' => $c['storage.post.listeners.watch_topic'],
'listeners.notification' => $c['listeners.notification'],
'storage.post.listeners.moderation_logging' => $c['storage.post.listeners.moderation_logging'],
'listener.recentchanges' => $c['listener.recentchanges'],
'listener.editcount' => $c['listener.editcount'],
'storage.post_board_history.indexes.primary' => $c['storage.post_board_history.indexes.primary'],
);
};
$c['storage.post.indexes.primary'] = function( $c ) {
return new UniqueFeatureIndex(
$c['memcache.local_buffered'],
$c['storage.post.backend'],
$c['storage.post.mapper'],
'flow_revision:v4:pk',
$c['storage.post.primary_key']
);
};
// Each bucket holds a list of revisions in a single post
$c['storage.post.indexes.post_lookup'] = function( $c ) {
return new TopKIndex(
$c['memcache.local_buffered'],
$c['storage.post.backend'],
$c['storage.post.mapper'],
'flow_revision:descendant',
array( 'rev_type_id' ),
array(
'limit' => 100,
'sort' => 'rev_id',
'order' => 'DESC',
'shallow' => $c['storage.post.indexes.primary'],
'create' => function( array $row ) {
// return true to create instead of merge index
return $row['rev_parent_id'] === null;
},
)
);
};
$c['storage.post.indexes'] = function( $c ) {
return array(
$c['storage.post.indexes.primary'],
$c['storage.post.indexes.post_lookup'],
$c['storage.post_topic_history.indexes.topic_lookup']
);
};
$c['storage.post'] = function( $c ) {
return new ObjectManager(
$c['storage.post.mapper'],
$c['storage.post.backend'],
$c['db.factory'],
$c['storage.post.indexes'],
$c['storage.post.listeners']
);
};
$c['storage.post_topic_history.backend'] = function( $c ) {
return new PostRevisionTopicHistoryStorage(
$c['storage.post.backend'],
$c['repository.tree']
);
};
$c['storage.post_topic_history.indexes.topic_lookup'] = function( $c ) {
return new PostRevisionTopicHistoryIndex(
$c['memcache.local_buffered'],
$c['storage.post_topic_history.backend'],
$c['storage.post.mapper'],
'flow_revision:topic_history:post:v2',
array( 'topic_root_id' ),
array(
'limit' => $c['board_topic_history_post_index_limit'],
'sort' => 'rev_id',
'order' => 'DESC',
// Why does topic history have a shallow compactor, but not board history?
'shallow' => $c['storage.post.indexes.primary'],
'create' => function( array $row ) {
// only create new indexes for new topics, so it has to be
// of type 'post' and have no parent post & revision
if ( $row['rev_type'] !== 'post' ) {
return false;
}
return $row['tree_parent_id'] === null && $row['rev_parent_id'] === null;
},
)
);
};
$c['storage.post_topic_history.indexes'] = function( $c ) {
return array(
$c['storage.post_topic_history.indexes.topic_lookup'],
);
};
$c['storage.post_topic_history'] = function( $c ) {
return new ObjectLocator(
$c['storage.post.mapper'],
$c['storage.post_topic_history.backend'],
$c['db.factory'],
$c['storage.post_topic_history.indexes']
);
};
$c['storage.manager_list'] = function( $c ) {
return array(
'Flow\\Model\\Workflow' => 'storage.workflow',
'Workflow' => 'storage.workflow',
'Flow\\Model\\PostRevision' => 'storage.post',
'PostRevision' => 'storage.post',
'post' => 'storage.post',
'Flow\\Model\\PostSummary' => 'storage.post_summary',
'PostSummary' => 'storage.post_summary',
'post-summary' => 'storage.post_summary',
'Flow\\Model\\TopicListEntry' => 'storage.topic_list',
'TopicListEntry' => 'storage.topic_list',
'Flow\\Model\\Header' => 'storage.header',
'Header' => 'storage.header',
'header' => 'storage.header',
'PostRevisionBoardHistoryEntry' => 'storage.post_board_history',
'PostSummaryBoardHistoryEntry' => 'storage.post_summary_board_history',
'PostRevisionTopicHistoryEntry' => 'storage.post_topic_history',
'Flow\\Model\\WikiReference' => 'storage.wiki_reference',
'WikiReference' => 'storage.wiki_reference',
'Flow\\Model\\URLReference' => 'storage.url_reference',
'URLReference' => 'storage.url_reference',
);
};
$c['storage'] = function( $c ) {
return new \Flow\Data\ManagerGroup(
$c,
$c['storage.manager_list']
);
};
$c['loader.root_post'] = function( $c ) {
return new \Flow\Repository\RootPostLoader(
$c['storage'],
$c['repository.tree']
);
};
// Queue of callbacks to run by DeferredUpdates, but only
// on successfull commit
$c['deferred_queue'] = function( $c ) {
return new SplQueue;
};
$c['submission_handler'] = function( $c ) {
return new Flow\SubmissionHandler(
$c['storage'],
$c['db.factory'],
$c['memcache.local_buffered'],
$c['deferred_queue']
);
};
$c['factory.block'] = function( $c ) {
return new Flow\BlockFactory(
$c['storage'],
$c['loader.root_post']
);
};
$c['factory.loader.workflow'] = function( $c ) {
return new Flow\WorkflowLoaderFactory(
$c['storage'],
$c['factory.block'],
$c['submission_handler']
);
};
// Initialized in FlowHooks to facilitate only loading the flow container
// when flow is specifically requested to run. Extension initialization
// must always happen before calling flow code.
$c['occupation_controller'] = FlowHooks::getOccupationController();
$c['controller.notification'] = function( $c ) {
global $wgContLang;
return new Flow\NotificationController( $wgContLang, $c['repository.tree'] );
};
// Initialized in FlowHooks to faciliate only loading the flow container
// when flow is specifically requested to run. Extension initialization
// must always happen before calling flow code.
$c['controller.abusefilter'] = FlowHooks::getAbuseFilter();
$c['controller.spamregex'] = function( $c ) {
return new Flow\SpamFilter\SpamRegex;
};
$c['controller.spamblacklist'] = function( $c ) {
return new Flow\SpamFilter\SpamBlacklist;
};
$c['controller.confirmedit'] = function( $c ) {
return new Flow\SpamFilter\ConfirmEdit;
};
$c['controller.contentlength'] = function( $c ) {
global $wgMaxArticleSize;
// wgMaxArticleSize is in kilobytes,
// whereas this really is characters (it uses
// mb_strlen), so it's not the exact same limit.
$maxCharCount = $wgMaxArticleSize * 1024;
return new Flow\SpamFilter\ContentLengthFilter( $maxCharCount );
};
$c['controller.ratelimits'] = function( $c ) {
return new Flow\SpamFilter\RateLimits;
};
$c['controller.spamfilter'] = function( $c ) {
return new Flow\SpamFilter\Controller(
$c['controller.contentlength'],
$c['controller.spamregex'],
$c['controller.ratelimits'],
$c['controller.spamblacklist'],
$c['controller.abusefilter'],
$c['controller.confirmedit']
);
};
$c['query.categoryviewer'] = function( $c ) {
return new Flow\Formatter\CategoryViewerQuery(
$c['storage'],
$c['repository.tree']
);
};
$c['formatter.categoryviewer'] = function( $c ) {
return new Flow\Formatter\CategoryViewerFormatter(
$c['permissions']
);
};
$c['query.singlepost'] = function( $c ) {
return new Flow\Formatter\SinglePostQuery(
$c['storage'],
$c['repository.tree']
);
};
$c['query.checkuser'] = function( $c ) {
return new Flow\Formatter\CheckUserQuery(
$c['storage'],
$c['repository.tree']
);
};
$c['formatter.irclineurl'] = function( $c ) {
return new Flow\Formatter\IRCLineUrlFormatter(
$c['permissions'],
$c['formatter.revision']
);
};
$c['formatter.checkuser'] = function( $c ) {
return new Flow\Formatter\CheckUserFormatter(
$c['permissions'],
$c['formatter.revision']
);
};
$c['formatter.revisionview'] = function( $c ) {
return new Flow\Formatter\RevisionViewFormatter(
$c['url_generator'],
$c['formatter.revision']
);
};
$c['formatter.revision.diff.view'] = function( $c ) {
return new Flow\Formatter\RevisionDiffViewFormatter(
$c['formatter.revisionview'],
$c['url_generator']
);
};
$c['query.topiclist'] = function( $c ) {
return new Flow\Formatter\TopicListQuery(
$c['storage'],
$c['repository.tree'],
$c['permissions'],
$c['watched_items']
);
};
$c['query.topic.history'] = function( $c ) {
return new Flow\Formatter\TopicHistoryQuery(
$c['storage'],
$c['repository.tree'],
$c['flow_actions']
);
};
$c['query.post.history'] = function( $c ) {
return new Flow\Formatter\PostHistoryQuery(
$c['storage'],
$c['repository.tree'],
$c['flow_actions']
);
};
$c['query.changeslist'] = function( $c ) {
$query = new Flow\Formatter\ChangesListQuery(
$c['storage'],
$c['repository.tree'],
$c['flow_actions']
);
$query->setExtendWatchlist( $c['user']->getOption( 'extendwatchlist' ) );
return $query;
};
$c['query.postsummary'] = function( $c ) {
return new Flow\Formatter\PostSummaryQuery(
$c['storage'],
$c['repository.tree'],
$c['flow_actions']
);
};
$c['query.header.view'] = function( $c ) {
return new Flow\Formatter\HeaderViewQuery(
$c['storage'],
$c['repository.tree'],
$c['permissions']
);
};
$c['query.post.view'] = function( $c ) {
return new Flow\Formatter\PostViewQuery(
$c['storage'],
$c['repository.tree'],
$c['permissions']
);
};
$c['query.postsummary.view'] = function( $c ) {
return new Flow\Formatter\PostSummaryViewQuery(
$c['storage'],
$c['repository.tree'],
$c['permissions']
);
};
$c['formatter.changeslist'] = function( $c ) {
return new Flow\Formatter\ChangesListFormatter(
$c['permissions'],
$c['formatter.revision']
);
};
$c['query.contributions'] = function( $c ) {
return new Flow\Formatter\ContributionsQuery(
$c['storage'],
$c['repository.tree'],
$c['memcache'],
$c['db.factory'],
$c['flow_actions']
);
};
$c['formatter.contributions'] = function( $c ) {
return new Flow\Formatter\ContributionsFormatter(
$c['permissions'],
$c['formatter.revision']
);
};
$c['formatter.contributions.feeditem'] = function( $c ) {
return new Flow\Formatter\FeedItemFormatter(
$c['permissions'],
$c['formatter.revision']
);
};
$c['query.board.history'] = function( $c ) {
return new Flow\Formatter\BoardHistoryQuery(
$c['storage'],
$c['repository.tree'],
$c['flow_actions']
);
};
// The RevisionFormatter holds internal state like
// contentType of output and if it should include history
// properties. To prevent different code using the formatter
// from causing problems return a new RevisionFormatter every
// time it is requested.
$c['formatter.revision'] = $c->factory( function( $c ) {
global $wgFlowMaxThreadingDepth;
return new Flow\Formatter\RevisionFormatter(
$c['permissions'],
$c['templating'],
$c['repository.username'],
$wgFlowMaxThreadingDepth
);
} );
$c['formatter.topiclist'] = function( $c ) {
return new Flow\Formatter\TopicListFormatter(
$c['url_generator'],
$c['formatter.revision']
);
};
$c['formatter.topiclist.toc'] = function ( $c ) {
return new Flow\Formatter\TocTopicListFormatter(
$c['templating']
);
};
$c['formatter.topic'] = function( $c ) {
return new Flow\Formatter\TopicFormatter(
$c['url_generator'],
$c['formatter.revision']
);
};
$c['search.connection'] = function( $c ) {
if ( defined( 'MW_PHPUNIT_TEST' ) && !class_exists( 'ElasticaConnection' ) ) {
/*
* ContainerTest::testInstantiateAll instantiates everything
* in container and doublechecks it's not null.
* Flow runs on Jenkins don't currently load Extension:Elastica,
* which is required to be able to construct this object.
* Because search is not currently in use, let's not add the
* dependency in Jenkins and just return a bogus value to not
* make the test fail ;)
*/
return 'not-supported';
}
global $wgFlowSearchServers, $wgFlowSearchConnectionAttempts;
return new Flow\Search\Connection( $wgFlowSearchServers, $wgFlowSearchConnectionAttempts );
};
$c['search.index.iterators.header'] = function( $c ) {
return new \Flow\Search\Iterators\HeaderIterator( $c['db.factory'] );
};
$c['search.index.iterators.topic'] = function( $c ) {
return new \Flow\Search\Iterators\TopicIterator( $c['db.factory'], $c['loader.root_post'] );
};
$c['search.index.updaters'] = function( $c ) {
// permissions for anon user
$anonPermissions = new Flow\RevisionActionPermissions( $c['flow_actions'], new User );
return array(
'topic' => new \Flow\Search\Updaters\TopicUpdater( $c['search.index.iterators.topic'], $anonPermissions, $c['loader.root_post'] ),
'header' => new \Flow\Search\Updaters\HeaderUpdater( $c['search.index.iterators.header'], $anonPermissions )
);
};
$c['logger.moderation'] = function( $c ) {
return new Flow\Log\ModerationLogger(
$c['flow_actions']
);
};
$c['storage.wiki_reference.class'] = 'Flow\Model\WikiReference';
$c['storage.wiki_reference.table'] = 'flow_wiki_ref';
$c['storage.wiki_reference.primary_key'] = function ( $c ) {
return array(
'ref_src_wiki',
'ref_src_namespace',
'ref_src_title',
'ref_src_object_id',
'ref_type',
'ref_target_namespace',
'ref_target_title'
);
};
$c['storage.wiki_reference.mapper'] = function( $c ) {
return BasicObjectMapper::model(
$c['storage.wiki_reference.class']
);
};
$c['storage.wiki_reference.backend'] = function( $c ) {
return new BasicDbStorage(
$c['db.factory'],
$c['storage.wiki_reference.table'],
$c['storage.wiki_reference.primary_key']
);
};
$c['storage.wiki_reference.indexes.source_lookup'] = function( $c ) {
return new TopKIndex(
$c['memcache.local_buffered'],
$c['storage.wiki_reference.backend'],
$c['storage.wiki_reference.mapper'],
'flow_ref:wiki:by-source:v3',
array(
'ref_src_wiki',
'ref_src_namespace',
'ref_src_title',
),
array(
'order' => 'ASC',
'sort' => 'ref_src_object_id',
)
);
};
$c['storage.wiki_reference.indexes.revision_lookup'] = function( $c ) {
return new TopKIndex(
$c['memcache.local_buffered'],
$c['storage.wiki_reference.backend'],
$c['storage.wiki_reference.mapper'],
'flow_ref:wiki:by-revision:v3',
array(
'ref_src_wiki',
'ref_src_object_type',
'ref_src_object_id',
),
array(
'order' => 'ASC',
'sort' => array( 'ref_target_namespace', 'ref_target_title' ),
)
);
};
$c['storage.wiki_reference.indexes'] = function( $c ) {
return array(
$c['storage.wiki_reference.indexes.source_lookup'],
$c['storage.wiki_reference.indexes.revision_lookup'],
);
};
$c['storage.wiki_reference'] = function( $c ) {
return new ObjectManager(
$c['storage.wiki_reference.mapper'],
$c['storage.wiki_reference.backend'],
$c['db.factory'],
$c['storage.wiki_reference.indexes'],
array()
);
};
$c['storage.url_reference.class'] = 'Flow\Model\URLReference';
$c['storage.url_reference.table'] = 'flow_ext_ref';
$c['storage.url_reference.primary_key'] = function ( $c ) {
return array(
'ref_src_wiki',
'ref_src_namespace',
'ref_src_title',
'ref_src_object_id',
'ref_type',
'ref_target',
);
};
$c['storage.url_reference.mapper'] = function( $c ) {
return BasicObjectMapper::model(
$c['storage.url_reference.class']
);
};
$c['storage.url_reference.backend'] = function( $c ) {
return new BasicDbStorage(
// factory and table
$c['db.factory'],
$c['storage.url_reference.table'],
$c['storage.url_reference.primary_key']
);
};
$c['storage.url_reference.indexes.source_lookup'] = function( $c ) {
return new TopKIndex(
$c['memcache.local_buffered'],
$c['storage.url_reference.backend'],
$c['storage.url_reference.mapper'],
'flow_ref:url:by-source:v3',
array(
'ref_src_wiki',
'ref_src_namespace',
'ref_src_title',
),
array(
'order' => 'ASC',
'sort' => 'ref_src_object_id',
)
);
};
$c['storage.url_reference.indexes.revision_lookup'] = function( $c ) {
return new TopKIndex(
$c['memcache.local_buffered'],
$c['storage.url_reference.backend'],
$c['storage.url_reference.mapper'],
'flow_ref:url:by-revision:v3',
array(
'ref_src_wiki',
'ref_src_object_type',
'ref_src_object_id',
),
array(
'order' => 'ASC',
'sort' => array( 'ref_target' ),
)
);
};
$c['storage.url_reference.indexes'] = function( $c ) {
return array(
$c['storage.url_reference.indexes.source_lookup'],
$c['storage.url_reference.indexes.revision_lookup'],
);
};
$c['storage.url_reference'] = function( $c ) {
return new ObjectManager(
$c['storage.url_reference.mapper'],
$c['storage.url_reference.backend'],
$c['db.factory'],
$c['storage.url_reference.indexes'],
array()
);
};
$c['reference.updater.links-tables'] = function( $c ) {
return new Flow\LinksTableUpdater( $c['storage'] );
};
$c['reference.clarifier'] = function( $c ) {
return new Flow\ReferenceClarifier( $c['storage'], $c['url_generator'] );
};
$c['reference.extractor'] = function( $c ) {
$default = array(
new Flow\Parsoid\Extractor\ImageExtractor,
new Flow\Parsoid\Extractor\PlaceholderExtractor,
new Flow\Parsoid\Extractor\WikiLinkExtractor,
new Flow\Parsoid\Extractor\ExtLinkExtractor,
new Flow\Parsoid\Extractor\TransclusionExtractor,
);
$extractors = array(
'header' => $default,
'post-summary' => $default,
'post' => $default,
);
// In addition to the defaults header and summaries collect
// the related categories.
$extractors['header'][] = $extractors['post-summary'][] = new Flow\Parsoid\Extractor\CategoryExtractor;
return new Flow\Parsoid\ReferenceExtractor( $extractors );
};
$c['reference.recorder'] = function( $c ) {
return new Flow\Data\Listener\ReferenceRecorder(
$c['reference.extractor'],
$c['reference.updater.links-tables'],
$c['storage'],
$c['repository.tree'],
$c['deferred_queue']
);
};
$c['user_merger'] = function( $c ) {
return new Flow\Data\Utils\UserMerger(
$c['db.factory'],
$c['storage']
);
};
$c['importer'] = function( $c ) {
$importer = new Flow\Import\Importer(
$c['storage'],
$c['factory.loader.workflow'],
$c['memcache.local_buffered'],
$c['db.factory'],
$c['deferred_queue'],
$c['occupation_controller']
);
$importer->addPostprocessor( new Flow\Import\Postprocessor\SpecialLogTopic(
$c['occupation_controller']->getTalkpageManager()
) );
return $importer;
};
$c['listener.editcount'] = function( $c ) {
return new \Flow\Data\Listener\EditCountListener( $c['flow_actions'] );
};
$c['formatter.undoedit'] = function( $c ) {
return new Flow\Formatter\RevisionUndoViewFormatter(
$c['formatter.revisionview']
);
};
$c['board_mover'] = function( $c ) {
return new Flow\BoardMover(
$c['db.factory'],
$c['memcache.local_buffered'],
$c['storage'],
$c['occupation_controller']->getTalkpageManager()
);
};
$c['parser'] = function() {
global $wgParser;
return $wgParser;
};
$c['default_logger'] = function() {
return MediaWiki\Logger\LoggerFactory::getInstance( 'Flow' );
};
return $c;