Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
35.14% |
13 / 37 |
|
0.00% |
0 / 4 |
CRAP | |
0.00% |
0 / 1 |
Hooks | |
35.14% |
13 / 37 |
|
0.00% |
0 / 4 |
31.11 | |
0.00% |
0 / 1 |
newInstance | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 | |||
__construct | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
onGetStreamConfigs | |
92.86% |
13 / 14 |
|
0.00% |
0 / 1 |
3.00 | |||
onBeforePageDisplay | |
0.00% |
0 / 14 |
|
0.00% |
0 / 1 |
20 |
1 | <?php |
2 | /** |
3 | * This program is free software; you can redistribute it and/or modify |
4 | * it under the terms of the GNU General Public License as published by |
5 | * the Free Software Foundation; either version 2 of the License, or |
6 | * (at your option) any later version. |
7 | * |
8 | * This program is distributed in the hope that it will be useful, |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | * GNU General Public License for more details. |
12 | * |
13 | * You should have received a copy of the GNU General Public License along |
14 | * with this program; if not, write to the Free Software Foundation, Inc., |
15 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
16 | * |
17 | * @file |
18 | */ |
19 | |
20 | namespace MediaWiki\Extension\MetricsPlatform; |
21 | |
22 | use MediaWiki\Config\Config; |
23 | use MediaWiki\Config\ServiceOptions; |
24 | use MediaWiki\Extension\EventStreamConfig\Hooks\GetStreamConfigsHook; |
25 | use MediaWiki\MediaWikiServices; |
26 | use MediaWiki\Output\Hook\BeforePageDisplayHook; |
27 | use MediaWiki\Output\OutputPage; |
28 | use Skin; |
29 | |
30 | class Hooks implements |
31 | GetStreamConfigsHook, |
32 | BeforePageDisplayHook |
33 | { |
34 | public const CONSTRUCTOR_OPTIONS = [ |
35 | 'MetricsPlatformEnableStreamConfigsMerging', |
36 | 'MetricsPlatformEnableExperimentOverrides', |
37 | ]; |
38 | |
39 | /** @var string */ |
40 | public const PRODUCT_METRICS_WEB_BASE_SCHEMA_TITLE = 'analytics/product_metrics/web/base'; |
41 | |
42 | /** @var string */ |
43 | public const PRODUCT_METRICS_STREAM_PREFIX = 'product_metrics.'; |
44 | |
45 | /** @var string */ |
46 | public const PRODUCT_METRICS_DESTINATION_EVENT_SERVICE = 'eventgate-analytics-external'; |
47 | |
48 | private InstrumentConfigsFetcher $configsFetcher; |
49 | private ExperimentManagerFactory $experimentManagerFactory; |
50 | private ServiceOptions $options; |
51 | |
52 | public static function newInstance( |
53 | InstrumentConfigsFetcher $configsFetcher, |
54 | ExperimentManagerFactory $experimentManagerFactory, |
55 | Config $config |
56 | ): self { |
57 | return new self( |
58 | $configsFetcher, |
59 | $experimentManagerFactory, |
60 | new ServiceOptions( self::CONSTRUCTOR_OPTIONS, $config ) |
61 | ); |
62 | } |
63 | |
64 | public function __construct( |
65 | InstrumentConfigsFetcher $configsFetcher, |
66 | ExperimentManagerFactory $experimentManagerFactory, |
67 | ServiceOptions $options |
68 | ) { |
69 | $options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS ); |
70 | $this->configsFetcher = $configsFetcher; |
71 | $this->experimentManagerFactory = $experimentManagerFactory; |
72 | $this->options = $options; |
73 | } |
74 | |
75 | /** |
76 | * @see https://www.mediawiki.org/wiki/Manual:Hooks/GetStreamConfigs |
77 | * @param array &$streamConfigs |
78 | */ |
79 | public function onGetStreamConfigs( array &$streamConfigs ): void { |
80 | if ( !$this->options->get( 'MetricsPlatformEnableStreamConfigsMerging' ) ) { |
81 | return; |
82 | } |
83 | |
84 | $instrumentConfigs = $this->configsFetcher->getInstrumentConfigs(); |
85 | |
86 | foreach ( $instrumentConfigs as $value ) { |
87 | $streamConfigs[ $value['stream_name'] ] = [ |
88 | 'schema_title' => self::PRODUCT_METRICS_WEB_BASE_SCHEMA_TITLE, |
89 | 'producers' => [ |
90 | 'metrics_platform_client' => [ |
91 | 'provide_values' => $value['contextual_attributes'] |
92 | ] |
93 | ], |
94 | 'sample' => $value['sample'], |
95 | 'destination_event_service' => self::PRODUCT_METRICS_DESTINATION_EVENT_SERVICE, |
96 | ]; |
97 | } |
98 | } |
99 | |
100 | /** |
101 | * This hook adds a JavaScript configuration variable to the output. |
102 | * |
103 | * In order to provide experiment enrollment data with bucketing assignments |
104 | * for a logged-in user, we take the user's id to deterministically sample and |
105 | * bucket the user. Based on the sample rates of active experiments, the user's |
106 | * participation in experimentation cohorts is written to a configuration variable |
107 | * that will be read by the Metrics Platform client libraries and instrument code |
108 | * to send that data along during events submission. |
109 | * |
110 | * @param OutputPage $out |
111 | * @param Skin $skin |
112 | */ |
113 | public function onBeforePageDisplay( $out, $skin ): void { |
114 | // Skip if the user is not logged in or is a temporary user. |
115 | if ( !$out->getUser()->isNamed() ) { |
116 | return; |
117 | } |
118 | $services = MediaWikiServices::getInstance(); |
119 | |
120 | // Get the user's central ID (for assigning buckets later) and skip if 0. |
121 | $lookup = $services->getCentralIdLookupFactory()->getLookup(); |
122 | $userId = $lookup->centralIdFromLocalUser( $out->getUser() ); |
123 | if ( $userId === 0 ) { |
124 | return; |
125 | } |
126 | |
127 | $experimentManager = $this->experimentManagerFactory->newInstance(); |
128 | |
129 | // Set the JS config variable for the user's experiment enrollment data. |
130 | $out->addJsConfigVars( |
131 | 'wgMetricsPlatformUserExperiments', |
132 | $experimentManager->enrollUser( $out->getUser(), $out->getRequest() ) |
133 | ); |
134 | |
135 | // Optimization: |
136 | // |
137 | // The `ext.metricsPlatform` module only contains a QA-related function right now. Only send the module to the |
138 | // browser when we allow experiment enrollment overrides. |
139 | if ( $this->options->get( 'MetricsPlatformEnableExperimentOverrides' ) ) { |
140 | $out->addModules( 'ext.metricsPlatform' ); |
141 | } |
142 | } |
143 | } |