Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
3 / 3
CRAP
100.00% covered (success)
100.00%
1 / 1
LexemeTermLanguageValidator
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
3 / 3
9
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 validate
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
1 / 1
6
 isValidItemId
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3declare( strict_types = 1 );
4
5namespace Wikibase\Lexeme\DataAccess\ChangeOp\Validation;
6
7use Wikibase\DataModel\Entity\ItemId;
8use Wikibase\Lexeme\MediaWiki\Api\Error\InvalidItemId;
9use Wikibase\Lexeme\MediaWiki\Api\Error\JsonFieldHasWrongType;
10use Wikibase\Lexeme\MediaWiki\Api\Error\LexemeTermLanguageCanNotBeEmpty;
11use Wikibase\Lexeme\MediaWiki\Api\Error\UnknownLanguage;
12use Wikibase\Lexeme\Presentation\ChangeOp\Deserialization\ValidationContext;
13use Wikibase\Lib\ContentLanguages;
14
15/**
16 * @license GPL-2.0-or-later
17 */
18class LexemeTermLanguageValidator {
19
20    /**
21     * According to BCP 47 (https://tools.ietf.org/html/bcp47)
22     */
23    private const PRIVATE_USE_SUBTAG_SEPARATOR = '-x-';
24
25    /**
26     * @var ContentLanguages
27     */
28    private $languages;
29
30    public function __construct( ContentLanguages $languages ) {
31        $this->languages = $languages;
32    }
33
34    /**
35     * @param string $input
36     * @param ValidationContext $context
37     * @param string|null $termText for context in the error message, if available
38     */
39    public function validate( $input, ValidationContext $context, $termText = null ) {
40        if ( !is_string( $input ) ) {
41            $context->addViolation( new JsonFieldHasWrongType( 'string', gettype( $input ) ) );
42            return;
43        }
44
45        $parts = explode(
46            self::PRIVATE_USE_SUBTAG_SEPARATOR,
47            $input,
48            2
49        );
50        $language = $parts[0];
51
52        if ( $language === '' ) {
53            $context->addViolation( new LexemeTermLanguageCanNotBeEmpty() );
54            return;
55        }
56
57        if ( !$this->languages->hasLanguage( $language ) ) {
58            $context->addViolation( new UnknownLanguage( $language, $termText ) );
59        }
60
61        if ( count( $parts ) > 1 && !$this->isValidItemId( $parts[1] ) ) {
62            $context->addViolation( new InvalidItemId( $parts[1] ) );
63        }
64    }
65
66    private function isValidItemId( $id ) {
67        return preg_match( ItemId::PATTERN, $id ) &&
68            strtoupper( $id ) === $id;
69    }
70
71}