Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
96.36% |
53 / 55 |
|
85.71% |
6 / 7 |
CRAP | |
0.00% |
0 / 1 |
| MathoidChecker | |
96.36% |
53 / 55 |
|
85.71% |
6 / 7 |
14 | |
0.00% |
0 / 1 |
| __construct | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| getCheckResponse | |
100.00% |
11 / 11 |
|
100.00% |
1 / 1 |
3 | |||
| getCacheKey | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
| runCheck | |
100.00% |
24 / 24 |
|
100.00% |
1 / 1 |
2 | |||
| isValid | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
| getError | |
75.00% |
6 / 8 |
|
0.00% |
0 / 1 |
4.25 | |||
| getValidTex | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
2 | |||
| 1 | <?php |
| 2 | |
| 3 | namespace MediaWiki\Extension\Math\InputCheck; |
| 4 | |
| 5 | use MediaWiki\Http\HttpRequestFactory; |
| 6 | use MediaWiki\Message\Message; |
| 7 | use Psr\Log\LoggerInterface; |
| 8 | use RuntimeException; |
| 9 | use Wikimedia\ObjectCache\WANObjectCache; |
| 10 | |
| 11 | class MathoidChecker extends BaseChecker { |
| 12 | |
| 13 | private const EXPECTED_RETURN_CODES = [ 200, 400 ]; |
| 14 | public const VERSION = 1; |
| 15 | /** @var int|null */ |
| 16 | private $statusCode; |
| 17 | /** @var string */ |
| 18 | private $response; |
| 19 | |
| 20 | public function __construct( |
| 21 | private readonly WANObjectCache $cache, |
| 22 | private readonly HttpRequestFactory $httpFactory, |
| 23 | private readonly LoggerInterface $logger, |
| 24 | private readonly string $url, |
| 25 | private readonly int $timeout, |
| 26 | string $input, |
| 27 | private readonly string $type, |
| 28 | bool $purge, |
| 29 | ) { |
| 30 | parent::__construct( $input, $purge ); |
| 31 | } |
| 32 | |
| 33 | public function getCheckResponse(): array { |
| 34 | if ( $this->statusCode === null ) { |
| 35 | $cacheInputKey = $this->getCacheKey(); |
| 36 | if ( $this->purge ) { |
| 37 | $this->cache->delete( $cacheInputKey, WANObjectCache::TTL_INDEFINITE ); |
| 38 | } |
| 39 | [ $this->statusCode, $this->response ] = $this->cache->getWithSetCallback( |
| 40 | $cacheInputKey, |
| 41 | WANObjectCache::TTL_INDEFINITE, |
| 42 | [ $this, 'runCheck' ], |
| 43 | [ 'version' => self::VERSION ] |
| 44 | ); |
| 45 | } |
| 46 | return [ $this->statusCode, $this->response ]; |
| 47 | } |
| 48 | |
| 49 | public function getCacheKey(): string { |
| 50 | return $this->cache->makeGlobalKey( |
| 51 | self::class, |
| 52 | md5( $this->type . '-' . $this->inputTeX ) |
| 53 | ); |
| 54 | } |
| 55 | |
| 56 | public function runCheck(): array { |
| 57 | $url = "{$this->url}/texvcinfo"; |
| 58 | $q = rawurlencode( $this->inputTeX ); |
| 59 | $postData = "type=$this->type&q=$q"; |
| 60 | $options = [ |
| 61 | 'method' => 'POST', |
| 62 | 'postData' => $postData, |
| 63 | 'timeout' => $this->timeout, |
| 64 | ]; |
| 65 | $req = $this->httpFactory->create( $url, $options, __METHOD__ ); |
| 66 | $req->execute(); |
| 67 | $statusCode = $req->getStatus(); |
| 68 | if ( in_array( $statusCode, self::EXPECTED_RETURN_CODES, true ) ) { |
| 69 | return [ $statusCode, $req->getContent() ]; |
| 70 | } |
| 71 | $e = new RuntimeException( 'Mathoid check returned unexpected error code.' ); |
| 72 | $this->logger->error( 'Mathoid check endpoint "{url}" returned ' . |
| 73 | 'HTTP status code "{statusCode}" for post data "{postData}": {exception}.', |
| 74 | [ |
| 75 | 'url' => $url, |
| 76 | 'statusCode' => $statusCode, |
| 77 | 'postData' => $postData, |
| 78 | 'exception' => $e, |
| 79 | ] |
| 80 | ); |
| 81 | throw $e; |
| 82 | } |
| 83 | |
| 84 | public function isValid(): bool { |
| 85 | [ $statusCode ] = $this->getCheckResponse(); |
| 86 | return $statusCode === 200; |
| 87 | } |
| 88 | |
| 89 | public function getError(): ?Message { |
| 90 | [ $statusCode, $content ] = $this->getCheckResponse(); |
| 91 | if ( $statusCode !== 200 ) { |
| 92 | // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged |
| 93 | $json = @json_decode( $content ); |
| 94 | if ( $json && isset( $json->detail ) ) { |
| 95 | return $this->errorObjectToMessage( $json->detail, $this->url ); |
| 96 | } |
| 97 | return $this->errorObjectToMessage( (object)[ 'error' => (object)[ |
| 98 | 'message' => 'Math extension cannot connect to mathoid.' ] ], $this->url ); |
| 99 | } |
| 100 | return null; |
| 101 | } |
| 102 | |
| 103 | public function getValidTex(): ?string { |
| 104 | [ $statusCode, $content ] = $this->getCheckResponse(); |
| 105 | if ( $statusCode === 200 ) { |
| 106 | $json = json_decode( $content ); |
| 107 | return $json->checked; |
| 108 | } |
| 109 | return parent::getValidTex(); |
| 110 | } |
| 111 | |
| 112 | } |