diff --git a/autoload.php b/autoload.php index 0e1240780f..72f28b1e61 100644 --- a/autoload.php +++ b/autoload.php @@ -1,368 +1,369 @@ __DIR__ . '/includes/api/ApiFlow.php', 'ApiFlowBase' => __DIR__ . '/includes/api/ApiFlowBase.php', 'ApiFlowBaseGet' => __DIR__ . '/includes/api/ApiFlowBaseGet.php', 'ApiFlowBasePost' => __DIR__ . '/includes/api/ApiFlowBasePost.php', 'ApiFlowEditHeader' => __DIR__ . '/includes/api/ApiFlowEditHeader.php', 'ApiFlowEditPost' => __DIR__ . '/includes/api/ApiFlowEditPost.php', 'ApiFlowEditTitle' => __DIR__ . '/includes/api/ApiFlowEditTitle.php', 'ApiFlowEditTopicSummary' => __DIR__ . '/includes/api/ApiFlowEditTopicSummary.php', 'ApiFlowLockTopic' => __DIR__ . '/includes/api/ApiFlowLockTopic.php', 'ApiFlowModeratePost' => __DIR__ . '/includes/api/ApiFlowModeratePost.php', 'ApiFlowModerateTopic' => __DIR__ . '/includes/api/ApiFlowModerateTopic.php', 'ApiFlowNewTopic' => __DIR__ . '/includes/api/ApiFlowNewTopic.php', 'ApiFlowReply' => __DIR__ . '/includes/api/ApiFlowReply.php', 'ApiFlowViewHeader' => __DIR__ . '/includes/api/ApiFlowViewHeader.php', 'ApiFlowViewPost' => __DIR__ . '/includes/api/ApiFlowViewPost.php', 'ApiFlowViewTopic' => __DIR__ . '/includes/api/ApiFlowViewTopic.php', 'ApiFlowViewTopicList' => __DIR__ . '/includes/api/ApiFlowViewTopicList.php', 'ApiFlowViewTopicSummary' => __DIR__ . '/includes/api/ApiFlowViewTopicSummary.php', 'ApiParsoidUtilsFlow' => __DIR__ . '/includes/api/ApiParsoidUtilsFlow.php', 'ApiQueryPropFlowInfo' => __DIR__ . '/includes/api/ApiQueryPropFlowInfo.php', 'FlowHooks' => __DIR__ . '/Hooks.php', 'Flow\\Actions\\CompareHeaderRevisionsAction' => __DIR__ . '/includes/Actions/CompareHeaderRevisionsAction.php', 'Flow\\Actions\\ComparePostRevisionsAction' => __DIR__ . '/includes/Actions/ComparePostRevisionsAction.php', 'Flow\\Actions\\ComparePostSummaryRevisionsAction' => __DIR__ . '/includes/Actions/ComparePostSummaryRevisionsAction.php', 'Flow\\Actions\\CreateTopicSummaryAction' => __DIR__ . '/includes/Actions/CreateTopicSummaryAction.php', 'Flow\\Actions\\EditAction' => __DIR__ . '/includes/Actions/EditAction.php', 'Flow\\Actions\\EditHeaderAction' => __DIR__ . '/includes/Actions/EditHeaderAction.php', 'Flow\\Actions\\EditPostAction' => __DIR__ . '/includes/Actions/EditPostAction.php', 'Flow\\Actions\\EditTitleAction' => __DIR__ . '/includes/Actions/EditTitleAction.php', 'Flow\\Actions\\EditTopicSummaryAction' => __DIR__ . '/includes/Actions/EditTopicSummaryAction.php', 'Flow\\Actions\\FlowAction' => __DIR__ . '/includes/Actions/Action.php', 'Flow\\Actions\\HistoryAction' => __DIR__ . '/includes/Actions/HistoryAction.php', 'Flow\\Actions\\LockTopicAction' => __DIR__ . '/includes/Actions/LockTopicAction.php', 'Flow\\Actions\\ModeratePostAction' => __DIR__ . '/includes/Actions/ModeratePostAction.php', 'Flow\\Actions\\ModerateTopicAction' => __DIR__ . '/includes/Actions/ModerateTopicAction.php', 'Flow\\Actions\\NewTopicAction' => __DIR__ . '/includes/Actions/NewTopicAction.php', 'Flow\\Actions\\PostSingleViewAction' => __DIR__ . '/includes/Actions/PostSingleViewAction.php', 'Flow\\Actions\\PurgeAction' => __DIR__ . '/includes/Actions/PurgeAction.php', 'Flow\\Actions\\ReplyAction' => __DIR__ . '/includes/Actions/ReplyAction.php', 'Flow\\Actions\\RestorePostAction' => __DIR__ . '/includes/Actions/RestorePostAction.php', 'Flow\\Actions\\RestoreTopicAction' => __DIR__ . '/includes/Actions/RestoreTopicAction.php', 'Flow\\Actions\\ViewAction' => __DIR__ . '/includes/Actions/ViewAction.php', 'Flow\\Actions\\ViewHeaderAction' => __DIR__ . '/includes/Actions/ViewHeaderAction.php', 'Flow\\Actions\\ViewTopicSummaryAction' => __DIR__ . '/includes/Actions/ViewTopicSummaryAction.php', 'Flow\\BlockFactory' => __DIR__ . '/includes/BlockFactory.php', 'Flow\\Block\\AbstractBlock' => __DIR__ . '/includes/Block/Block.php', 'Flow\\Block\\Block' => __DIR__ . '/includes/Block/Block.php', 'Flow\\Block\\BoardHistoryBlock' => __DIR__ . '/includes/Block/BoardHistory.php', 'Flow\\Block\\HeaderBlock' => __DIR__ . '/includes/Block/Header.php', 'Flow\\Block\\TopicBlock' => __DIR__ . '/includes/Block/Topic.php', 'Flow\\Block\\TopicListBlock' => __DIR__ . '/includes/Block/TopicList.php', 'Flow\\Block\\TopicSummaryBlock' => __DIR__ . '/includes/Block/TopicSummary.php', 'Flow\\Collection\\AbstractCollection' => __DIR__ . '/includes/Collection/AbstractCollection.php', 'Flow\\Collection\\CollectionCache' => __DIR__ . '/includes/Collection/CollectionCache.php', 'Flow\\Collection\\HeaderCollection' => __DIR__ . '/includes/Collection/HeaderCollection.php', 'Flow\\Collection\\LocalCacheAbstractCollection' => __DIR__ . '/includes/Collection/LocalCacheAbstractCollection.php', 'Flow\\Collection\\PostCollection' => __DIR__ . '/includes/Collection/PostCollection.php', 'Flow\\Collection\\PostSummaryCollection' => __DIR__ . '/includes/Collection/PostSummaryCollection.php', 'Flow\\Container' => __DIR__ . '/includes/Container.php', 'Flow\\Content\\BoardContent' => __DIR__ . '/includes/Content/BoardContent.php', 'Flow\\Content\\BoardContentHandler' => __DIR__ . '/includes/Content/BoardContentHandler.php', 'Flow\\Content\\Content' => __DIR__ . '/includes/Content/Content.php', 'Flow\\Data\\BagOStuff\\BufferedBagOStuff' => __DIR__ . '/includes/Data/BagOStuff/BufferedBagOStuff.php', 'Flow\\Data\\BagOStuff\\LocalBufferedBagOStuff' => __DIR__ . '/includes/Data/BagOStuff/LocalBufferedBagOStuff.php', 'Flow\\Data\\BufferedCache' => __DIR__ . '/includes/Data/BufferedCache.php', 'Flow\\Data\\Compactor' => __DIR__ . '/includes/Data/Compactor.php', 'Flow\\Data\\Compactor\\FeatureCompactor' => __DIR__ . '/includes/Data/Compactor/FeatureCompactor.php', 'Flow\\Data\\Compactor\\ShallowCompactor' => __DIR__ . '/includes/Data/Compactor/ShallowCompactor.php', 'Flow\\Data\\Index' => __DIR__ . '/includes/Data/Index.php', 'Flow\\Data\\Index\\BoardHistoryIndex' => __DIR__ . '/includes/Data/Index/BoardHistoryIndex.php', 'Flow\\Data\\Index\\FeatureIndex' => __DIR__ . '/includes/Data/Index/FeatureIndex.php', 'Flow\\Data\\Index\\TopKIndex' => __DIR__ . '/includes/Data/Index/TopKIndex.php', 'Flow\\Data\\Index\\TopicHistoryIndex' => __DIR__ . '/includes/Data/Index/TopicHistoryIndex.php', 'Flow\\Data\\Index\\UniqueFeatureIndex' => __DIR__ . '/includes/Data/Index/UniqueFeatureIndex.php', 'Flow\\Data\\LifecycleHandler' => __DIR__ . '/includes/Data/LifecycleHandler.php', 'Flow\\Data\\Listener\\AbstractTopicInsertListener' => __DIR__ . '/includes/Data/Listener/WatchTopicListener.php', 'Flow\\Data\\Listener\\DeferredInsertLifecycleHandler' => __DIR__ . '/includes/Data/Listener/DeferredInsertLifecycleHandler.php', 'Flow\\Data\\Listener\\EditCountListener' => __DIR__ . '/includes/Data/Listener/EditCountListener.php', 'Flow\\Data\\Listener\\ImmediateWatchTopicListener' => __DIR__ . '/includes/Data/Listener/WatchTopicListener.php', 'Flow\\Data\\Listener\\NotificationListener' => __DIR__ . '/includes/Data/Listener/NotificationListener.php', 'Flow\\Data\\Listener\\OccupationListener' => __DIR__ . '/includes/Data/Listener/OccupationListener.php', 'Flow\\Data\\Listener\\RecentChangesListener' => __DIR__ . '/includes/Data/Listener/RecentChangesListener.php', 'Flow\\Data\\Listener\\ReferenceRecorder' => __DIR__ . '/includes/Data/Listener/ReferenceRecorder.php', 'Flow\\Data\\Listener\\UrlGenerationListener' => __DIR__ . '/includes/Data/Listener/UrlGenerationListener.php', 'Flow\\Data\\Listener\\UserNameListener' => __DIR__ . '/includes/Data/Listener/UserNameListener.php', 'Flow\\Data\\Listener\\WorkflowTopicListListener' => __DIR__ . '/includes/Data/Listener/WorkflowTopicListListener.php', 'Flow\\Data\\ManagerGroup' => __DIR__ . '/includes/Data/ManagerGroup.php', 'Flow\\Data\\Mapper\\BasicObjectMapper' => __DIR__ . '/includes/Data/Mapper/BasicObjectMapper.php', 'Flow\\Data\\Mapper\\CachingObjectMapper' => __DIR__ . '/includes/Data/Mapper/CachingObjectMapper.php', 'Flow\\Data\\ObjectLocator' => __DIR__ . '/includes/Data/ObjectLocator.php', 'Flow\\Data\\ObjectManager' => __DIR__ . '/includes/Data/ObjectManager.php', 'Flow\\Data\\ObjectMapper' => __DIR__ . '/includes/Data/ObjectMapper.php', 'Flow\\Data\\ObjectStorage' => __DIR__ . '/includes/Data/ObjectStorage.php', 'Flow\\Data\\Pager\\HistoryPager' => __DIR__ . '/includes/Data/Pager/HistoryPager.php', 'Flow\\Data\\Pager\\Pager' => __DIR__ . '/includes/Data/Pager/Pager.php', 'Flow\\Data\\Pager\\PagerPage' => __DIR__ . '/includes/Data/Pager/PagerPage.php', 'Flow\\Data\\Storage\\BasicDbStorage' => __DIR__ . '/includes/Data/Storage/BasicDbStorage.php', 'Flow\\Data\\Storage\\BoardHistoryStorage' => __DIR__ . '/includes/Data/Storage/BoardHistoryStorage.php', 'Flow\\Data\\Storage\\DbStorage' => __DIR__ . '/includes/Data/Storage/DbStorage.php', 'Flow\\Data\\Storage\\HeaderRevisionStorage' => __DIR__ . '/includes/Data/Storage/HeaderRevisionStorage.php', 'Flow\\Data\\Storage\\PostRevisionStorage' => __DIR__ . '/includes/Data/Storage/PostRevisionStorage.php', 'Flow\\Data\\Storage\\PostSummaryRevisionStorage' => __DIR__ . '/includes/Data/Storage/PostSummaryRevisionStorage.php', 'Flow\\Data\\Storage\\RevisionStorage' => __DIR__ . '/includes/Data/Storage/RevisionStorage.php', 'Flow\\Data\\Storage\\TopicHistoryStorage' => __DIR__ . '/includes/Data/Storage/TopicHistoryStorage.php', 'Flow\\Data\\Storage\\TopicListLastUpdatedStorage' => __DIR__ . '/includes/Data/Storage/TopicListLastUpdatedStorage.php', 'Flow\\Data\\Storage\\TopicListStorage' => __DIR__ . '/includes/Data/Storage/TopicListStorage.php', 'Flow\\Data\\Utils\\Merger' => __DIR__ . '/includes/Data/Utils/Merger.php', 'Flow\\Data\\Utils\\MultiDimArray' => __DIR__ . '/includes/Data/Utils/MultiDimArray.php', 'Flow\\Data\\Utils\\RawSql' => __DIR__ . '/includes/Data/Utils/RawSql.php', 'Flow\\Data\\Utils\\RecentChangeFactory' => __DIR__ . '/includes/Data/Utils/RecentChangeFactory.php', 'Flow\\Data\\Utils\\ResultDuplicator' => __DIR__ . '/includes/Data/Utils/ResultDuplicator.php', 'Flow\\Data\\Utils\\SortArrayByKeys' => __DIR__ . '/includes/Data/Utils/SortArrayByKeys.php', 'Flow\\Data\\Utils\\UserMerger' => __DIR__ . '/includes/Data/Utils/UserMerger.php', 'Flow\\DbFactory' => __DIR__ . '/includes/DbFactory.php', 'Flow\\Exception\\CatchableFatalErrorException' => __DIR__ . '/includes/Exception/CatchableFatalErrorException.php', 'Flow\\Exception\\CrossWikiException' => __DIR__ . '/includes/Exception/ExceptionHandling.php', 'Flow\\Exception\\DataModelException' => __DIR__ . '/includes/Exception/ExceptionHandling.php', 'Flow\\Exception\\DataPersistenceException' => __DIR__ . '/includes/Exception/ExceptionHandling.php', 'Flow\\Exception\\FailCommitException' => __DIR__ . '/includes/Exception/ExceptionHandling.php', 'Flow\\Exception\\FlowException' => __DIR__ . '/includes/Exception/ExceptionHandling.php', 'Flow\\Exception\\InvalidActionException' => __DIR__ . '/includes/Exception/ExceptionHandling.php', 'Flow\\Exception\\InvalidDataException' => __DIR__ . '/includes/Exception/ExceptionHandling.php', 'Flow\\Exception\\InvalidInputException' => __DIR__ . '/includes/Exception/ExceptionHandling.php', 'Flow\\Exception\\InvalidReferenceException' => __DIR__ . '/includes/Exception/ExceptionHandling.php', 'Flow\\Exception\\InvalidTopicUuidException' => __DIR__ . '/includes/Exception/ExceptionHandling.php', 'Flow\\Exception\\NoIndexException' => __DIR__ . '/includes/Exception/ExceptionHandling.php', 'Flow\\Exception\\NoParsoidException' => __DIR__ . '/includes/Exception/ExceptionHandling.php', 'Flow\\Exception\\PermissionException' => __DIR__ . '/includes/Exception/ExceptionHandling.php', 'Flow\\Exception\\UnknownWorkflowIdException' => __DIR__ . '/includes/Exception/ExceptionHandling.php', 'Flow\\Exception\\WikitextException' => __DIR__ . '/includes/Exception/ExceptionHandling.php', 'Flow\\Exception\\WrongNumberArgumentsException' => __DIR__ . '/includes/Exception/ExceptionHandling.php', 'Flow\\FlowActions' => __DIR__ . '/includes/FlowActions.php', 'Flow\\Formatter\\AbstractFormatter' => __DIR__ . '/includes/Formatter/AbstractFormatter.php', 'Flow\\Formatter\\AbstractQuery' => __DIR__ . '/includes/Formatter/AbstractQuery.php', 'Flow\\Formatter\\BaseTopicListFormatter' => __DIR__ . '/includes/Formatter/BaseTopicListFormatter.php', 'Flow\\Formatter\\BoardHistoryQuery' => __DIR__ . '/includes/Formatter/BoardHistoryQuery.php', 'Flow\\Formatter\\CheckUserFormatter' => __DIR__ . '/includes/Formatter/CheckUserFormatter.php', 'Flow\\Formatter\\CheckUserQuery' => __DIR__ . '/includes/Formatter/CheckUserQuery.php', 'Flow\\Formatter\\CheckUserRow' => __DIR__ . '/includes/Formatter/CheckUserQuery.php', 'Flow\\Formatter\\Contributions' => __DIR__ . '/includes/Formatter/Contributions.php', 'Flow\\Formatter\\ContributionsQuery' => __DIR__ . '/includes/Formatter/ContributionsQuery.php', 'Flow\\Formatter\\ContributionsRow' => __DIR__ . '/includes/Formatter/ContributionsQuery.php', 'Flow\\Formatter\\FeedItemFormatter' => __DIR__ . '/includes/Formatter/FeedItemFormatter.php', 'Flow\\Formatter\\FormatterRow' => __DIR__ . '/includes/Formatter/AbstractQuery.php', 'Flow\\Formatter\\HeaderViewQuery' => __DIR__ . '/includes/Formatter/RevisionViewQuery.php', 'Flow\\Formatter\\IRCLineUrlFormatter' => __DIR__ . '/includes/Formatter/IRCLineUrlFormatter.php', 'Flow\\Formatter\\PostHistoryQuery' => __DIR__ . '/includes/Formatter/PostHistoryQuery.php', 'Flow\\Formatter\\PostSummaryQuery' => __DIR__ . '/includes/Formatter/PostSummaryQuery.php', 'Flow\\Formatter\\PostSummaryViewQuery' => __DIR__ . '/includes/Formatter/RevisionViewQuery.php', 'Flow\\Formatter\\PostViewQuery' => __DIR__ . '/includes/Formatter/RevisionViewQuery.php', 'Flow\\Formatter\\RecentChanges' => __DIR__ . '/includes/Formatter/RecentChanges.php', 'Flow\\Formatter\\RecentChangesQuery' => __DIR__ . '/includes/Formatter/RecentChangesQuery.php', 'Flow\\Formatter\\RecentChangesRow' => __DIR__ . '/includes/Formatter/RecentChangesQuery.php', 'Flow\\Formatter\\RevisionDiffViewFormatter' => __DIR__ . '/includes/Formatter/RevisionViewFormatter.php', 'Flow\\Formatter\\RevisionFormatter' => __DIR__ . '/includes/Formatter/RevisionFormatter.php', 'Flow\\Formatter\\RevisionViewFormatter' => __DIR__ . '/includes/Formatter/RevisionViewFormatter.php', 'Flow\\Formatter\\RevisionViewQuery' => __DIR__ . '/includes/Formatter/RevisionViewQuery.php', 'Flow\\Formatter\\SinglePostQuery' => __DIR__ . '/includes/Formatter/SinglePostQuery.php', 'Flow\\Formatter\\TocTopicListFormatter' => __DIR__ . '/includes/Formatter/TocTopicListFormatter.php', 'Flow\\Formatter\\TopicFormatter' => __DIR__ . '/includes/Formatter/TopicFormatter.php', 'Flow\\Formatter\\TopicHistoryQuery' => __DIR__ . '/includes/Formatter/TopicHistoryQuery.php', 'Flow\\Formatter\\TopicListFormatter' => __DIR__ . '/includes/Formatter/TopicListFormatter.php', 'Flow\\Formatter\\TopicListQuery' => __DIR__ . '/includes/Formatter/TopicListQuery.php', 'Flow\\Formatter\\TopicRow' => __DIR__ . '/includes/Formatter/TopicRow.php', 'Flow\\Import\\Converter' => __DIR__ . '/includes/Import/Converter.php', 'Flow\\Import\\FileImportSourceStore' => __DIR__ . '/includes/Import/ImportSourceStore.php', 'Flow\\Import\\HistoricalUIDGenerator' => __DIR__ . '/includes/Import/Importer.php', 'Flow\\Import\\IConversionStrategy' => __DIR__ . '/includes/Import/IConversionStrategy.php', 'Flow\\Import\\IImportHeader' => __DIR__ . '/includes/Import/ImportSource.php', 'Flow\\Import\\IImportObject' => __DIR__ . '/includes/Import/ImportSource.php', 'Flow\\Import\\IImportPost' => __DIR__ . '/includes/Import/ImportSource.php', 'Flow\\Import\\IImportSource' => __DIR__ . '/includes/Import/ImportSource.php', 'Flow\\Import\\IImportSummary' => __DIR__ . '/includes/Import/ImportSource.php', 'Flow\\Import\\IImportTopic' => __DIR__ . '/includes/Import/ImportSource.php', 'Flow\\Import\\IObjectRevision' => __DIR__ . '/includes/Import/ImportSource.php', 'Flow\\Import\\IRevisionableObject' => __DIR__ . '/includes/Import/ImportSource.php', 'Flow\\Import\\ImportException' => __DIR__ . '/includes/Import/Exception.php', 'Flow\\Import\\ImportSourceStore' => __DIR__ . '/includes/Import/ImportSourceStore.php', 'Flow\\Import\\ImportSourceStoreException' => __DIR__ . '/includes/Import/Exception.php', 'Flow\\Import\\Importer' => __DIR__ . '/includes/Import/Importer.php', 'Flow\\Import\\LiquidThreadsApi\\ApiBackend' => __DIR__ . '/includes/Import/LiquidThreadsApi/Source.php', 'Flow\\Import\\LiquidThreadsApi\\ApiNotFoundException' => __DIR__ . '/includes/Import/LiquidThreadsApi/Exception.php', 'Flow\\Import\\LiquidThreadsApi\\CachedApiData' => __DIR__ . '/includes/Import/LiquidThreadsApi/CachedData.php', 'Flow\\Import\\LiquidThreadsApi\\CachedData' => __DIR__ . '/includes/Import/LiquidThreadsApi/CachedData.php', 'Flow\\Import\\LiquidThreadsApi\\CachedPageData' => __DIR__ . '/includes/Import/LiquidThreadsApi/CachedData.php', 'Flow\\Import\\LiquidThreadsApi\\CachedThreadData' => __DIR__ . '/includes/Import/LiquidThreadsApi/CachedData.php', 'Flow\\Import\\LiquidThreadsApi\\ConversionStrategy' => __DIR__ . '/includes/Import/LiquidThreadsApi/ConversionStrategy.php', 'Flow\\Import\\LiquidThreadsApi\\ImportHeader' => __DIR__ . '/includes/Import/LiquidThreadsApi/Objects.php', 'Flow\\Import\\LiquidThreadsApi\\ImportPost' => __DIR__ . '/includes/Import/LiquidThreadsApi/Objects.php', 'Flow\\Import\\LiquidThreadsApi\\ImportRevision' => __DIR__ . '/includes/Import/LiquidThreadsApi/Objects.php', 'Flow\\Import\\LiquidThreadsApi\\ImportSource' => __DIR__ . '/includes/Import/LiquidThreadsApi/Source.php', 'Flow\\Import\\LiquidThreadsApi\\ImportSummary' => __DIR__ . '/includes/Import/LiquidThreadsApi/Objects.php', 'Flow\\Import\\LiquidThreadsApi\\ImportTopic' => __DIR__ . '/includes/Import/LiquidThreadsApi/Objects.php', 'Flow\\Import\\LiquidThreadsApi\\LocalApiBackend' => __DIR__ . '/includes/Import/LiquidThreadsApi/Source.php', 'Flow\\Import\\LiquidThreadsApi\\MovedImportPost' => __DIR__ . '/includes/Import/LiquidThreadsApi/Objects.php', 'Flow\\Import\\LiquidThreadsApi\\MovedImportRevision' => __DIR__ . '/includes/Import/LiquidThreadsApi/Objects.php', 'Flow\\Import\\LiquidThreadsApi\\MovedImportTopic' => __DIR__ . '/includes/Import/LiquidThreadsApi/Objects.php', 'Flow\\Import\\LiquidThreadsApi\\PageRevisionedObject' => __DIR__ . '/includes/Import/LiquidThreadsApi/Objects.php', 'Flow\\Import\\LiquidThreadsApi\\RemoteApiBackend' => __DIR__ . '/includes/Import/LiquidThreadsApi/Source.php', 'Flow\\Import\\LiquidThreadsApi\\ReplyIterator' => __DIR__ . '/includes/Import/LiquidThreadsApi/Iterators.php', 'Flow\\Import\\LiquidThreadsApi\\RevisionIterator' => __DIR__ . '/includes/Import/LiquidThreadsApi/Iterators.php', 'Flow\\Import\\LiquidThreadsApi\\ScriptedImportRevision' => __DIR__ . '/includes/Import/LiquidThreadsApi/Objects.php', 'Flow\\Import\\LiquidThreadsApi\\TopicIterator' => __DIR__ . '/includes/Import/LiquidThreadsApi/Iterators.php', 'Flow\\Import\\NullImportSourceStore' => __DIR__ . '/includes/Import/ImportSourceStore.php', 'Flow\\Import\\PageImportState' => __DIR__ . '/includes/Import/Importer.php', 'Flow\\Import\\Plain\\ImportHeader' => __DIR__ . '/includes/Import/Plain/ImportHeader.php', 'Flow\\Import\\Plain\\ObjectRevision' => __DIR__ . '/includes/Import/Plain/ObjectRevision.php', 'Flow\\Import\\Postprocessor\\LqtRedirector' => __DIR__ . '/includes/Import/Postprocessor/LqtRedirector.php', 'Flow\\Import\\Postprocessor\\PostprocessingException' => __DIR__ . '/includes/Import/Postprocessor/PostprocessingException.php', 'Flow\\Import\\Postprocessor\\Postprocessor' => __DIR__ . '/includes/Import/Postprocessor/Postprocessor.php', 'Flow\\Import\\Postprocessor\\ProcessorGroup' => __DIR__ . '/includes/Import/Postprocessor/ProcessorGroup.php', 'Flow\\Import\\Postprocessor\\SpecialLogTopic' => __DIR__ . '/includes/Import/Postprocessor/SpecialLogTopic.php', 'Flow\\Import\\TalkpageImportOperation' => __DIR__ . '/includes/Import/Importer.php', 'Flow\\Import\\TopicImportState' => __DIR__ . '/includes/Import/Importer.php', 'Flow\\Import\\Wikitext\\ConversionStrategy' => __DIR__ . '/includes/Import/Wikitext/ConversionStrategy.php', 'Flow\\Import\\Wikitext\\ImportSource' => __DIR__ . '/includes/Import/Wikitext/ImportSource.php', 'Flow\\LinksTableUpdater' => __DIR__ . '/includes/LinksTableUpdater.php', 'Flow\\Log\\ActionFormatter' => __DIR__ . '/includes/Log/ActionFormatter.php', 'Flow\\Log\\Logger' => __DIR__ . '/includes/Log/Logger.php', 'Flow\\Log\\LqtImportFormatter' => __DIR__ . '/includes/Log/LqtImportFormatter.php', 'Flow\\Log\\PostModerationLogger' => __DIR__ . '/includes/Log/PostModerationLogger.php', 'Flow\\Model\\AbstractRevision' => __DIR__ . '/includes/Model/AbstractRevision.php', 'Flow\\Model\\AbstractSummary' => __DIR__ . '/includes/Model/AbstractSummary.php', 'Flow\\Model\\Anchor' => __DIR__ . '/includes/Model/Anchor.php', 'Flow\\Model\\Header' => __DIR__ . '/includes/Model/Header.php', 'Flow\\Model\\PostRevision' => __DIR__ . '/includes/Model/PostRevision.php', 'Flow\\Model\\PostSummary' => __DIR__ . '/includes/Model/PostSummary.php', 'Flow\\Model\\Reference' => __DIR__ . '/includes/Model/Reference.php', 'Flow\\Model\\TopicListEntry' => __DIR__ . '/includes/Model/TopicListEntry.php', 'Flow\\Model\\URLReference' => __DIR__ . '/includes/Model/URLReference.php', 'Flow\\Model\\UUID' => __DIR__ . '/includes/Model/UUID.php', 'Flow\\Model\\UserTuple' => __DIR__ . '/includes/Model/UserTuple.php', 'Flow\\Model\\WikiReference' => __DIR__ . '/includes/Model/WikiReference.php', 'Flow\\Model\\Workflow' => __DIR__ . '/includes/Model/Workflow.php', 'Flow\\NewTopicFormatter' => __DIR__ . '/includes/Notifications/Formatter.php', 'Flow\\NotificationController' => __DIR__ . '/includes/Notifications/Controller.php', 'Flow\\NotificationFormatter' => __DIR__ . '/includes/Notifications/Formatter.php', 'Flow\\NotificationsUserLocator' => __DIR__ . '/includes/Notifications/UserLocator.php', 'Flow\\OccupationController' => __DIR__ . '/includes/TalkpageManager.php', 'Flow\\Parsoid\\ContentFixer' => __DIR__ . '/includes/Parsoid/ContentFixer.php', 'Flow\\Parsoid\\Extractor' => __DIR__ . '/includes/Parsoid/Extractor.php', + 'Flow\\Parsoid\\Extractor\\CategoryExtractor' => __DIR__ . '/includes/Parsoid/Extractor/CategoryExtractor.php', 'Flow\\Parsoid\\Extractor\\ExtLinkExtractor' => __DIR__ . '/includes/Parsoid/Extractor/ExtLinkExtractor.php', 'Flow\\Parsoid\\Extractor\\ImageExtractor' => __DIR__ . '/includes/Parsoid/Extractor/ImageExtractor.php', 'Flow\\Parsoid\\Extractor\\PlaceholderExtractor' => __DIR__ . '/includes/Parsoid/Extractor/PlaceholderExtractor.php', 'Flow\\Parsoid\\Extractor\\TransclusionExtractor' => __DIR__ . '/includes/Parsoid/Extractor/TransclusionExtractor.php', 'Flow\\Parsoid\\Extractor\\WikiLinkExtractor' => __DIR__ . '/includes/Parsoid/Extractor/WikiLinkExtractor.php', 'Flow\\Parsoid\\Fixer' => __DIR__ . '/includes/Parsoid/Fixer.php', 'Flow\\Parsoid\\Fixer\\BadImageRemover' => __DIR__ . '/includes/Parsoid/Fixer/BadImageRemover.php', 'Flow\\Parsoid\\Fixer\\Redlinker' => __DIR__ . '/includes/Parsoid/Fixer/Redlinker.php', 'Flow\\Parsoid\\ReferenceExtractor' => __DIR__ . '/includes/Parsoid/ReferenceExtractor.php', 'Flow\\Parsoid\\ReferenceFactory' => __DIR__ . '/includes/Parsoid/ReferenceFactory.php', 'Flow\\Parsoid\\Utils' => __DIR__ . '/includes/Parsoid/Utils.php', 'Flow\\RecoverableErrorHandler' => __DIR__ . '/includes/RecoverableErrorHandler.php', 'Flow\\ReferenceClarifier' => __DIR__ . '/includes/ReferenceClarifier.php', 'Flow\\Repository\\MultiGetList' => __DIR__ . '/includes/Repository/MultiGetList.php', 'Flow\\Repository\\RootPostLoader' => __DIR__ . '/includes/Repository/RootPostLoader.php', 'Flow\\Repository\\TitleRepository' => __DIR__ . '/includes/Repository/TitleRepository.php', 'Flow\\Repository\\TreeRepository' => __DIR__ . '/includes/Repository/TreeRepository.php', 'Flow\\Repository\\UserNameBatch' => __DIR__ . '/includes/Repository/UserNameBatch.php', 'Flow\\Repository\\UserName\\OneStepUserNameQuery' => __DIR__ . '/includes/Repository/UserName/OneStepUserNameQuery.php', 'Flow\\Repository\\UserName\\TwoStepUserNameQuery' => __DIR__ . '/includes/Repository/UserName/TwoStepUserNameQuery.php', 'Flow\\Repository\\UserName\\UserNameQuery' => __DIR__ . '/includes/Repository/UserName/UserNameQuery.php', 'Flow\\RevisionActionPermissions' => __DIR__ . '/includes/RevisionActionPermissions.php', 'Flow\\SpamFilter\\AbuseFilter' => __DIR__ . '/includes/SpamFilter/AbuseFilter.php', 'Flow\\SpamFilter\\ConfirmEdit' => __DIR__ . '/includes/SpamFilter/ConfirmEdit.php', 'Flow\\SpamFilter\\ContentLengthFilter' => __DIR__ . '/includes/SpamFilter/ContentLengthFilter.php', 'Flow\\SpamFilter\\Controller' => __DIR__ . '/includes/SpamFilter/Controller.php', 'Flow\\SpamFilter\\SpamBlacklist' => __DIR__ . '/includes/SpamFilter/SpamBlacklist.php', 'Flow\\SpamFilter\\SpamFilter' => __DIR__ . '/includes/SpamFilter/SpamFilter.php', 'Flow\\SpamFilter\\SpamRegex' => __DIR__ . '/includes/SpamFilter/SpamRegex.php', 'Flow\\SpecialFlow' => __DIR__ . '/includes/SpecialFlow.php', 'Flow\\SubmissionHandler' => __DIR__ . '/includes/SubmissionHandler.php', 'Flow\\TalkpageManager' => __DIR__ . '/includes/TalkpageManager.php', 'Flow\\TemplateHelper' => __DIR__ . '/includes/TemplateHelper.php', 'Flow\\Templating' => __DIR__ . '/includes/Templating.php', 'Flow\\Tests\\Api\\ApiFlowEditHeaderTest' => __DIR__ . '/tests/phpunit/api/ApiFlowEditHeaderTest.php', 'Flow\\Tests\\Api\\ApiFlowEditPostTest' => __DIR__ . '/tests/phpunit/api/ApiFlowEditPostTest.php', 'Flow\\Tests\\Api\\ApiFlowEditTitleTest' => __DIR__ . '/tests/phpunit/api/ApiFlowEditTitleTest.php', 'Flow\\Tests\\Api\\ApiFlowEditTopicSummaryTest' => __DIR__ . '/tests/phpunit/api/ApiFlowEditTopicSummary.php', 'Flow\\Tests\\Api\\ApiFlowLockTopicTest' => __DIR__ . '/tests/phpunit/api/ApiFlowLockTopicTest.php', 'Flow\\Tests\\Api\\ApiFlowModeratePostTest' => __DIR__ . '/tests/phpunit/api/ApiFlowModeratePostTest.php', 'Flow\\Tests\\Api\\ApiFlowModerateTopicTest' => __DIR__ . '/tests/phpunit/api/ApiFlowModerateTopicTest.php', 'Flow\\Tests\\Api\\ApiFlowReplyTest' => __DIR__ . '/tests/phpunit/api/ApiFlowReplyTest.php', 'Flow\\Tests\\Api\\ApiFlowViewHeaderTest' => __DIR__ . '/tests/phpunit/api/ApiFlowViewHeaderTest.php', 'Flow\\Tests\\Api\\ApiFlowViewTopicListTest' => __DIR__ . '/tests/phpunit/api/ApiFlowViewTopicListTest.php', 'Flow\\Tests\\Api\\ApiTestCase' => __DIR__ . '/tests/phpunit/api/ApiTestCase.php', 'Flow\\Tests\\Api\\ApiWatchTopicTest' => __DIR__ . '/tests/phpunit/api/ApiWatchTopicTest.php', 'Flow\\Tests\\BlockFactoryTest' => __DIR__ . '/tests/phpunit/BlockFactoryTest.php', 'Flow\\Tests\\Block\\TopicListTest' => __DIR__ . '/tests/phpunit/Block/TopicListTest.php', 'Flow\\Tests\\BufferedBagOStuffTest' => __DIR__ . '/tests/phpunit/Data/BagOStuff/BufferedBagOStuffTest.php', 'Flow\\Tests\\BufferedCacheTest' => __DIR__ . '/tests/phpunit/Data/BufferedCacheTest.php', 'Flow\\Tests\\Collection\\PostCollectionTest' => __DIR__ . '/tests/phpunit/Collection/PostCollectionTest.php', 'Flow\\Tests\\Collection\\RevisionCollectionPermissionsTest' => __DIR__ . '/tests/phpunit/Collection/RevisionCollectionPermissionsTest.php', 'Flow\\Tests\\ContainerTest' => __DIR__ . '/tests/phpunit/ContainerTest.php', 'Flow\\Tests\\Data\\CachingObjectManagerTest' => __DIR__ . '/tests/phpunit/Data/CachingObjectMapperTest.php', 'Flow\\Tests\\Data\\FlowNothingTest' => __DIR__ . '/tests/phpunit/Data/NothingTest.php', 'Flow\\Tests\\Data\\IndexTest' => __DIR__ . '/tests/phpunit/Data/IndexTest.php', 'Flow\\Tests\\Data\\Index\\FeatureIndexTest' => __DIR__ . '/tests/phpunit/Data/Index/FeatureIndexTest.php', 'Flow\\Tests\\Data\\Index\\MockFeatureIndex' => __DIR__ . '/tests/phpunit/Data/Index/FeatureIndexTest.php', 'Flow\\Tests\\Data\\Listener\\RecentChangesListenerTest' => __DIR__ . '/tests/phpunit/Data/Listener/RecentChangesListenerTest.php', 'Flow\\Tests\\Data\\ManagerGroupTest' => __DIR__ . '/tests/phpunit/Data/ManagerGroupTest.php', 'Flow\\Tests\\Data\\ObjectLocatorTest' => __DIR__ . '/tests/phpunit/Data/ObjectLocatorTest.php', 'Flow\\Tests\\Data\\Pager\\PagerTest' => __DIR__ . '/tests/phpunit/Data/Pager/PagerTest.php', 'Flow\\Tests\\Data\\RevisionStorageTest' => __DIR__ . '/tests/phpunit/Data/RevisionStorageTest.php', 'Flow\\Tests\\Data\\Storage\\RevisionStorageTest' => __DIR__ . '/tests/phpunit/Data/Storage/RevisionStorageTest.php', 'Flow\\Tests\\Data\\UserNameBatchTest' => __DIR__ . '/tests/phpunit/Data/UserNameBatchTest.php', 'Flow\\Tests\\Data\\UserNameListenerTest' => __DIR__ . '/tests/phpunit/Data/UserNameListenerTest.php', 'Flow\\Tests\\FlowActionsTest' => __DIR__ . '/tests/phpunit/FlowActionsTest.php', 'Flow\\Tests\\FlowTestCase' => __DIR__ . '/tests/phpunit/FlowTestCase.php', 'Flow\\Tests\\Formatter\\FormatterTest' => __DIR__ . '/tests/phpunit/Formatter/FormatterTest.php', 'Flow\\Tests\\Formatter\\RevisionFormatterTest' => __DIR__ . '/tests/phpunit/Formatter/RevisionFormatterTest.php', 'Flow\\Tests\\Handlebars\\FlowPostMetaActionsTest' => __DIR__ . '/tests/phpunit/Handlebars/FlowPostMetaActionsTest.php', 'Flow\\Tests\\HookTest' => __DIR__ . '/tests/phpunit/HookTest.php', 'Flow\\Tests\\Import\\ConverterTest' => __DIR__ . '/tests/phpunit/Import/ConverterTest.php', 'Flow\\Tests\\Import\\HistoricalUIDGeneratorTest' => __DIR__ . '/tests/phpunit/Import/HistoricalUIDGeneratorTest.php', 'Flow\\Tests\\Import\\LiquidThreadsApi\\ConversionStrategyTest' => __DIR__ . '/tests/phpunit/Import/LiquidThreadsApi/ConversionStrategyTest.php', 'Flow\\Tests\\Import\\PageImportStateTest' => __DIR__ . '/tests/phpunit/Import/PageImportStateTest.php', 'Flow\\Tests\\Import\\TalkpageImportOperationTest' => __DIR__ . '/tests/phpunit/Import/TalkpageImportOperationTest.php', 'Flow\\Tests\\Import\\Wikitext\\ConversionStrategyTest' => __DIR__ . '/tests/phpunit/Import/Wikitext/ConversionStrategyTest.php', 'Flow\\Tests\\Import\\Wikitext\\ImportSourceTest' => __DIR__ . '/tests/phpunit/Import/Wikitext/ImportSourceTest.php', 'Flow\\Tests\\LinksTableTest' => __DIR__ . '/tests/phpunit/LinksTableTest.php', 'Flow\\Tests\\LocalBufferedBagOStuffTest' => __DIR__ . '/tests/phpunit/Data/BagOStuff/LocalBufferedBagOStuffTest.php', 'Flow\\Tests\\Mock\\MockImportHeader' => __DIR__ . '/tests/phpunit/Mock/MockImportHeader.php', 'Flow\\Tests\\Mock\\MockImportPost' => __DIR__ . '/tests/phpunit/Mock/MockImportPost.php', 'Flow\\Tests\\Mock\\MockImportRevision' => __DIR__ . '/tests/phpunit/Mock/MockImportRevision.php', 'Flow\\Tests\\Mock\\MockImportSource' => __DIR__ . '/tests/phpunit/Mock/MockImportSource.php', 'Flow\\Tests\\Mock\\MockImportSummary' => __DIR__ . '/tests/phpunit/Mock/MockImportSummary.php', 'Flow\\Tests\\Mock\\MockImportTopic' => __DIR__ . '/tests/phpunit/Mock/MockImportTopic.php', 'Flow\\Tests\\Model\\PostRevisionTest' => __DIR__ . '/tests/phpunit/Model/PostRevisionTest.php', 'Flow\\Tests\\Model\\UUIDTest' => __DIR__ . '/tests/phpunit/Model/UUIDTest.php', 'Flow\\Tests\\Model\\UserTupleTest' => __DIR__ . '/tests/phpunit/Model/UserTupleTest.php', 'Flow\\Tests\\NotifiedUsersTest' => __DIR__ . '/tests/phpunit/Notifications/NotifiedUsersTest.php', 'Flow\\Tests\\PagerTest' => __DIR__ . '/tests/phpunit/PagerTest.php', 'Flow\\Tests\\Parsoid\\BadImageRemoverTest' => __DIR__ . '/tests/phpunit/Parsoid/Fixer/BadImageRemoverTest.php', 'Flow\\Tests\\Parsoid\\Fixer\\MethodReturnsConstraint' => __DIR__ . '/tests/phpunit/Parsoid/Fixer/RedlinkerTest.php', 'Flow\\Tests\\Parsoid\\Fixer\\RedlinkerTest' => __DIR__ . '/tests/phpunit/Parsoid/Fixer/RedlinkerTest.php', 'Flow\\Tests\\Parsoid\\ParsoidUtilsTest' => __DIR__ . '/tests/phpunit/Parsoid/UtilsTest.php', 'Flow\\Tests\\Parsoid\\ReferenceExtractorTestCase' => __DIR__ . '/tests/phpunit/Parsoid/ReferenceExtractorTest.php', 'Flow\\Tests\\Parsoid\\ReferenceFactoryTest' => __DIR__ . '/tests/phpunit/Parsoid/ReferenceFactoryTest.php', 'Flow\\Tests\\PermissionsTest' => __DIR__ . '/tests/phpunit/PermissionsTest.php', 'Flow\\Tests\\PostRevisionTestCase' => __DIR__ . '/tests/phpunit/PostRevisionTestCase.php', 'Flow\\Tests\\Repository\\TreeRepositoryTest' => __DIR__ . '/tests/phpunit/Repository/TreeRepositoryTest.php', 'Flow\\Tests\\Repository\\TreeRepositorydbTest' => __DIR__ . '/tests/phpunit/Repository/TreeRepositoryDbTest.php', 'Flow\\Tests\\SpamFilter\\AbuseFilterTest' => __DIR__ . '/tests/phpunit/SpamFilter/AbuseFilterTest.php', 'Flow\\Tests\\SpamFilter\\ConfirmEditTest' => __DIR__ . '/tests/phpunit/SpamFilter/ConfirmEditTest.php', 'Flow\\Tests\\SpamFilter\\ContentLengthFilterTest' => __DIR__ . '/tests/phpunit/SpamFilter/ContentLengthFilterTest.php', 'Flow\\Tests\\SpamFilter\\SpamBlacklistTest' => __DIR__ . '/tests/phpunit/SpamFilter/SpamBlacklistTest.php', 'Flow\\Tests\\SpamFilter\\SpamRegexTest' => __DIR__ . '/tests/phpunit/SpamFilter/SpamRegexTest.php', 'Flow\\Tests\\TemplateHelperTest' => __DIR__ . '/tests/phpunit/TemplateHelperTest.php', 'Flow\\Tests\\TemplatingTest' => __DIR__ . '/tests/phpunit/TemplatingTest.php', 'Flow\\Tests\\UrlGeneratorTest' => __DIR__ . '/tests/phpunit/UrlGeneratorTest.php', 'Flow\\Tests\\WatchedTopicItemTest' => __DIR__ . '/tests/phpunit/WatchedTopicItemsTest.php', 'Flow\\UrlGenerator' => __DIR__ . '/includes/UrlGenerator.php', 'Flow\\Utils\\NamespaceIterator' => __DIR__ . '/includes/Utils/NamespaceIterator.php', 'Flow\\Utils\\PagesWithPropertyIterator' => __DIR__ . '/includes/Utils/PagesWithPropertyIterator.php', 'Flow\\View' => __DIR__ . '/includes/View.php', 'Flow\\WatchedTopicItems' => __DIR__ . '/includes/WatchedTopicItems.php', 'Flow\\WorkflowLoader' => __DIR__ . '/includes/WorkflowLoader.php', 'Flow\\WorkflowLoaderFactory' => __DIR__ . '/includes/WorkflowLoaderFactory.php', 'MaintenanceDebugLogger' => __DIR__ . '/maintenance/MaintenanceDebugLogger.php', 'Pimple' => __DIR__ . '/vendor/Pimple.php', ); diff --git a/container.php b/container.php index a3404c8151..e4a6dcd46b 100644 --- a/container.php +++ b/container.php @@ -1,1154 +1,1163 @@ share( function( $c ) { global $wgFlowActions; return new Flow\FlowActions( $wgFlowActions ); } ); // Always returns the correct database for flow storage $c['db.factory'] = $c->share( function( $c ) { global $wgFlowDefaultWikiDb, $wgFlowCluster; return new Flow\DbFactory( $wgFlowDefaultWikiDb, $wgFlowCluster ); } ); // Database Access Layer external from main implementation $c['repository.tree'] = $c->share( function( $c ) { global $wgFlowCacheTime; return new Flow\Repository\TreeRepository( $c['db.factory'], $c['memcache.buffered'] ); } ); $c['url_generator'] = $c->share( function( $c ) { return new Flow\UrlGenerator(); } ); // listener is attached to storage.workflow, it // notifies the url generator about all loaded workflows. $c['listener.url_generator'] = $c->share( function( $c ) { return new Flow\Data\Listener\UrlGenerationListener( $c['url_generator'] ); } ); $c['watched_items'] = $c->share( function( $c ) { return new Flow\WatchedTopicItems( $c['user'], wfGetDB( DB_SLAVE, 'watchlist' ) ); } ); $c['link_batch'] = $c->share( function() { return new LinkBatch; } ); $c['redlinker'] = $c->share( function( $c ) { return new Flow\Parsoid\Fixer\Redlinker( $c['link_batch'] ); } ); $c['bad_image_remover'] = $c->share( function( $c ) { return new Flow\Parsoid\Fixer\BadImageRemover( 'wfIsBadImage' ); } ); $c['content_fixer'] = $c->share( function( $c ) { return new Flow\Parsoid\ContentFixer( $c['redlinker'], $c['bad_image_remover'] ); } ); $c['permissions'] = $c->share( function( $c ) { return new Flow\RevisionActionPermissions( $c['flow_actions'], $c['user'] ); } ); $c['lightncandy.template_dir'] = __DIR__ . '/handlebars'; $c['lightncandy'] = $c->share( function( $c ) { global $wgFlowServerCompileTemplates; return new Flow\TemplateHelper( $c['lightncandy.template_dir'], $wgFlowServerCompileTemplates ); } ); $c['templating'] = $c->share( 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\PostRevisionStorage; use Flow\Data\Storage\HeaderRevisionStorage; use Flow\Data\Storage\PostSummaryRevisionStorage; use Flow\Data\Storage\TopicHistoryStorage; use Flow\Data\Index\UniqueFeatureIndex; use Flow\Data\Index\TopKIndex; use Flow\Data\Index\TopicHistoryIndex; use Flow\Data\Storage\BoardHistoryStorage; use Flow\Data\Index\BoardHistoryIndex; use Flow\Data\ObjectManager; use Flow\Data\ObjectLocator; use Flow\Model\Header; use Flow\Model\PostRevision; use Flow\Model\PostSummary; $c['memcache.buffered'] = $c->share( function( $c ) { global $wgFlowCacheTime; // This is the real buffered cached that will allow transactional-like cache $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 ); } ); // Batched username loader $c['repository.username.query'] = $c->share( function( $c ) { return new Flow\Repository\UserName\TwoStepUserNameQuery( $c['db.factory'] ); } ); $c['repository.username'] = $c->share( function( $c ) { return new Flow\Repository\UserNameBatch( $c['repository.username.query'] ); } ); $c['collection.cache'] = $c->share( 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.backend'] = $c->share( function( $c ) { return new BasicDbStorage( $c['db.factory'], $c['storage.workflow.table'], $c['storage.workflow.primary_key'] ); } ); $c['storage.workflow.mapper'] = $c->share( function( $c ) { return CachingObjectMapper::model( $c['storage.workflow.class'], $c['storage.workflow.primary_key'] ); } ); $c['storage.workflow.indexes.primary'] = $c->share( function( $c ) { return new UniqueFeatureIndex( $c['memcache.buffered'], $c['storage.workflow.backend'], 'flow_workflow:v2:pk', $c['storage.workflow.primary_key'] ); } ); $c['storage.workflow.indexes.title_lookup'] = $c->share( function( $c ) { return new TopKIndex( $c['memcache.buffered'], $c['storage.workflow.backend'], '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'] = $c->share( 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( $c['listener.occupation'], $c['listener.url_generator'], $c['storage.workflow.listeners.topiclist'], ); }; $c['storage.workflow'] = $c->share( function( $c ) { return new ObjectManager( $c['storage.workflow.mapper'], $c['storage.workflow.backend'], $c['storage.workflow.indexes'], $c['storage.workflow.listeners'] ); } ); $c['listener.recentchanges'] = $c->share( function( $c ) { global $wgContLang; // 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.occupation'] = $c->share( function( $c ) { global $wgFlowDefaultWorkflow; return new Flow\Data\Listener\OccupationListener( $c['occupation_controller'], $c['deferred_queue'], $wgFlowDefaultWorkflow ); } ); $c['storage.board_history.backend'] = $c->share( function( $c ) { return new BoardHistoryStorage( $c['db.factory'] ); } ); $c['storage.board_history.indexes.primary'] = $c->share( function( $c ) { return new BoardHistoryIndex( $c['memcache.buffered'], // backend storage $c['storage.board_history.backend'], // key prefix 'flow_revision:topic_list_history', // primary key array( 'topic_list_id' ), // index options array( 'limit' => 500, 'sort' => 'rev_id', 'order' => 'DESC' ), $c['storage.topic_list'] ); } ); $c['storage.board_history.mapper'] = $c->share( function( $c ) { return new BasicObjectMapper( function( $rev ) use( $c ) { if ( $rev instanceof PostRevision ) { return $c['storage.post.mapper']->toStorageRow( $rev ); } elseif ( $rev instanceof Header ) { return $c['storage.header.mapper']->toStorageRow( $rev ); } elseif ( $rev instanceof PostSummary ) { return $c['storage.post_summary.mapper']->toStorageRow( $rev ); } else { throw new \Flow\Exception\InvalidDataException( 'Invalid class for board history entry: ' . get_class( $rev ), 'fail-load-data' ); } }, function( array $row, $obj = null ) use( $c ) { if ( $row['rev_type'] === 'header' ) { return $c['storage.header.mapper']->fromStorageRow( $row, $obj ); } elseif ( $row['rev_type'] === 'post' ) { return $c['storage.post.mapper']->fromStorageRow( $row, $obj ); } elseif ( $row['rev_type'] === 'post-summary' ) { return $c['storage.post_summary.mapper']->fromStorageRow( $row, $obj ); } else { throw new \Flow\Exception\InvalidDataException( 'Invalid rev_type for board history entry: ' . $row['rev_type'], 'fail-load-data' ); } } ); } ); $c['storage.board_history.indexes'] = function( $c ) { return array( $c['storage.board_history.indexes.primary'] ); }; $c['storage.board_history'] = $c->share( function( $c ) { return new ObjectLocator( $c['storage.board_history.mapper'], $c['storage.board_history.backend'], $c['storage.board_history.indexes'] ); } ); $c['storage.header.listeners.username'] = $c->share( 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'] = $c->share( function( $c ) { return array( $c['reference.recorder'], $c['storage.board_history.indexes.primary'], $c['storage.header.listeners.username'], $c['listener.recentchanges'], $c['listener.editcount'], ); } ); $c['storage.header.primary_key'] = array( 'rev_id' ); $c['storage.header.mapper'] = $c->share( function( $c ) { return CachingObjectMapper::model( 'Flow\\Model\\Header', array( 'rev_id' ) ); } ); $c['storage.header.backend'] = $c->share( function( $c ) { global $wgFlowExternalStore; return new HeaderRevisionStorage( $c['db.factory'], $wgFlowExternalStore ); } ); $c['storage.header.indexes.primary'] = $c->share( function( $c ) { return new UniqueFeatureIndex( $c['memcache.buffered'], $c['storage.header.backend'], 'flow_header:v2:pk', $c['storage.header.primary_key'] ); } ); $c['storage.header.indexes.topic_lookup'] = $c->share( function( $c ) { return new TopKIndex( $c['memcache.buffered'], $c['storage.header.backend'], 'flow_header:workflow', array( 'rev_type_id' ), array( 'limit' => 100, '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.topic_lookup'] ); }; $c['storage.header'] = $c->share( function( $c ) { return new ObjectManager( $c['storage.header.mapper'], $c['storage.header.backend'], $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'] = $c->share( function( $c ) { return CachingObjectMapper::model( $c['storage.post_summary.class'], $c['storage.post_summary.primary_key'] ); } ); $c['storage.post_summary.listeners.username'] = $c->share( 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( $c['listener.recentchanges'], $c['storage.post_summary.listeners.username'], $c['storage.board_history.indexes.primary'], $c['listener.editcount'], // topic history -- to keep a history by topic we have to know what topic every post // belongs to, not just its parent. TopicHistoryIndex is a slight tweak to TopKIndex // using TreeRepository for extra information and stuffing it into topic_root while indexing $c['storage.topic_history.indexes.primary'], + $c['reference.recorder'], ); }; $c['storage.post_summary.backend'] = $c->share( function( $c ) { global $wgFlowExternalStore; return new PostSummaryRevisionStorage( $c['db.factory'], $wgFlowExternalStore ); } ); $c['storage.post_summary.indexes.primary'] = $c->share( function( $c ) { return new UniqueFeatureIndex( $c['memcache.buffered'], $c['storage.post_summary.backend'], 'flow_post_summary:v2:pk', $c['storage.post_summary.primary_key'] ); } ); $c['storage.post_summary.indexes.topic_lookup'] = $c->share( function( $c ) { return new TopKIndex( $c['memcache.buffered'], $c['storage.post_summary.backend'], 'flow_post_summary:workflow', array( 'rev_type_id' ), array( 'limit' => 100, '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'] = $c->share( function( $c ) { return new ObjectManager( $c['storage.post_summary.mapper'], $c['storage.post_summary.backend'], $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'] = $c->share( function( $c ) { return new TopicListLastUpdatedStorage( $c['db.factory'], $c['storage.topic_list.table'], $c['storage.topic_list.primary_key'] ); } ); $c['storage.topic_list.mapper'] = $c->share( function( $c ) { return CachingObjectMapper::model( $c['storage.topic_list.class'], $c['storage.topic_list.primary_key'] ); } ); $c['storage.topic_list.backend'] = $c->share( 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'] = $c->share( function( $c ) { return new UniqueFeatureIndex( $c['memcache.buffered'], $c['storage.topic_list.backend'], 'flow_topic_list:topic', array( 'topic_id' ) ); } ); // Lookup from board to contained topics $c['storage.topic_list.indexes.reverse_lookup'] = $c->share( function( $c ) { return new TopKIndex( $c['memcache.buffered'], $c['storage.topic_list.backend'], 'flow_topic_list:list', array( 'topic_list_id' ), array( 'sort' => 'topic_id' ) ); } ); $c['storage.topic_list.indexes.last_updated'] = $c->share( function( $c ) { return new TopKIndex( $c['memcache.buffered'], $c['storage.topic_list.indexes.last_updated.backend'], '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'] = $c->share( function( $c ) { return new ObjectManager( $c['storage.topic_list.mapper'], $c['storage.topic_list.backend'], $c['storage.topic_list.indexes'] ); } ); $c['storage.post.class'] = 'Flow\Model\PostRevision'; $c['storage.post.primary_key'] = array( 'rev_id' ); $c['storage.post.mapper'] = $c->share( function( $c ) { return CachingObjectMapper::model( $c['storage.post.class'], $c['storage.post.primary_key'] ); } ); $c['storage.post.backend'] = $c->share( function( $c ) { global $wgFlowExternalStore; return new PostRevisionStorage( $c['db.factory'], $wgFlowExternalStore, $c['repository.tree'] ); } ); $c['storage.post.listeners.moderation_logger'] = $c->share( function( $c ) { return new Flow\Log\PostModerationLogger( $c['logger'] ); } ); $c['storage.post.listeners.username'] = $c->share( 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'] = $c->share( 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.notification'] = $c->share( function( $c ) { // Defer notifications triggering till end of request so we could get // article_id in the case of a new topic, this will need support of // adding deferred update when running deferred update return new Flow\Data\Listener\DeferredInsertLifecycleHandler( $c['deferred_queue'], new Flow\Data\Listener\NotificationListener( $c['controller.notification'] ) ); } ); $c['storage.post.listeners'] = function( $c ) { return array( $c['reference.recorder'], $c['collection.cache'], $c['storage.post.listeners.username'], $c['storage.post.listeners.watch_topic'], $c['storage.post.listeners.notification'], $c['listener.recentchanges'], $c['listener.editcount'], // topic history -- to keep a history by topic we have to know what topic every post // belongs to, not just its parent. TopicHistoryIndex is a slight tweak to TopKIndex // using TreeRepository for extra information and stuffing it into topic_root while indexing $c['storage.board_history.indexes.primary'], $c['storage.topic_history.indexes.primary'], ); }; $c['storage.post.indexes.primary'] = $c->share( function( $c ) { return new UniqueFeatureIndex( $c['memcache.buffered'], $c['storage.post.backend'], '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'] = $c->share( function( $c ) { return new TopKIndex( $c['memcache.buffered'], $c['storage.post.backend'], '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'] = $c->share( function( $c ) { return new ObjectManager( $c['storage.post.mapper'], $c['storage.post.backend'], $c['storage.post.indexes'], $c['storage.post.listeners'] ); } ); $c['storage.topic_history.primary_key'] = array( 'rev_id' ); $c['storage.topic_history.backend'] = $c->share( function( $c ) { global $wgFlowExternalStore; return new TopicHistoryStorage( new PostRevisionStorage( $c['db.factory'], $wgFlowExternalStore, $c['repository.tree'] ), new PostSummaryRevisionStorage( $c['db.factory'], $wgFlowExternalStore ) ); } ); $c['storage.topic_history.indexes.primary'] = $c->share( function( $c ) { return new UniqueFeatureIndex( $c['memcache.buffered'], $c['storage.topic_history.backend'], 'flow_revision:v4:pk', $c['storage.topic_history.primary_key'] ); } ); $c['storage.topic_history.indexes.topic_lookup'] = $c->share( function( $c ) { return new TopicHistoryIndex( $c['memcache.buffered'], $c['storage.topic_history.backend'], $c['repository.tree'], 'flow_revision:topic', array( 'topic_root_id' ), array( 'limit' => 500, 'sort' => 'rev_id', 'order' => 'DESC', 'shallow' => $c['storage.topic_history.indexes.primary'], 'create' => function( array $row ) { // only create new indexes for post revisions if ( $row['rev_type'] !== 'post' ) { return false; } // if the post has no parent and the revision has no parent // then this is a brand new topic title return $row['tree_parent_id'] === null && $row['rev_parent_id'] === null; }, ) ); } ); $c['storage.topic_history.indexes'] = function( $c ) { return array( $c['storage.topic_history.indexes.primary'], $c['storage.topic_history.indexes.topic_lookup'], ); }; $c['storage.topic_history.mapper'] = $c->share( function( $c ) { return new BasicObjectMapper( function( $rev ) use( $c ) { if ( $rev instanceof PostRevision ) { return $c['storage.post.mapper']->toStorageRow( $rev ); } elseif ( $rev instanceof PostSummary ) { return $c['storage.post_summary.mapper']->toStorageRow( $rev ); } else { throw new \Flow\Exception\InvalidDataException( 'Invalid class for board history entry: ' . get_class( $rev ), 'fail-load-data' ); } }, function( array $row, $obj = null ) use( $c ) { if ( $row['rev_type'] === 'post' ) { return $c['storage.post.mapper']->fromStorageRow( $row, $obj ); } elseif ( $row['rev_type'] === 'post-summary' ) { return $c['storage.post_summary.mapper']->fromStorageRow( $row, $obj ); } else { throw new \Flow\Exception\InvalidDataException( 'Invalid rev_type for board history entry: ' . $row['rev_type'], 'fail-load-data' ); } } ); } ); $c['storage.topic_history'] = $c->share( function( $c ) { return new ObjectLocator( $c['storage.topic_history.mapper'], $c['storage.topic_history.backend'], $c['storage.topic_history.indexes'] ); } ); $c['storage.manager_list'] = $c->share( function( $c ) { return array( 'Flow\\Model\\Workflow' => 'storage.workflow', 'Workflow' => 'storage.workflow', 'Flow\\Model\\PostRevision' => 'storage.post', 'PostRevision' => 'storage.post', 'Flow\\Model\\PostSummary' => 'storage.post_summary', 'PostSummary' => 'storage.post_summary', 'Flow\\Model\\TopicListEntry' => 'storage.topic_list', 'TopicListEntry' => 'storage.topic_list', 'Flow\\Model\\Header' => 'storage.header', 'Header' => 'storage.header', 'BoardHistoryEntry' => 'storage.board_history', 'TopicHistoryEntry' => 'storage.topic_history', 'Flow\\Model\\WikiReference' => 'storage.wiki_reference', 'WikiReference' => 'storage.wiki_reference', 'Flow\\Model\\URLReference' => 'storage.url_reference', 'URLReference' => 'storage.url_reference', ); } ); $c['storage'] = $c->share( function( $c ) { return new \Flow\Data\ManagerGroup( $c, $c['storage.manager_list'] ); } ); $c['loader.root_post'] = $c->share( 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'] = $c->share( function( $c ) { return new SplQueue; } ); $c['submission_handler'] = $c->share( function( $c ) { return new Flow\SubmissionHandler( $c['storage'], $c['db.factory'], $c['memcache.buffered'], $c['deferred_queue'] ); } ); $c['factory.block'] = $c->share( function( $c ) { return new Flow\BlockFactory( $c['storage'], $c['loader.root_post'] ); } ); $c['factory.loader.workflow'] = $c->share( function( $c ) { global $wgFlowDefaultWorkflow; return new Flow\WorkflowLoaderFactory( $c['storage'], $c['factory.block'], $c['submission_handler'], $wgFlowDefaultWorkflow ); } ); // 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['occupation_controller'] = FlowHooks::getOccupationController(); $c['controller.notification'] = $c->share( function( $c ) { global $wgContLang; return new Flow\NotificationController( $wgContLang ); } ); // 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'] = $c->share( function( $c ) { return new Flow\SpamFilter\SpamRegex; } ); $c['controller.spamblacklist'] = $c->share( function( $c ) { return new Flow\SpamFilter\SpamBlacklist; } ); $c['controller.confirmedit'] = $c->share( function( $c ) { return new Flow\SpamFilter\ConfirmEdit; } ); $c['controller.contentlength'] = $c->share( function( $c ) { return new Flow\SpamFilter\ContentLengthFilter; } ); $c['controller.spamfilter'] = $c->share( function( $c ) { return new Flow\SpamFilter\Controller( $c['controller.spamregex'], $c['controller.spamblacklist'], $c['controller.abusefilter'], $c['controller.confirmedit'], $c['controller.contentlength'] ); } ); $c['query.singlepost'] = $c->share( function( $c ) { return new Flow\Formatter\SinglePostQuery( $c['storage'], $c['repository.tree'] ); } ); $c['query.checkuser'] = $c->share( function( $c ) { return new Flow\Formatter\CheckUserQuery( $c['storage'], $c['repository.tree'] ); } ); $c['formatter.irclineurl'] = $c->share( function( $c ) { return new Flow\Formatter\IRCLineUrlFormatter( $c['permissions'], $c['formatter.revision'] ); } ); $c['formatter.checkuser'] = $c->share( function( $c ) { return new Flow\Formatter\CheckUserFormatter( $c['permissions'], $c['formatter.revision'] ); } ); $c['formatter.revisionview'] = $c->share( function( $c ) { return new Flow\Formatter\RevisionViewFormatter( $c['url_generator'], $c['formatter.revision'] ); } ); $c['formatter.revision.diff.view'] = $c->share( function( $c ) { return new Flow\Formatter\RevisionDiffViewFormatter( $c['formatter.revisionview'] ); } ); $c['query.topiclist'] = $c->share( function( $c ) { return new Flow\Formatter\TopicListQuery( $c['storage'], $c['repository.tree'], $c['permissions'], $c['watched_items'] ); } ); $c['query.topic.history'] = $c->share( function( $c ) { return new Flow\Formatter\TopicHistoryQuery( $c['storage'], $c['repository.tree'] ); } ); $c['query.post.history'] = $c->share( function( $c ) { return new Flow\Formatter\PostHistoryQuery( $c['storage'], $c['repository.tree'] ); } ); $c['query.recentchanges'] = $c->share( function( $c ) { $query = new Flow\Formatter\RecentChangesQuery( $c['storage'], $c['repository.tree'], $c['flow_actions'] ); $query->setExtendWatchlist( $c['user']->getOption( 'extendwatchlist' ) ); return $query; } ); $c['query.postsummary'] = $c->share( function( $c ) { return new Flow\Formatter\PostSummaryQuery( $c['storage'], $c['repository.tree'], $c['flow_actions'] ); } ); $c['query.header.view'] = $c->share( function( $c ) { return new Flow\Formatter\HeaderViewQuery( $c['storage'], $c['repository.tree'] ); } ); $c['query.post.view'] = $c->share( function( $c ) { return new Flow\Formatter\PostViewQuery( $c['storage'], $c['repository.tree'] ); } ); $c['query.postsummary.view'] = $c->share( function( $c ) { return new Flow\Formatter\PostSummaryViewQuery( $c['storage'], $c['repository.tree'] ); } ); $c['formatter.recentchanges'] = $c->share( function( $c ) { return new Flow\Formatter\RecentChanges( $c['permissions'], $c['formatter.revision'] ); } ); $c['query.contributions'] = $c->share( function( $c ) { return new Flow\Formatter\ContributionsQuery( $c['storage'], $c['repository.tree'], $c['memcache'], $c['db.factory'] ); } ); $c['formatter.contributions'] = $c->share( function( $c ) { return new Flow\Formatter\Contributions( $c['permissions'], $c['formatter.revision'] ); } ); $c['formatter.contributions.feeditem'] = $c->share( function( $c ) { return new Flow\Formatter\FeedItemFormatter( $c['permissions'], $c['formatter.revision'] ); } ); $c['query.board-history'] = $c->share( function( $c ) { return new Flow\Formatter\BoardHistoryQuery( $c['storage'], $c['repository.tree'] ); } ); // 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'] = function( $c ) { global $wgFlowMaxThreadingDepth; return new Flow\Formatter\RevisionFormatter( $c['permissions'], $c['templating'], $c['repository.username'], $wgFlowMaxThreadingDepth ); }; $c['formatter.topiclist'] = $c->share( function( $c ) { return new Flow\Formatter\TopicListFormatter( $c['url_generator'], $c['formatter.revision'] ); } ); $c['formatter.topiclist.toc'] = $c->share( function ( $c ) { return new Flow\Formatter\TocTopicListFormatter( $c['templating'] ); } ); $c['formatter.topic'] = $c->share( function( $c ) { return new Flow\Formatter\TopicFormatter( $c['url_generator'], $c['formatter.revision'] ); } ); $c['logger'] = $c->share( function( $c ) { return new Flow\Log\Logger( $c['flow_actions'], $c['user'] ); } ); -$c['reference.extractor'] = $c->share( function( $c ) { - return new Flow\Parsoid\ReferenceExtractor( - 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, - ) - ); -} ); - $c['storage.wiki_reference.class'] = 'Flow\Model\WikiReference'; $c['storage.wiki_reference.table'] = 'flow_wiki_ref'; $c['storage.wiki_reference.primary_key'] = array( 'ref_src_namespace', 'ref_src_title', 'ref_src_object_id', 'ref_type', 'ref_target_namespace', 'ref_target_title' ); $c['storage.wiki_reference.mapper'] = $c->share( function( $c ) { return Flow\Data\Mapper\BasicObjectMapper::model( $c['storage.wiki_reference.class'] ); } ); $c['storage.wiki_reference.backend'] = $c->share( 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'] = $c->share( function( $c ) { return new TopKIndex( $c['memcache.buffered'], $c['storage.wiki_reference.backend'], 'flow_ref:wiki:by-source', array( 'ref_src_namespace', 'ref_src_title', ), array( 'order' => 'ASC', 'sort' => 'ref_src_object_id', ) ); } ); $c['storage.wiki_reference.indexes.revision_lookup'] = $c->share( function( $c ) { return new TopKIndex( $c['memcache.buffered'], $c['storage.wiki_reference.backend'], 'flow_ref:wiki:by-revision:v2', array( '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'] = $c->share( function( $c ) { return new ObjectManager( $c['storage.wiki_reference.mapper'], $c['storage.wiki_reference.backend'], $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'] = array( 'ref_src_namespace', 'ref_src_title', 'ref_src_object_id', 'ref_type', 'ref_target' ); $c['storage.url_reference.mapper'] = $c->share( function( $c ) { return Flow\Data\Mapper\BasicObjectMapper::model( $c['storage.url_reference.class'] ); } ); $c['storage.url_reference.backend'] = $c->share( 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.revision_lookup'] = $c->share( function( $c ) { return new TopKIndex( $c['memcache.buffered'], $c['storage.url_reference.backend'], 'flow_ref:url:by-source', array( 'ref_src_namespace', 'ref_src_title', ), array( 'order' => 'ASC', 'sort' => 'ref_src_object_id', ) ); } ); $c['storage.url_reference.indexes.source_lookup'] = $c->share( function( $c ) { return new TopKIndex( $c['memcache.buffered'], $c['storage.url_reference.backend'], 'flow_ref:url:by-revision:v2', array( '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'] = $c->share( function( $c ) { return new ObjectManager( $c['storage.url_reference.mapper'], $c['storage.url_reference.backend'], $c['storage.url_reference.indexes'], array() ); } ); $c['reference.updater.links-tables'] = $c->share( function( $c ) { return new Flow\LinksTableUpdater( $c['storage'] ); } ); $c['reference.clarifier'] = $c->share( function( $c ) { return new Flow\ReferenceClarifier( $c['storage'], $c['url_generator'] ); } ); +$c['reference.extractor'] = $c->share( 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'] = $c->share( function( $c ) { return new Flow\Data\Listener\ReferenceRecorder( $c['reference.extractor'], $c['reference.updater.links-tables'], $c['storage'] ); } ); $c['user_merger'] = $c->share( function( $c ) { return new Flow\Data\Utils\UserMerger( $c['db.factory'], $c['storage'] ); } ); $c['importer'] = $c->share( function( $c ) { $importer = new Flow\Import\Importer( $c['storage'], $c['factory.loader.workflow'], $c['memcache.buffered'], $c['db.factory'], $c['deferred_queue'] ); $importer->addPostprocessor( new Flow\Import\Postprocessor\SpecialLogTopic( $c['occupation_controller']->getTalkpageManager() ) ); return $importer; } ); $c['listener.editcount'] = $c->share( function( $c ) { return new \Flow\Data\Listener\EditCountListener( $c['flow_actions'] ); } ); return $c; diff --git a/includes/LinksTableUpdater.php b/includes/LinksTableUpdater.php index 0886fd7282..9346dff4ff 100644 --- a/includes/LinksTableUpdater.php +++ b/includes/LinksTableUpdater.php @@ -1,128 +1,137 @@ storage = $storage; } public function doUpdate( Workflow $workflow ) { $title = $workflow->getArticleTitle(); $page = WikiPage::factory( $title ); $content = $page->getContent(); if ( $content === null ) { $updates = array(); } else { $updates = $content->getSecondaryDataUpdates( $title ); } DataUpdate::runUpdates( $updates ); } /** * @param Title $title * @param ParserOutput $parserOutput * @param Reference[] $references */ public function mutateParserOutput( Title $title, ParserOutput $parserOutput, $references = null ) { if ( $references === null ) { $references = $this->getReferencesForTitle( $title ); } $linkBatch = new LinkBatch(); /** @var Title[] $internalLinks */ $internalLinks = array(); /** @var Title[] $templates */ $templates = array(); foreach( $references as $reference ) { if ( $reference->getType() === 'link' ) { if ( $reference instanceof URLReference ) { $parserOutput->mExternalLinks[$reference->getURL()] = true; } elseif ( $reference instanceof WikiReference ) { $internalLinks[$reference->getTitle()->getPrefixedDBkey()] = $reference->getTitle(); $linkBatch->addObj( $reference->getTitle() ); } + } elseif ( $reference->getType() === WikiReference::TYPE_CATEGORY ) { + if ( $reference instanceof WikiReference ) { + $title = $reference->getTitle(); + $parserOutput->addCategory( + $title->getDBkey(), + // parsoid moves the sort key into the fragment + $title->getFragment() + ); + } } elseif ( $reference->getType() === 'file' ) { if ( $reference instanceof WikiReference ) { // Only local images supported $parserOutput->mImages[$reference->getTitle()->getDBkey()] = true; } } elseif ( $reference->getType() === 'template' ) { if ( $reference instanceof WikiReference ) { $templates[$reference->getTitle()->getPrefixedDBkey()] = $reference->getTitle(); $linkBatch->addObj( $reference->getTitle() ); } } } $linkBatch->execute(); $linkCache = LinkCache::singleton(); foreach( $internalLinks as $title ) { $ns = $title->getNamespace(); $dbk = $title->getDBkey(); if ( !isset( $parserOutput->mLinks[$ns] ) ) { $parserOutput->mLinks[$ns] = array(); } $id = $linkCache->getGoodLinkID( $title->getPrefixedDBkey() ); $parserOutput->mLinks[$ns][$dbk] = $id; } foreach( $templates as $title ) { $ns = $title->getNamespace(); $dbk = $title->getDBkey(); if ( !isset( $parserOutput->mTemplates[$ns] ) ) { $parserOutput->mTemplates[$ns] = array(); } $id = $linkCache->getGoodLinkID( $title->getPrefixedDBkey() ); $parserOutput->mTemplates[$ns][$dbk] = $id; } } public function getReferencesForTitle( Title $title ) { $wikiReferences = $this->storage->find( 'WikiReference', array( 'ref_src_namespace' => $title->getNamespace(), 'ref_src_title' => $title->getDBkey(), ) ); $urlReferences = $this->storage->find( 'URLReference', array( 'ref_src_namespace' => $title->getNamespace(), 'ref_src_title' => $title->getDBkey(), ) ); // let's make sure the merge doesn't fail when nothing was found $wikiReferences = $wikiReferences ?: array(); $urlReferences = $urlReferences ?: array(); return array_merge( $wikiReferences, $urlReferences ); } } diff --git a/includes/Model/WikiReference.php b/includes/Model/WikiReference.php index 8dcf090729..43c4f08657 100644 --- a/includes/Model/WikiReference.php +++ b/includes/Model/WikiReference.php @@ -1,93 +1,95 @@ target = $targetTitle; $this->validTypes = array_merge( $this->validTypes, array( self::TYPE_FILE, self::TYPE_TEMPLATE, + self::TYPE_CATEGORY, ) ); parent::__construct( $srcWorkflow, $srcTitle, $objectType, $objectId, $type ); } /** * Gets the storage row for this WikiReference * * @return array */ public function getStorageRow() { return parent::getStorageRow() + array( 'ref_target_namespace' => $this->target->getNamespace(), 'ref_target_title' => $this->target->getDBkey(), ); } /** * Instantiates a WikiReference object from a storage row. * * @param \StdClass $row * @return WikiReference */ public static function fromStorageRow( $row ) { $workflow = UUID::create( $row['ref_src_workflow_id'] ); $objectType = $row['ref_src_object_type']; $objectId = UUID::create( $row['ref_src_object_id'] ); $srcTitle = self::makeTitle( $row['ref_src_namespace'], $row['ref_src_title'] ); $targetTitle = self::makeTitle( $row['ref_target_namespace'], $row['ref_target_title'] ); $type = $row['ref_type']; return new WikiReference( $workflow, $srcTitle, $objectType, $objectId, $type, $targetTitle ); } /** * Gets the storage row from an object. * Helper for BasicObjectMapper. */ public static function toStorageRow( WikiReference $object ) { return $object->getStorageRow(); } /** * Many loaded references typically point to the same Title, cache those instead * of generating a bunch of duplicate title classes. */ public static function makeTitle( $namespace, $title ) { try { return Workflow::getFromTitleCache( wfWikiId(), $namespace, $title ); } catch ( InvalidInputException $e ) { // duplicate Title::makeTitleSafe which returns null on failure, // but only for InvalidInputException return null; } } public function getTitle() { return $this->target; } public function getTargetIdentifier() { return 'title:' . $this->getTitle()->getPrefixedDBKey(); } } diff --git a/includes/Parsoid/Extractor/CategoryExtractor.php b/includes/Parsoid/Extractor/CategoryExtractor.php new file mode 100644 index 0000000000..8b0a0d3078 --- /dev/null +++ b/includes/Parsoid/Extractor/CategoryExtractor.php @@ -0,0 +1,52 @@ + + * + * Flow does not currently handle the other page properties. When it becomes + * necessary a more generic page property extractor should be implemented and + * this class should be removed. + */ +class CategoryExtractor implements Extractor { + /** + * {@inheritDoc} + */ + public function getXPath() { + return '//link[starts-with( @rel, "mw:PageProp/Category" )]'; + } + + /** + * {@inheritDoc} + */ + public function perform( ReferenceFactory $factory, DOMElement $element ) { + // our provided xpath guarantees there is a rel attribute + // with our expected format so only perform a very minimal + // validation. + $rel = $element->getAttribute( 'rel' ); + if ( $rel !== 'mw:PageProp/Category' ) { + return null; + } + + $href = $element->getAttribute( 'href' ); + if ( $href ) { + return $factory->createWikiReference( + WikiReference::TYPE_CATEGORY, + urldecode( $href ) + ); + } else { + return null; + } + } +} diff --git a/includes/Parsoid/ReferenceExtractor.php b/includes/Parsoid/ReferenceExtractor.php index 7b71f65045..dc5af8cfe0 100644 --- a/includes/Parsoid/ReferenceExtractor.php +++ b/includes/Parsoid/ReferenceExtractor.php @@ -1,87 +1,96 @@ extractors = $extractors; } /** * @param Workflow $workflow * @param string $objectType * @param UUID $objectId * @param string $text * @return array */ public function getReferences( Workflow $workflow, $objectType, UUID $objectId, $text ) { - return $this->extractReferences( - new ReferenceFactory( $workflow, $objectType, $objectId ), - $text - ); + if ( isset( $this->extractors[$objectType] ) ) { + return $this->extractReferences( + new ReferenceFactory( $workflow, $objectType, $objectId ), + $this->extractors[$objectType], + $text + ); + } else { + throw new \Exception( "No extractors available for $objectType" ); + return array(); + } } /** * @param ReferenceFactory $factory + * @param Extractor[] $extractors * @param string $text * @return Reference[] * @throws MWException * @throws \Flow\Exception\WikitextException */ - protected function extractReferences( ReferenceFactory $factory, $text ) { + protected function extractReferences( ReferenceFactory $factory, array $extractors, $text ) { $dom = Utils::createDOM( '' . $text ); $output = array(); $xpath = new DOMXPath( $dom ); - foreach( $this->extractors as $extractor ) { + foreach( $extractors as $extractor ) { $elements = $xpath->query( $extractor->getXPath() ); if ( !$elements ) { $class = get_class( $extractor ); throw new MWException( "Malformed xpath from $class: " . $extractor->getXPath() ); } foreach( $elements as $element ) { try { $ref = $extractor->perform( $factory, $element ); } catch ( InvalidReferenceException $e ) { wfDebugLog( 'Flow', 'Invalid reference detected, skipping element' ); $ref = null; } // no reference was generated if ( $ref === null ) { continue; } // reference points to a special page if ( $ref->getSrcTitle()->isSpecialPage() ) { continue; } $output[] = $ref; } } return $output; } } diff --git a/includes/ReferenceClarifier.php b/includes/ReferenceClarifier.php index fb199ffd3c..1fe339f8b8 100644 --- a/includes/ReferenceClarifier.php +++ b/includes/ReferenceClarifier.php @@ -1,124 +1,129 @@ storage = $storage; $this->urlGenerator = $urlGenerator; $this->referenceCache = array(); } public function getWhatLinksHereProps( $row, Title $from, Title $to ) { $ids = array(); $props = array(); $references = $this->getWikiReferences( $from, $to ); // Collect referenced workflow ids and load them so we can generate // links to their pages foreach( $references as $reference ) { $id = $reference->getWorkflowId(); // utilize array key to de-duplicate $ids[$id->getAlphadecimal()] = $id; } // Dont need to do anything with them, they are automatically // passed into url generator when loaded. $this->storage->getMulti( 'Workflow', $ids ); // Messages that can be used here: // * flow-whatlinkshere-header // * flow-whatlinkshere-post // Topic and Summary are plain text and do not have links. foreach( $references as $reference ) { + if ( $reference->getType() === WikiReference::TYPE_CATEGORY ) { + // While it might make sense to have backlinks from categories to + // a page in what links here, thats not what mediawiki currently does. + continue; + } try { $url = $this->getObjectLink( $reference->getWorkflowId(), $reference->getObjectType(), $reference->getObjectId() ); $props[] = wfMessage( 'flow-whatlinkshere-' . $reference->getObjectType(), $url )->parse(); } catch ( CrossWikiException $e ) { // Ignore expected cross-wiki exception. // Gerrit 136280 would add a wiki field to the query in // loadReferencesForPage(), we can remove catching the exception // in here once it's merged } } return $props; } /** * @param Title $from * @param Title $to * @return WikiReference[] */ public function getWikiReferences( Title $from, Title $to ) { if ( ! isset( $this->referenceCache[$from->getPrefixedDBkey()] ) ) { $this->loadReferencesForPage( $from ); } $fromT = $from->getPrefixedDBkey(); $toT = 'title:' . $to->getPrefixedDBkey(); return isset( $this->referenceCache[$fromT][$toT] ) ? $this->referenceCache[$fromT][$toT] : array(); } /** * @param UUID $workflow * @param string $objectType * @param UUID $objectId * @return string Full URL */ protected function getObjectLink( UUID $workflow, $objectType, UUID $objectId ) { if ( $objectType === 'post' ) { $anchor = $this->urlGenerator->postLink( null, $workflow, $objectId ); } elseif ( $objectType === 'header' ) { $anchor = $this->urlGenerator->workflowLink( null, $workflow ); } else { wfDebugLog( 'Flow', __METHOD__ . ": Unknown \$objectType: $objectType" ); $anchor = $this->urlGenerator->workflowLink( null, $workflow ); } return $anchor->getFullURL(); } protected function loadReferencesForPage( Title $from ) { /** @var Reference[] $allReferences */ $allReferences = array(); foreach( array( 'WikiReference', 'URLReference' ) as $refType ) { // find() returns null for error or empty result $res = $this->storage->find( $refType, array( 'ref_src_namespace' => $from->getNamespace(), 'ref_src_title' => $from->getDBkey(), ) ); if ( $res ) { $allReferences = array_merge( $allReferences, $res ); } } $cache = array(); foreach( $allReferences as $reference ) { if ( ! isset( $cache[$reference->getTargetIdentifier()] ) ) { $cache[$reference->getTargetIdentifier()] = array(); } $cache[$reference->getTargetIdentifier()][] = $reference; } $this->referenceCache[$from->getPrefixedDBkey()] = $cache; } } diff --git a/includes/View.php b/includes/View.php index 6e610c088d..bcfd9eacc1 100644 --- a/includes/View.php +++ b/includes/View.php @@ -1,263 +1,289 @@ urlGenerator = $urlGenerator; $this->lightncandy = $lightncandy; $this->setContext( $requestContext ); } public function show( WorkflowLoader $loader, $action ) { wfProfileIn( __CLASS__ . '-init' ); $out = $this->getOutput(); $styles = array( 'mediawiki.ui', 'mediawiki.ui.anchor', 'mediawiki.ui.button', 'mediawiki.ui.input', 'mediawiki.ui.text', 'ext.flow.styles', 'ext.flow.mediawiki.ui.tooltips', 'ext.flow.mediawiki.ui.form', 'ext.flow.mediawiki.ui.modal', 'ext.flow.mediawiki.ui.text', 'ext.flow.icons.styles', 'ext.flow.board.styles', 'ext.flow.board.topic.styles' ); $out->addModuleStyles( $styles ); $out->addModules( array( 'ext.flow' ) ); // Allow other extensions to add modules wfRunHooks( 'FlowAddModules', array( $out ) ); $workflow = $loader->getWorkflow(); $title = $workflow->getArticleTitle(); $request = $this->getRequest(); $user = $this->getUser(); $blocks = $loader->getBlocks(); wfProfileOut( __CLASS__ . '-init' ); $parameters = $this->extractBlockParameters( $action, $request, $blocks ); $wasPosted = $request->wasPosted(); if ( $wasPosted ) { wfProfileIn( __CLASS__ . '-submit' ); $blocksToCommit = $loader->handleSubmit( $this, $action, $parameters ); if ( $blocksToCommit ) { if ( !$user->matchEditToken( $request->getVal( 'wpEditToken' ) ) ) { // only render the failed blocks $blocks = $blocksToCommit; foreach ( $blocks as $block ) { $block->addError( 'edit-token', $this->msg( 'sessionfailure' ) ); } } else { $loader->commit( $workflow, $blocksToCommit ); $this->redirect( $workflow, 'view' ); wfProfileOut( __CLASS__ . '-submit' ); return; } } wfProfileOut( __CLASS__ . '-submit' ); } else { foreach ( $blocks as $block ) { $block->init( $this, $action ); } } wfProfileIn( __CLASS__ . '-serialize' ); // @todo This and API should use same code $apiResponse = array( 'title' => $title->getPrefixedText(), 'workflow' => $workflow->isNew() ? '' : $workflow->getId()->getAlphadecimal(), 'blocks' => array(), 'isWatched' => $user->isWatched( $title ), 'watchable' => !$user->isAnon(), 'links' => array( 'watch-board' => array( 'url' => $title->getLocalUrl( 'action=watch' ), ), 'unwatch-board' => array( 'url' => $title->getLocalUrl( 'action=unwatch' ), ), ), ); $editToken = $user->getEditToken(); foreach ( $blocks as $block ) { if ( $wasPosted ? $block->canSubmit( $action ) : $block->canRender( $action ) ) { $apiResponse['blocks'][] = $block->renderApi( $parameters[$block->getName()] ) + array( 'title' => $apiResponse['title'], 'block-action-template' => $block->getTemplate( $action ), 'editToken' => $editToken, ); } } // Please note that all blocks can set page title, which may cause them // to override one another's titles foreach ( $blocks as $block ) { $block->setPageTitle( $this->getOutput() ); } if ( count( $apiResponse['blocks'] ) === 0 ) { throw new InvalidActionException( "No blocks accepted action: $action" ); } array_walk_recursive( $apiResponse, function( &$value ) { if ( $value instanceof Anchor ) { $anchor = $value; $value = $value->toArray(); // TODO: We're looking into another approach for this // using a parser function, so the URL doesn't have to be // fully qualified. // See https://bugzilla.wikimedia.org/show_bug.cgi?id=66746 $value['url'] = $anchor->getFullURL(); } elseif ( $value instanceof Message ) { $value = $value->text(); } elseif ( $value instanceof UUID ) { $value = $value->getAlphadecimal(); } } ); wfProfileOut( __CLASS__ . '-serialize' ); - // Update newtalk and watchlist notification status on view action of any workflow - // since the normal page view that resets notification status is not accessiable - // anymore due to Flow occupation if ( $action === 'view' ) { + // Update newtalk and watchlist notification status on view action of any workflow + // since the normal page view that resets notification status is not accessiable + // anymore due to Flow occupation $user->clearNotification( $title ); + + // attach categories that would be shown on a normal page + $out->addCategoryLinks( $this->getCategories( $title ) ); } /** header( 'Content-Type: application/json; content=utf-8' ); $data = json_encode( $apiResponse ); //return; die( $data ); **/ // Render with lightncandy. The exact template to render // will likely need to vary, but not yet. wfProfileIn( __CLASS__ . '-render' ); // Render the flow-component wrapper if ( !empty( $apiResponse['blocks'] ) ) { $renderedBlocks = array(); foreach ( $apiResponse['blocks'] as $block ) { // @todo find a better way to do this; potentially make all blocks their own components switch ( $block['type'] ) { case 'board-history': $flowComponent = 'boardHistory'; break; default: $flowComponent = 'board'; } // Don't re-render a block type twice in one page if ( isset( $renderedBlocks[$flowComponent] ) ) { continue; } $renderedBlocks[$flowComponent] = true; // Get the block loop template $template = $this->lightncandy->getTemplate( 'flow_block_loop' ); // Output the component, with the rendered blocks inside it $out->addHTML( Html::rawElement( 'div', array( 'class' => 'flow-component', 'data-flow-component' => $flowComponent, 'data-flow-id' => $apiResponse['workflow'], ), $template( $apiResponse ) ) ); } } wfProfileOut( __CLASS__ . '-render' ); } protected function redirect( Workflow $workflow ) { $link = $this->urlGenerator->workflowLink( $workflow->getArticleTitle(), $workflow->getId() ); $this->getOutput()->redirect( $link->getFullURL() ); } /** * Helper function extracts parameters from a WebRequest. * * @param string $action * @param WebRequest $request * @param AbstractBlock[] $blocks * @return array */ public function extractBlockParameters( $action, WebRequest $request, array $blocks ) { $result = array(); // BC for old parameters enclosed in square brackets foreach ( $blocks as $block ) { $name = $block->getName(); $result[$name] = $request->getArray( $name, array() ); } // BC for topic_list renamed to topiclist if ( isset( $result['topiclist'] ) && !$result['topiclist'] ) { $result['topiclist'] = $request->getArray( 'topic_list', array() ); } $globalData = array( 'action' => $action ); foreach ( $request->getValues() as $name => $value ) { // between urls only allowing [-_.] as unencoded special chars and // php mangling all of those into '_', we have to split on '_' if ( false !== strpos( $name, '_' ) ) { list( $block, $var ) = explode( '_', $name, 2 ); // flow_xxx is global data for all blocks if ( $block === 'flow' ) { $globalData[$var] = $value; } else { $result[$block][$var] = $value; } } } foreach ( $blocks as $block ) { $result[$block->getName()] += $globalData; } return $result; } + + protected function getCategories( Title $title ) { + $id = $title->getArticleId(); + if ( !$id ) { + return array(); + } + + $dbr = wfGetDB( DB_SLAVE ); + $res = $dbr->select( + /* from */ 'categorylinks', + /* select */ array( 'cl_to', 'cl_sortkey' ), + /* conditions */ array( 'cl_from' => $id ), + __METHOD__ + ); + + $categories = array(); + foreach ( $res as $row ) { + $categories[$row->cl_to] = $row->cl_sortkey; + } + + return $categories; + } } diff --git a/tests/phpunit/Parsoid/ReferenceExtractorTest.php b/tests/phpunit/Parsoid/ReferenceExtractorTest.php index 07d13ee662..e47e85caaa 100644 --- a/tests/phpunit/Parsoid/ReferenceExtractorTest.php +++ b/tests/phpunit/Parsoid/ReferenceExtractorTest.php @@ -1,174 +1,179 @@ markTestSkipped( 'Parsoid not enabled' ); } } public static function referenceExtractorProvider() { return array( array( 'Normal link', // source wiki text '[[My page]]', // expected factory method 'Flow\Model\WikiReference', // expected type 'link', // expected target 'title:My_page', ), array( 'Link with URL encoding issues', // source wiki text '[[User talk:Werdna?]]', // expected factory method 'Flow\Model\WikiReference', // expected type 'link', // expected target 'title:User_talk:Werdna?', ), array( 'Subpage link', // source wiki text '[[/Subpage]]', // expected factory method 'Flow\Model\WikiReference', // expected type 'link', // expected target 'title:Talk:UTPage/Subpage', // ??? 'Talk:UTPage', ), array( 'External link', // source wiki text '[http://www.google.com Google]', // expected factory method 'Flow\Model\UrlReference', // expected type 'link', // expected target 'url:http://www.google.com', ), array( 'File', // source wiki text '[[File:Image.png]]', // expected factory method 'Flow\Model\WikiReference', // expected type 'file', // expected target 'title:File:Image.png', ), array( 'File with parameters', // source wiki text '[[File:Image.png|25px]]', // expected factory method 'Flow\Model\WikiReference', // expected type 'file', // expected target 'title:File:Image.png', ), array( 'File with encoding issues', // source wiki text '[[File:Image?.png]]', // expected class 'Flow\Model\WikiReference', // expected type 'file', // expected target 'title:File:Image?.png', ), array( 'Template', // source wiki text '{{Foo}}', // expected factory method 'Flow\Model\WikiReference', // expected type 'template', // expected target 'title:Template:Foo', ), array( 'Non-existent File', // source wiki text '[[File:Some/Files/Really/Should_Not_Ex/ist.png]]', // expected factory method 'Flow\Model\WikiReference', // expected type 'file', // expected target 'title:File:Some/Files/Really/Should_Not_Ex/ist.png', ) ); } /** * @dataProvider referenceExtractorProvider */ public function testReferenceExtractor( $description, $wikitext, $expectedClass, $expectedType, $expectedTarget, $page = 'UTPage' ) { $referenceExtractor = Container::get( 'reference.extractor' ); $workflow = $this->getMock( 'Flow\Model\Workflow' ); $workflow->expects( $this->any() ) ->method( 'getId' ) ->will( $this->returnValue( UUID::create() ) ); $workflow->expects( $this->any() ) ->method( 'getArticleTitle' ) ->will( $this->returnValue( Title::newMainPage() ) ); $factory = new ReferenceFactory( $workflow, 'foo', UUID::create() ); $reflMethod = new ReflectionMethod( $referenceExtractor, 'extractReferences' ); $reflMethod->setAccessible( true ); + $reflProperty = new \ReflectionProperty( $referenceExtractor, 'extractors' ); + $reflProperty->setAccessible( true ); + $extractors = $reflProperty->getValue( $referenceExtractor ); + $result = $reflMethod->invoke( $referenceExtractor, $factory, + $extractors['post'], Utils::convert( 'wt', 'html', $wikitext, Title::newFromText( $page ) ) ); $this->assertCount( 1, $result ); $result = reset( $result ); $this->assertInstanceOf( $expectedClass, $result, $description ); $this->assertEquals( $expectedType, $result->getType(), $description ); $this->assertEquals( $expectedTarget, $result->getTargetIdentifier(), $description ); } }