Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
55 / 55
100.00% covered (success)
100.00%
4 / 4
CRAP
100.00% covered (success)
100.00%
1 / 1
MediaWikiRevisionEntitySchemaInserter
100.00% covered (success)
100.00%
55 / 55
100.00% covered (success)
100.00%
4 / 4
6
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 insertSchema
100.00% covered (success)
100.00%
31 / 31
100.00% covered (success)
100.00%
1 / 1
1
 truncateSchemaTextForCommentData
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 saveRevision
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2
3declare( strict_types = 1 );
4
5namespace EntitySchema\DataAccess;
6
7use DerivativeContext;
8use EntitySchema\Domain\Model\EntitySchemaId;
9use EntitySchema\Domain\Storage\IdGenerator;
10use EntitySchema\MediaWiki\Content\EntitySchemaContent;
11use EntitySchema\Services\Converter\EntitySchemaConverter;
12use IContextSource;
13use MediaWiki\CommentStore\CommentStoreComment;
14use MediaWiki\HookContainer\HookContainer;
15use MediaWiki\Languages\LanguageFactory;
16use MediaWiki\Revision\SlotRecord;
17use MediaWiki\Status\Status;
18use MediaWiki\Storage\PageUpdater;
19use MediaWiki\Title\TitleFactory;
20use RuntimeException;
21
22/**
23 * @license GPL-2.0-or-later
24 */
25class MediaWikiRevisionEntitySchemaInserter implements EntitySchemaInserter {
26    public const AUTOCOMMENT_NEWSCHEMA = 'entityschema-summary-newschema-nolabel';
27
28    private MediaWikiPageUpdaterFactory $pageUpdaterFactory;
29    private IdGenerator $idGenerator;
30    private WatchlistUpdater $watchListUpdater;
31    private IContextSource $context;
32    private LanguageFactory $languageFactory;
33    private HookContainer $hookContainer;
34    private TitleFactory $titleFactory;
35
36    public function __construct(
37        MediaWikiPageUpdaterFactory $pageUpdaterFactory,
38        WatchlistUpdater $watchListUpdater,
39        IdGenerator $idGenerator,
40        IContextSource $context,
41        LanguageFactory $languageFactory,
42        HookContainer $hookContainer,
43        TitleFactory $titleFactory
44    ) {
45        $this->idGenerator = $idGenerator;
46        $this->pageUpdaterFactory = $pageUpdaterFactory;
47        $this->watchListUpdater = $watchListUpdater;
48        $this->context = $context;
49        $this->languageFactory = $languageFactory;
50        $this->hookContainer = $hookContainer;
51        $this->titleFactory = $titleFactory;
52    }
53
54    /**
55     * @param string $language
56     * @param string $label
57     * @param string $description
58     * @param string[] $aliases
59     * @param string $schemaText
60     *
61     * @return EntitySchemaId id of the inserted Schema
62     */
63    public function insertSchema(
64        string $language,
65        string $label = '',
66        string $description = '',
67        array $aliases = [],
68        string $schemaText = ''
69    ): EntitySchemaId {
70        $id = new EntitySchemaId( 'E' . $this->idGenerator->getNewId() );
71        $persistentRepresentation = EntitySchemaEncoder::getPersistentRepresentation(
72            $id,
73            [ $language => $label ],
74            [ $language => $description ],
75            [ $language => $aliases ],
76            $schemaText
77        );
78
79        $schemaConverter = new EntitySchemaConverter();
80        $schemaData = $schemaConverter->getMonolingualNameBadgeData(
81            $persistentRepresentation,
82            $language
83        );
84        $summary = CommentStoreComment::newUnsavedComment(
85            '/* ' . self::AUTOCOMMENT_NEWSCHEMA . ' */' . $schemaData->label,
86            [
87                'key' => 'entityschema-summary-newschema-nolabel',
88                'language' => $language,
89                'label' => $schemaData->label,
90                'description' => $schemaData->description,
91                'aliases' => $schemaData->aliases,
92                'schemaText_truncated' => $this->truncateSchemaTextForCommentData(
93                    $schemaConverter->getSchemaText( $persistentRepresentation )
94                ),
95            ]
96        );
97
98        $updater = $this->pageUpdaterFactory->getPageUpdater( $id->getId() );
99        $content = new EntitySchemaContent( $persistentRepresentation );
100        $this->saveRevision( $updater, $content, $summary );
101
102        $this->watchListUpdater->optionallyWatchNewSchema( $id );
103
104        return $id;
105    }
106
107    private function truncateSchemaTextForCommentData( string $schemaText ): string {
108        $language = $this->languageFactory->getLanguage( 'en' );
109        return $language->truncateForVisual( $schemaText, 5000 );
110    }
111
112    private function saveRevision(
113        PageUpdater $updater,
114        EntitySchemaContent $content,
115        CommentStoreComment $summary
116    ): void {
117        $context = new DerivativeContext( $this->context );
118        $context->setTitle( $this->titleFactory->newFromPageIdentity( $updater->getPage() ) );
119        $status = Status::newGood();
120        if ( !$this->hookContainer->run(
121            'EditFilterMergedContent',
122            [ $context, $content, &$status, $summary->text, $this->context->getUser(), false ]
123        ) ) {
124            throw new RuntimeException( $status->getWikiText() );
125        }
126
127        $updater->setContent( SlotRecord::MAIN, $content );
128        $updater->saveRevision(
129            $summary,
130            EDIT_NEW | EDIT_INTERNAL
131        );
132        if ( !$updater->wasSuccessful() ) {
133            throw new RuntimeException( 'The revision could not be saved' );
134        }
135    }
136
137}