Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 46
0.00% covered (danger)
0.00%
0 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
ImportSource
0.00% covered (danger)
0.00%
0 / 46
0.00% covered (danger)
0.00%
0 / 3
72
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
 getHeader
0.00% covered (danger)
0.00%
0 / 39
0.00% covered (danger)
0.00%
0 / 1
30
 getTopics
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace Flow\Import\Wikitext;
4
5use ArrayIterator;
6use Flow\Import\IImportSource;
7use Flow\Import\ImportException;
8use Flow\Import\Plain\ImportHeader;
9use Flow\Import\Plain\ObjectRevision;
10use Flow\Import\TemplateHelper;
11use IDBAccessObject;
12use MediaWiki\MediaWikiServices;
13use MediaWiki\Revision\SlotRecord;
14use MediaWiki\StubObject\StubObject;
15use MediaWiki\Title\Title;
16use MediaWiki\User\User;
17use MediaWiki\Utils\MWTimestamp;
18use Parser;
19use ParserOptions;
20use WikitextContent;
21
22/**
23 * Imports the header of a wikitext talk page. Does not attempt to
24 * parse out and return individual topics. See the wikitext
25 * ConversionStrategy for more details.
26 */
27class ImportSource implements IImportSource {
28    /** @var User User doing the conversion actions (e.g. initial description, wikitext
29     *    archive edit).  However, actions will be attributed to the original user if
30     *    applicable.
31     */
32    protected $user;
33
34    /**
35     * @var Title
36     */
37    private $title;
38
39    /**
40     * @var Parser|StubObject
41     */
42    private $parser;
43
44    /**
45     * @var string|null
46     */
47    private $headerSuffix;
48
49    /**
50     * @param Title $title
51     * @param Parser|StubObject $parser
52     * @param User $user User to take actions as
53     * @param string|null $headerSuffix
54     * @throws ImportException When $title is an external title
55     */
56    public function __construct( Title $title, $parser, User $user, $headerSuffix = null ) {
57        if ( $title->isExternal() ) {
58            throw new ImportException( "Invalid non-local title: $title" );
59        }
60        $this->title = $title;
61        $this->parser = $parser;
62        $this->user = $user;
63        $this->headerSuffix = $headerSuffix;
64    }
65
66    /**
67     * Converts the existing wikitext talk page into a flow board header.
68     * If sections exist the header only receives the content up to the
69     * first section. Appends a template to the output indicating conversion
70     * occurred parameterized with the page the source lives at and the date
71     * of conversion in GMT.
72     *
73     * @return ImportHeader
74     * @throws ImportException When source header revision can not be loaded
75     */
76    public function getHeader() {
77        $revision = MediaWikiServices::getInstance()
78            ->getRevisionLookup()
79            ->getRevisionByTitle( $this->title, 0, IDBAccessObject::READ_LATEST );
80        if ( !$revision ) {
81            throw new ImportException( "Failed to load revision for title: {$this->title->getPrefixedText()}" );
82        }
83
84        $content = $revision->getContent( SlotRecord::MAIN );
85
86        // Verify we're operating on wikitext here. This should always be the case for talk pages.
87        if ( !( $content instanceof WikitextContent ) ) {
88            $revId = $revision->getId();
89            $model = $content->getModel();
90            throw new ImportException(
91                "The main slot for revision $revId has non-wikitext content model $model"
92            );
93        }
94
95        // If sections exist only take the content from the top of the page
96        // to the first section.
97        $nativeContent = $content->getText();
98        $output = $this->parser->parse(
99            $nativeContent,
100            $this->title,
101            new ParserOptions( $this->user )
102        );
103        $sections = $output->getSections();
104        if ( $sections ) {
105            # T319141: `byteoffset` is actually a *codepoint* offset.
106            $nativeContent = mb_substr( $nativeContent, 0, $sections[0]['byteoffset'] );
107        }
108
109        $content = TemplateHelper::extractTemplates( $nativeContent, $this->title );
110
111        $template = wfMessage( 'flow-importer-wt-converted-template' )->inContentLanguage()->plain();
112        $arguments = implode( '|', [
113            'archive=' . $this->title->getPrefixedText(),
114            'date=' . MWTimestamp::getInstance()->timestamp->format( 'Y-m-d' ),
115        ] );
116        $content .= "\n\n{{{$template}|$arguments}}";
117
118        if ( $this->headerSuffix ) {
119            $content .= "\n\n{$this->headerSuffix}";
120        }
121
122        return new ImportHeader(
123            [ new ObjectRevision(
124                $content,
125                wfTimestampNow(),
126                $this->user->getName(),
127                "wikitext-import:header-revision:{$revision->getId()}"
128            ) ],
129            "wikitext-import:header:{$this->title->getPrefixedText()}"
130        );
131    }
132
133    /**
134     * @inheritDoc
135     */
136    public function getTopics() {
137        return new ArrayIterator( [] );
138    }
139}