aboutsummaryrefslogtreecommitdiffstats
path: root/includes/user/TempUser/Pattern.php
blob: 99b9bf77f10237fdaa686b6cabdf12dc20773ed8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
<?php

namespace MediaWiki\User\TempUser;

use Stringable;
use UnexpectedValueException;
use Wikimedia\Rdbms\LikeValue;
use Wikimedia\Rdbms\Platform\ISQLPlatform;

/**
 * Helper for TempUserConfig representing string patterns with "$1" indicating
 * variable substitution.
 *
 * @internal
 */
class Pattern implements Stringable {
	/** @var string */
	private $debugName;
	/** @var string */
	private $pattern;
	/** @var string */
	private $prefix;
	/** @var string */
	private $suffix;

	/**
	 * @param string $debugName The name of the pattern, for use in error messages
	 * @param string $pattern The pattern itself
	 */
	public function __construct( string $debugName, string $pattern ) {
		$this->debugName = $debugName;
		$this->pattern = $pattern;
	}

	/**
	 * Does the pattern match the given name?
	 * @param string $name
	 * @return bool
	 */
	public function isMatch( string $name ) {
		$this->init();
		$match = true;
		if ( $this->prefix !== '' ) {
			$match = str_starts_with( $name, $this->prefix );
		}
		if ( $match && $this->suffix !== '' ) {
			$match = str_ends_with( $name, $this->suffix )
				&& strlen( $name ) >= strlen( $this->prefix ) + strlen( $this->suffix );
		}
		return $match;
	}

	/**
	 * Substitute the serial number into the pattern.
	 *
	 * @param string $mappedSerial
	 * @param ?string $year
	 * @return string
	 */
	public function generate( $mappedSerial, ?string $year = null ) {
		$this->init();
		return $this->prefix .
			( $year ? $year . '-' : '' ) .
			$mappedSerial .
			$this->suffix;
	}

	/**
	 * Convert the pattern to an SQL like clause
	 *
	 * @deprecated since 1.42. Use toLikeValue() instead
	 * @param ISQLPlatform $db
	 * @return string
	 */
	public function buildLike( ISQLPlatform $db ) {
		wfDeprecated( __METHOD__, '1.42' );
		$this->init();
		return $db->buildLike(
			$this->prefix,
			$db->anyString(),
			$this->suffix
		);
	}

	/**
	 * Convert the pattern to an SQL builder "LIKE" value that matches it
	 *
	 * @param ISQLPlatform $db
	 * @return LikeValue
	 */
	public function toLikeValue( ISQLPlatform $db ): LikeValue {
		$this->init();
		return new LikeValue(
			$this->prefix,
			$db->anyString(),
			$this->suffix
		);
	}

	/**
	 * Extract the variable part of the string (matching $1 or YYYY-$1),
	 * or null if there is no match
	 *
	 * @param string $name
	 * @return ?string
	 */
	public function extract( string $name ) {
		if ( $this->isMatch( $name ) ) {
			return substr( $name,
				strlen( $this->prefix ),
				strlen( $name ) - strlen( $this->prefix ) - strlen( $this->suffix ) );
		}
		return null;
	}

	/**
	 * Initialise the prefix and suffix
	 */
	private function init() {
		if ( $this->prefix === null ) {
			$varPos = strpos( $this->pattern, '$1' );
			if ( $varPos === false ) {
				throw new UnexpectedValueException( __CLASS__ .
					"pattern {$this->debugName} must be of the form \"prefix \$1 suffix\"" );
			}
			$this->prefix = substr( $this->pattern, 0, $varPos );
			$this->suffix = substr( $this->pattern, $varPos + strlen( '$1' ) );
		}
	}

	public function __toString() {
		return $this->pattern;
	}
}