Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
96.55% covered (success)
96.55%
28 / 29
100.00% covered (success)
100.00%
6 / 6
CRAP
100.00% covered (success)
100.00%
1 / 1
ApiMessageTrait
100.00% covered (success)
100.00%
28 / 28
100.00% covered (success)
100.00%
6 / 6
14
100.00% covered (success)
100.00%
1 / 1
 getApiCode
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
6
 setApiCode
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
4
 getApiData
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setApiData
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 __serialize
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 __unserialize
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3// @phan-file-suppress PhanTraitParentReference,PhanUndeclaredMethod
4
5/**
6 * @license GPL-2.0-or-later
7 * @file
8 */
9
10namespace MediaWiki\Api;
11
12use InvalidArgumentException;
13
14/**
15 * Trait to implement the IApiMessage interface for Message subclasses
16 * @since 1.27
17 * @ingroup API
18 */
19trait ApiMessageTrait {
20
21    /**
22     * Compatibility code mappings for various MW messages.
23     * @todo Ideally anything relying on this should be changed to use ApiMessage.
24     * @var string[]
25     * @phpcs-require-sorted-array
26     */
27    protected static $messageMap = [
28        'actionthrottledtext' => 'ratelimited',
29        'autoblockedtext' => 'autoblocked',
30        'autoblockedtext-tempuser' => 'autoblocked',
31        'badaccess-group0' => 'permissiondenied',
32        'badaccess-groups' => 'permissiondenied',
33        'badipaddress' => 'invalidip',
34        'blankpage' => 'emptypage',
35        'blockedtext' => 'blocked',
36        'blockedtext-composite' => 'blocked',
37        'blockedtext-partial' => 'blocked',
38        'blockedtext-tempuser' => 'blocked',
39        'cannotdelete' => 'cantdelete',
40        'cannotundelete' => 'cantundelete',
41        'cantmove-titleprotected' => 'protectedtitle',
42        'cantrollback' => 'onlyauthor',
43        'confirmedittext' => 'confirmemail',
44        'content-not-allowed-here' => 'contentnotallowedhere',
45        'delete-toobig' => 'bigdelete',
46        'deleteprotected' => 'cantedit',
47        'edit-conflict' => 'editconflict',
48        'edit-constraint-confirmrecreate' => 'pagedeleted',
49        'edit-constraint-confirmrecreate-noreason' => 'pagedeleted',
50        'imagenocrossnamespace' => 'nonfilenamespace',
51        'imagetypemismatch' => 'filetypemismatch',
52        'import-noarticle' => 'badinterwiki',
53        'importbadinterwiki' => 'badinterwiki',
54        'importcantopen' => 'cantopenfile',
55        'importnofile' => 'nofile',
56        'importuploaderrorpartial' => 'partialupload',
57        'importuploaderrorsize' => 'filetoobig',
58        'importuploaderrortemp' => 'notempdir',
59        'ipb-block-not-found' => 'alreadyblocked',
60        'ipb_already_blocked' => 'alreadyblocked',
61        'ipb_blocked_as_range' => 'blockedasrange',
62        'ipb_cant_unblock' => 'cantunblock',
63        'ipb_expiry_invalid' => 'invalidexpiry',
64        'ip_range_invalid' => 'invalidrange',
65        'longpageerror' => 'contenttoobig',
66        'mailnologin' => 'cantsend',
67        'markedaspatrollederror-noautopatrol' => 'noautopatrol',
68        'movenologintext' => 'cantmove-anon',
69        'movenotallowed' => 'cantmove',
70        'movenotallowedfile' => 'cantmovefile',
71        'namespaceprotected' => 'protectednamespace',
72        'nocreate-loggedin' => 'cantcreate',
73        'nocreatetext' => 'cantcreate-anon',
74        'noname' => 'invaliduser',
75        'nosuchusershort' => 'nosuchuser',
76        'notanarticle' => 'missingtitle',
77        'nouserspecified' => 'invaliduser',
78        'ns-specialprotected' => 'unsupportednamespace',
79        'protect-cantedit' => 'cantedit',
80        'protectedinterface' => 'protectednamespace-interface',
81        'protectedpagetext' => 'protectedpage',
82        'range_block_disabled' => 'rangedisabled',
83        'rcpatroldisabled' => 'patroldisabled',
84        'readonlytext' => 'readonly',
85        'sessionfailure' => 'badtoken',
86        'systemblockedtext' => 'blocked',
87        'titleprotected' => 'protectedtitle',
88        'undo-failure' => 'undofailure',
89        'userrights-no-interwiki' => 'nointerwikiuserrights',
90        'userrights-nodatabase' => 'nosuchdatabase',
91    ];
92
93    /** @var string|null */
94    protected $apiCode = null;
95    /** @var array */
96    protected $apiData = [];
97
98    /** @inheritDoc */
99    public function getApiCode() {
100        if ( $this->apiCode === null ) {
101            $key = $this->getKey();
102            if ( isset( self::$messageMap[$key] ) ) {
103                $this->apiCode = self::$messageMap[$key];
104            } elseif ( $key === 'apierror-missingparam' ) {
105                // @todo: Kill this case along with ApiBase::$messageMap
106                $this->apiCode = 'no' . $this->getParams()[0];
107            } elseif ( str_starts_with( $key, 'apiwarn-' ) ) {
108                $this->apiCode = substr( $key, 8 );
109            } elseif ( str_starts_with( $key, 'apierror-' ) ) {
110                $this->apiCode = substr( $key, 9 );
111            } else {
112                $this->apiCode = $key;
113            }
114
115            // Ensure the code is actually valid
116            $this->apiCode = preg_replace( '/[^a-zA-Z0-9_-]/', '_', $this->apiCode );
117        }
118        return $this->apiCode;
119    }
120
121    /** @inheritDoc */
122    public function setApiCode( $code, ?array $data = null ) {
123        if ( $code !== null && !ApiErrorFormatter::isValidApiCode( $code ) ) {
124            throw new InvalidArgumentException( "Invalid code \"$code\"" );
125        }
126
127        $this->apiCode = $code;
128        if ( $data !== null ) {
129            $this->setApiData( $data );
130        }
131    }
132
133    /** @inheritDoc */
134    public function getApiData() {
135        return $this->apiData;
136    }
137
138    public function setApiData( array $data ) {
139        $this->apiData = $data;
140    }
141
142    public function __serialize() {
143        return [
144            'parent' => parent::__serialize(),
145            'apiCode' => $this->apiCode,
146            'apiData' => $this->apiData,
147        ];
148    }
149
150    public function __unserialize( $data ) {
151        parent::__unserialize( $data['parent'] );
152        $this->apiCode = $data['apiCode'];
153        $this->apiData = $data['apiData'];
154    }
155}
156
157/** @deprecated class alias since 1.43 */
158class_alias( ApiMessageTrait::class, 'ApiMessageTrait' );