Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
56.10% covered (warning)
56.10%
23 / 41
62.50% covered (warning)
62.50%
5 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
Pattern
56.10% covered (warning)
56.10%
23 / 41
62.50% covered (warning)
62.50%
5 / 8
37.66
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 isMatch
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
5
 generate
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 buildLike
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
2
 toLikeValue
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 extract
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 init
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
3
 __toString
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace MediaWiki\User\TempUser;
4
5use Stringable;
6use UnexpectedValueException;
7use Wikimedia\Rdbms\LikeValue;
8use Wikimedia\Rdbms\Platform\ISQLPlatform;
9
10/**
11 * Helper for TempUserConfig representing string patterns with "$1" indicating
12 * variable substitution.
13 *
14 * @internal
15 */
16class Pattern implements Stringable {
17    /** @var string */
18    private $debugName;
19    /** @var string */
20    private $pattern;
21    /** @var string */
22    private $prefix;
23    /** @var string */
24    private $suffix;
25
26    /**
27     * @param string $debugName The name of the pattern, for use in error messages
28     * @param string $pattern The pattern itself
29     */
30    public function __construct( string $debugName, string $pattern ) {
31        $this->debugName = $debugName;
32        $this->pattern = $pattern;
33    }
34
35    /**
36     * Does the pattern match the given name?
37     * @param string $name
38     * @return bool
39     */
40    public function isMatch( string $name ) {
41        $this->init();
42        $match = true;
43        if ( $this->prefix !== '' ) {
44            $match = str_starts_with( $name, $this->prefix );
45        }
46        if ( $match && $this->suffix !== '' ) {
47            $match = str_ends_with( $name, $this->suffix )
48                && strlen( $name ) >= strlen( $this->prefix ) + strlen( $this->suffix );
49        }
50        return $match;
51    }
52
53    /**
54     * Substitute the serial number into the pattern.
55     *
56     * @param string $mappedSerial
57     * @param ?string $year
58     * @return string
59     */
60    public function generate( $mappedSerial, ?string $year = null ) {
61        $this->init();
62        return $this->prefix .
63            ( $year ? $year . '-' : '' ) .
64            $mappedSerial .
65            $this->suffix;
66    }
67
68    /**
69     * Convert the pattern to an SQL like clause
70     *
71     * @deprecated since 1.42. Use toLikeValue() instead
72     * @param ISQLPlatform $db
73     * @return string
74     */
75    public function buildLike( ISQLPlatform $db ) {
76        wfDeprecated( __METHOD__, '1.42' );
77        $this->init();
78        return $db->buildLike(
79            $this->prefix,
80            $db->anyString(),
81            $this->suffix
82        );
83    }
84
85    /**
86     * Convert the pattern to an SQL builder "LIKE" value that matches it
87     *
88     * @param ISQLPlatform $db
89     * @return LikeValue
90     */
91    public function toLikeValue( ISQLPlatform $db ): LikeValue {
92        $this->init();
93        return new LikeValue(
94            $this->prefix,
95            $db->anyString(),
96            $this->suffix
97        );
98    }
99
100    /**
101     * Extract the variable part of the string (matching $1 or YYYY-$1),
102     * or null if there is no match
103     *
104     * @param string $name
105     * @return ?string
106     */
107    public function extract( string $name ) {
108        if ( $this->isMatch( $name ) ) {
109            return substr( $name,
110                strlen( $this->prefix ),
111                strlen( $name ) - strlen( $this->prefix ) - strlen( $this->suffix ) );
112        }
113        return null;
114    }
115
116    /**
117     * Initialise the prefix and suffix
118     */
119    private function init() {
120        if ( $this->prefix === null ) {
121            $varPos = strpos( $this->pattern, '$1' );
122            if ( $varPos === false ) {
123                throw new UnexpectedValueException( __CLASS__ .
124                    "pattern {$this->debugName} must be of the form \"prefix \$1 suffix\"" );
125            }
126            $this->prefix = substr( $this->pattern, 0, $varPos );
127            $this->suffix = substr( $this->pattern, $varPos + strlen( '$1' ) );
128        }
129    }
130
131    public function __toString() {
132        return $this->pattern;
133    }
134}