Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
45.16% covered (danger)
45.16%
14 / 31
50.00% covered (danger)
50.00%
2 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
EventSerializer
45.16% covered (danger)
45.16%
14 / 31
50.00% covered (danger)
50.00%
2 / 4
26.49
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 timestampToDt
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 createEvent
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
30
 createMeta
90.91% covered (success)
90.91%
10 / 11
0.00% covered (danger)
0.00%
0 / 1
3.01
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 * http://www.gnu.org/copyleft/gpl.html
17 *
18 * @file
19 * @author Andrew Otto <otto@wikimedia.org>
20 */
21
22namespace MediaWiki\Extension\EventBus\Serializers;
23
24use MediaWiki\Config\Config;
25use MediaWiki\Http\Telemetry;
26use MediaWiki\WikiMap\WikiMap;
27use Wikimedia\UUID\GlobalIdGenerator;
28
29/**
30 * EventSerializer should be used to create an event array suitable
31 * for producing to WMF's Event Platform, usually via EventGate.
32 */
33class EventSerializer {
34    /**
35     * @var Config
36     */
37    private Config $mainConfig;
38    /**
39     * @var GlobalIdGenerator
40     */
41    private GlobalIdGenerator $globalIdGenerator;
42    private Telemetry $telemetry;
43
44    /**
45     * @param Config $mainConfig
46     *    NOTE: this parameter is unused.
47     *    It should be removed as part of T392516.
48     * @param GlobalIdGenerator $globalIdGenerator
49     * @param Telemetry $telemetry
50     */
51    public function __construct(
52        Config $mainConfig,
53        GlobalIdGenerator $globalIdGenerator,
54        Telemetry $telemetry
55    ) {
56        $this->mainConfig = $mainConfig;
57        $this->globalIdGenerator = $globalIdGenerator;
58        $this->telemetry = $telemetry;
59    }
60
61    /**
62     * Format a timestamp for a date-time attribute in an event in ISO_8601 format.
63     *
64     * @param string|null $timestamp Timestamp, in a format supported by wfTimestamp(), or null for current timestamp.
65     * @return string
66     */
67    public static function timestampToDt( ?string $timestamp = null ): string {
68        return wfTimestamp( TS_ISO_8601, $timestamp );
69    }
70
71    /**
72     * Adds a meta subobject to $eventAttrs based on uri and stream.
73     *
74     * @param string $schema
75     *  Schema URI for '$schema' field.
76     *
77     * @param string $stream
78     *  Name of stream for meta.stream field.
79     *
80     * @param string $uri
81     *  Uri of this entity for meta.uri field.
82     *
83     * @param array $eventAttrs
84     *  Additional event attributes to include.
85     *
86     * @param string|null $wikiId
87     *  wikiId to use when looking up value for meta.domain.
88     *  If null, meta.domain will not be set.
89     *  NOTE: It would be better if wiki domain name was fetched and passed into createEvent,
90     *        rather than forcing createEvent to look up the domain itself.
91     *        However, this would require changing the createEvent method signature, which is used
92     *        by CirrusSearch extension.
93     *        See: https://phabricator.wikimedia.org/T392516
94     *
95     * @param bool|string|null $ingestionTimestamp
96     *  If true, meta.dt will be set to the current timestamp.
97     *  If a string, meta.dt will be set to value of timestampToDt($timestampToDt).
98     *  If null, meta.dt will not be set.
99     *  It is preferred to leave this value at null,
100     *  as EventBus produces through EventGate, which will handle setting meta.dt
101     *  to its ingestion time.
102     *  See: https://phabricator.wikimedia.org/T267648
103     *
104     * @return array $eventAttrs + $schema + meta sub object
105     */
106    public function createEvent(
107        string $schema,
108        string $stream,
109        string $uri,
110        array $eventAttrs,
111        ?string $wikiId = null,
112        $ingestionTimestamp = null
113    ): array {
114        // Get canonical wiki domain 'display name' via wikiId.
115        // If WikiMap::getWiki is null, then we can't get a domain (and are likely in a unit test).
116        // In that case, don't provide a domain name.
117        $wikiDomainName = null;
118        if ( $wikiId !== null ) {
119            $wikiReference = WikiMap::getWiki( $wikiId );
120            $wikiDomainName = $wikiReference ? $wikiReference->getDisplayName() : null;
121        }
122
123        $metaDt = null;
124        if ( $ingestionTimestamp === true ) {
125            $metaDt = self::timestampToDt();
126        } elseif ( $ingestionTimestamp !== null ) {
127            $metaDt = self::timestampToDt( $ingestionTimestamp );
128        }
129        return array_merge(
130            $eventAttrs,
131            [
132                '$schema' => $schema,
133                'meta' => $this->createMeta( $stream, $uri, $wikiDomainName, $metaDt )
134            ]
135        );
136    }
137
138    /**
139     * Creates the meta subobject that should be common for all events.
140     *
141     * @param string $stream
142     * @param string $uri
143     * @param string|null $domain
144     *    If null, 'domain' will not be set.
145     * @param string|null $dt
146     *    If null, 'dt' will not be set.
147     * @return array
148     */
149    private function createMeta(
150        string $stream,
151        string $uri,
152        ?string $domain = null,
153        ?string $dt = null
154    ): array {
155        $metaAttrs = [
156            'stream' => $stream,
157            'uri' => $uri,
158            'id' => $this->globalIdGenerator->newUUIDv4(),
159            'request_id' => $this->telemetry->getRequestId(),
160        ];
161
162        if ( $domain !== null ) {
163            $metaAttrs['domain'] = $domain;
164        }
165
166        if ( $dt !== null ) {
167            $metaAttrs['dt'] = $dt;
168        }
169        return $metaAttrs;
170    }
171}