Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 44
0.00% covered (danger)
0.00%
0 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
RecentEditEntrypointRegistrationHandler
0.00% covered (danger)
0.00%
0 / 44
0.00% covered (danger)
0.00%
0 / 2
182
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 onBeforePageDisplay
0.00% covered (danger)
0.00%
0 / 42
0.00% covered (danger)
0.00%
0 / 1
156
1<?php
2
3declare( strict_types=1 );
4
5namespace ContentTranslation\HookHandler;
6
7use ContentTranslation\Service\WikidataIdFetcher;
8use ContentTranslation\SiteMapper;
9use ContentTranslation\Store\RecentSignificantEditStore;
10use MediaWiki\MediaWikiServices;
11use MediaWiki\Output\Hook\BeforePageDisplayHook;
12use MediaWiki\Output\OutputPage;
13use MediaWiki\Registration\ExtensionRegistry;
14use MediaWiki\Skin\Skin;
15use MobileContext;
16
17class RecentEditEntrypointRegistrationHandler implements BeforePageDisplayHook {
18    /** @var RecentSignificantEditStore */
19    private $significantEditStore;
20
21    /** @var WikidataIdFetcher */
22    private $wikidataIdFetcher;
23
24    public function __construct(
25        RecentSignificantEditStore $significantEditStore,
26        WikidataIdFetcher $wikidataIdFetcher
27    ) {
28        $this->significantEditStore = $significantEditStore;
29        $this->wikidataIdFetcher = $wikidataIdFetcher;
30    }
31
32    /**
33     * This hook adds "ext.cx.entrypoints.recentedit" module, to support
34     * entrypoint inside articles, that encourages users to translate
35     * a section, they recently edited for the same page in another language.
36     *
37     * To support this entrypoint, a table named "cx_significant_edits"
38     * has been created, that stores the 10 latest "significant" edits,
39     * that affect at least one non-lead section, for each user.
40     *
41     * If such edits exist for the current article, then the
42     * "ext.cx.entrypoints.recentedit" module is added and
43     * "wgSectionTranslationRecentlyEditedSections" JS variable
44     * is set, containing an array of objects containing the page title
45     * and the sections edited for each language:
46     * ([{ "language": "en", page: "Moon", "sections": ["Formation"] }]).
47     *
48     * @param OutputPage $out
49     * @param Skin $skin
50     */
51    public function onBeforePageDisplay( $out, $skin ): void {
52        $isMobileView = false;
53        if ( ExtensionRegistry::getInstance()->isLoaded( 'MobileFrontend' ) ) {
54            /** @var MobileContext $mobileContext */
55            $mobileContext = MediaWikiServices::getInstance()->getService( 'MobileFrontend.Context' );
56            $isMobileView = $mobileContext->shouldDisplayMobileView();
57        }
58
59        // This entrypoint should only be enabled for mobile web version
60        if ( !$isMobileView ) {
61            return;
62        }
63
64        // This entrypoint should only be enabled for logged-in users
65        $user = $out->getUser();
66        if ( !$user->isNamed() ) {
67            return;
68        }
69
70        // This entrypoint should only be enabled for article pages
71        $isContentPage = $out->getTitle()->isContentPage();
72        if ( !$isContentPage ) {
73            return;
74        }
75
76        $currentLanguageCode = SiteMapper::getCurrentLanguageCode();
77        // This entrypoint should only be enabled for wikis that have SectionTranslation enabled
78        $enabledLanguages = $out->getConfig()->get( 'SectionTranslationTargetLanguages' );
79        $isSXEnabled = is_array( $enabledLanguages ) && in_array( $currentLanguageCode, $enabledLanguages );
80        if ( !$isSXEnabled ) {
81            return;
82        }
83
84        // If current wiki family is not supported for this entrypoint, return
85        if ( !$this->significantEditStore->isCurrentWikiFamilySupported() ) {
86            return;
87        }
88
89        $title = $out->getTitle();
90        $qid = $this->wikidataIdFetcher->getWikidataId( $title->getPrefixedDBkey(), $currentLanguageCode );
91
92        if ( !$qid ) {
93            wfDebugLog( 'cx-entrypoints-recent-edit', 'qid not found' );
94            return;
95        }
96        // get integer from Q id ("Q123")
97        $wikidataId = (int)filter_var( $qid, FILTER_SANITIZE_NUMBER_INT );
98
99        /**
100         * Fetch recent edits that satisfy the below conditions:
101         * 1. Were made by the current user
102         * 2. Were done to an article with the current wikidata page id
103         * 3. Were done in a language different from the current one
104         */
105        $edits = $this->significantEditStore->findEditsForPotentialSuggestions(
106            $user->getId(),
107            $wikidataId,
108            SiteMapper::getCurrentLanguageCode()
109        );
110
111        if ( !$edits ) {
112            return;
113        }
114
115        // We want to group the edited sections by language. For that reason, group the above
116        // RecentSignificantEdit instances to an associative array, that follow the below form:
117        // [
118        //    "en" => [ "language" => "en", "page" => "Moon", "sections" => ["Formation"] ],
119        //    "es" => [ "language" => "es", "page" => "Luna", "sections" => ["Formación"] ]
120        // ]
121        $recentUserEdits = [];
122        foreach ( $edits as $edit ) {
123            $editLanguage = $edit->getLanguage();
124            $recentUserEdits[$editLanguage]['language'] = $editLanguage;
125            $recentUserEdits[$editLanguage]['page'] = $edit->getPageTitle();
126
127            foreach ( $edit->getSectionTitles() as $sectionTitle ) {
128                $recentUserEdits[$editLanguage]['sections'][] = $sectionTitle;
129            }
130        }
131
132        // If all the above conditions are met, add 'ext.cx.entrypoints.recentedit' entrypoint
133        $out->addModules( 'ext.cx.entrypoints.recentedit' );
134
135        // Add Javascript variable that will contain an array of objects containing
136        // the edited sections, the respective page title and the respective language.
137        $out->addJsConfigVars( 'wgSectionTranslationRecentlyEditedSections',
138            array_values( $recentUserEdits ) );
139    }
140}