Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
72.41% covered (warning)
72.41%
21 / 29
60.00% covered (warning)
60.00%
3 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
RestStatusTrait
72.41% covered (warning)
72.41%
21 / 29
60.00% covered (warning)
60.00%
3 / 5
13.54
0.00% covered (danger)
0.00%
0 / 1
 getMessageValueConverter
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 convertStatusToMessageValues
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 throwExceptionForStatus
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
 getStatusErrorKeys
55.56% covered (warning)
55.56%
5 / 9
0.00% covered (danger)
0.00%
0 / 1
7.19
 logStatusError
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace MediaWiki\Rest\Handler\Helper;
4
5use MediaWiki\Logger\LoggerFactory;
6use MediaWiki\Message\Converter;
7use MediaWiki\Message\Message;
8use MediaWiki\Rest\LocalizedHttpException;
9use MessageSpecifier;
10use StatusValue;
11use Wikimedia\Message\MessageValue;
12
13/**
14 * Trait for handling Status objects in REST handlers.
15 */
16trait RestStatusTrait {
17
18    private ?Converter $messageValueConverter = null;
19
20    private function getMessageValueConverter(): Converter {
21        if ( !$this->messageValueConverter ) {
22            $this->messageValueConverter = new Converter();
23        }
24        return $this->messageValueConverter;
25    }
26
27    /**
28     * Extract the error messages from a Status, as MessageValue objects.
29     * @param StatusValue $status
30     * @return MessageValue[]
31     */
32    private function convertStatusToMessageValues( StatusValue $status ): array {
33        $conv = $this->getMessageValueConverter();
34        return array_map( static function ( $error ) use ( $conv ) {
35            // TODO: It should be possible to do this without going through a Message object,
36            // but the internal format of parameters is different in MessageValue (T358779)
37            return $conv->convertMessage(
38                Message::newFromSpecifier( [ $error['message'], ...$error['params'], ] )
39            );
40        }, $status->getErrors() );
41    }
42
43    /**
44     * @param StatusValue $status
45     * @param string|MessageValue $msg
46     * @param int $code
47     * @param array $data
48     *
49     * @return never
50     * @throws LocalizedHttpException
51     */
52    private function throwExceptionForStatus(
53        StatusValue $status,
54        $msg,
55        int $code,
56        array $data = []
57    ) {
58        $data += [ 'error-keys' => $this->getStatusErrorKeys( $status ) ];
59
60        if ( is_string( $msg ) ) {
61            $msg = MessageValue::new( $msg )
62                ->semicolonListParams(
63                    $this->convertStatusToMessageValues( $status )
64                );
65        }
66
67        throw new LocalizedHttpException( $msg, $code, $data );
68    }
69
70    private function getStatusErrorKeys( StatusValue $status ) {
71        $keys = [];
72
73        foreach ( $status->getErrors() as [ 'message' => $msg ] ) {
74            if ( is_string( $msg ) ) {
75                $keys[] = $msg;
76            } elseif ( is_array( $msg ) ) {
77                $keys[] = $msg[0];
78            } elseif ( $msg instanceof MessageSpecifier ) {
79                $keys[] = $msg->getKey();
80            }
81        }
82
83        return array_unique( $keys );
84    }
85
86    private function logStatusError( StatusValue $status, string $message, string $channel ) {
87        LoggerFactory::getInstance( $channel )->error(
88            $message,
89            [ 'reason' => $this->getStatusErrorKeys( $status ) ]
90        );
91    }
92
93}