Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 57
0.00% covered (danger)
0.00%
0 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
StoryContentHandler
0.00% covered (danger)
0.00%
0 / 57
0.00% covered (danger)
0.00%
0 / 9
272
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
2
 getContentClass
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getActionOverrides
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
2
 fillParserOutput
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
56
 isParserCacheSupported
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSlotDiffRendererWithOptions
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 preloadTransform
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 preSaveTransform
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 validateSave
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3namespace MediaWiki\Extension\Wikistories;
4
5use MediaWiki\Category\TrackingCategories;
6use MediaWiki\Content\Content;
7use MediaWiki\Content\JsonContentHandler;
8use MediaWiki\Content\Renderer\ContentParseParams;
9use MediaWiki\Content\Transform\PreloadTransformParams;
10use MediaWiki\Content\Transform\PreSaveTransformParams;
11use MediaWiki\Content\ValidationParams;
12use MediaWiki\Context\IContextSource;
13use MediaWiki\JobQueue\JobQueueGroup;
14use MediaWiki\JobQueue\Jobs\RefreshLinksJob;
15use MediaWiki\Parser\ParserOutput;
16use MediaWiki\Title\Title;
17use MediaWiki\Title\TitleFactory;
18use MediaWiki\Title\TitleValue;
19
20class StoryContentHandler extends JsonContentHandler {
21
22    /** @var StoryConverter */
23    private $storyConverter;
24
25    /** @var StoryValidator */
26    private $storyValidator;
27
28    /** @var StoryRenderer */
29    private $storyRenderer;
30
31    /** @var StoryTrackingCategories */
32    private $storyTrackingCategories;
33
34    /** @var TrackingCategories */
35    private $trackingCategories;
36
37    /** @var JobQueueGroup */
38    private $jobQueueGroup;
39
40    /** @var TitleFactory */
41    private $titleFactory;
42
43    /**
44     * @param string $modelId
45     * @param StoryConverter $storyConverter
46     * @param StoryValidator $storyValidator
47     * @param StoryRenderer $storyRenderer
48     * @param StoryTrackingCategories $storyTrackingCategories
49     * @param TrackingCategories $trackingCategories
50     * @param JobQueueGroup $jobQueueGroup
51     * @param TitleFactory $titleFactory
52     */
53    public function __construct(
54        $modelId,
55        StoryConverter $storyConverter,
56        StoryValidator $storyValidator,
57        StoryRenderer $storyRenderer,
58        StoryTrackingCategories $storyTrackingCategories,
59        TrackingCategories $trackingCategories,
60        JobQueueGroup $jobQueueGroup,
61        TitleFactory $titleFactory
62    ) {
63        parent::__construct( $modelId );
64        $this->storyConverter = $storyConverter;
65        $this->storyValidator = $storyValidator;
66        $this->storyRenderer = $storyRenderer;
67        $this->storyTrackingCategories = $storyTrackingCategories;
68        $this->trackingCategories = $trackingCategories;
69        $this->jobQueueGroup = $jobQueueGroup;
70        $this->titleFactory = $titleFactory;
71    }
72
73    /**
74     * @return string
75     */
76    protected function getContentClass() {
77        return StoryContent::class;
78    }
79
80    /**
81     * @return array
82     */
83    public function getActionOverrides() {
84        return [
85            'edit' => StoryEditAction::class,
86            'submit' => StorySubmitAction::class,
87            'storyview' => [
88                'class' => StoryViewAction::class,
89                'services' => [
90                    'Wikistories.Cache',
91                    'UrlUtils',
92                ]
93            ],
94        ];
95    }
96
97    /**
98     * Outputs the plain html version of a story.
99     *
100     * @param Content $content
101     * @param ContentParseParams $cpoParams
102     * @param ParserOutput &$parserOutput
103     */
104    public function fillParserOutput(
105        Content $content,
106        ContentParseParams $cpoParams,
107        ParserOutput &$parserOutput
108    ) {
109        '@phan-var StoryContent $content';
110        /** @var StoryContent $story */
111        $story = $this->storyConverter->toLatest( $content );
112        $storyPage = $cpoParams->getPage();
113        $storyTitle = Title::newFromPageReference( $storyPage );
114        $storyData = $this->storyRenderer->getStoryData( $story, $storyTitle );
115
116        // Links
117        $parserOutput->addLink( new TitleValue( NS_MAIN, $storyData[ 'articleTitle' ] ) );
118        foreach ( $storyData[ 'frames' ] as $frame ) {
119            $parserOutput->addImage( strtr( $frame[ 'filename' ], ' ', '_' ) );
120        }
121
122        // Categories
123        foreach ( $story->getCategories() as $categoryName ) {
124            $categoryTitle = $this->titleFactory->makeTitleSafe( NS_CATEGORY, $categoryName );
125            if ( $categoryTitle ) {
126                $parserOutput->addCategory( $categoryTitle, $storyPage->getDBkey() );
127            }
128        }
129
130        // Tracking categories
131        foreach ( $storyData[ 'trackingCategories' ] as $trackingCategory ) {
132            $this->trackingCategories->addTrackingCategory(
133                $parserOutput, $trackingCategory, $storyPage
134            );
135        }
136
137        // refresh links job when there are changes of tracking categories
138        if ( $this->storyTrackingCategories->hasDiff( $storyData[ 'trackingCategories' ], $storyTitle ) ) {
139            $this->jobQueueGroup->push(
140                RefreshLinksJob::newPrioritized( $storyTitle, [] )
141            );
142        }
143
144        // HTML version
145        if ( $cpoParams->getGenerateHtml() ) {
146            $parts = $this->storyRenderer->renderNoJS( $storyData );
147            $parserOutput->addModuleStyles( [ $parts['style'] ] );
148            $parserOutput->setText( $parts['html'] );
149        }
150    }
151
152    /**
153     * @inheritDoc
154     */
155    public function isParserCacheSupported() {
156        return true;
157    }
158
159    /**
160     * @param IContextSource $context
161     * @param array $options
162     * @return StorySlotDiffRenderer
163     */
164    public function getSlotDiffRendererWithOptions( IContextSource $context, $options = [] ) {
165        return new StorySlotDiffRenderer(
166            $this->storyConverter,
167            $this->createTextSlotDiffRenderer( $options )
168        );
169    }
170
171    /**
172     * @inheritDoc
173     */
174    public function preloadTransform( Content $content, PreloadTransformParams $pltParams ): Content {
175        '@phan-var StoryContent $content';
176        /** @var StoryContent $story */
177        $story = $content;
178        return $this->storyConverter->toLatest( $story );
179    }
180
181    /**
182     * @inheritDoc
183     */
184    public function preSaveTransform( Content $content, PreSaveTransformParams $pstParams ): Content {
185        '@phan-var StoryContent $content';
186        /** @var StoryContent $story */
187        $story = $content;
188        return $this->storyConverter->withSchemaVersion( $story );
189    }
190
191    /**
192     * @inheritDoc
193     */
194    public function validateSave( Content $content, ValidationParams $validationParams ) {
195        '@phan-var StoryContent $content';
196        $status = parent::validateSave( $content, $validationParams );
197        if ( !$status->isGood() ) {
198            return $status;
199        }
200        /** @var StoryContent $story */
201        $story = $content;
202        return $this->storyValidator->isValid( $story );
203    }
204
205}