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