Passed
Push — master ( 021966...b0a157 )
by Aimeos
04:52
created

Utils::language()   A

Complexity

Conditions 6
Paths 5

Size

Total Lines 23
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 11
c 1
b 0
f 0
dl 0
loc 23
rs 9.2222
cc 6
nc 5
nop 2
1
<?php
2
3
/**
4
 * @license LGPLv3, https://opensource.org/licenses/LGPL-3.0
5
 * @copyright Aimeos (aimeos.org), 2023-2024
6
 */
7
8
9
namespace Aimeos;
10
11
12
/**
13
 * Utility methods
14
 */
15
class Utils
16
{
17
	/**
18
	 * Creates a new object instance
19
	 *
20
	 * @param string $class Name of the class
21
	 * @param array $args Constructor arguments
22
	 * @param string|null $iface Name of the interface the object must implement
23
	 * @return object New object instance
24
	 * @throws \LogicException If the class isn't found or doesn't implement the interface
25
	 * @todo 2025.01 Allow list of interfaces to check for common and specific interfaces
26
	 */
27
	public static function create( string $class, array $args, string $iface = null ) : object
28
	{
29
		if( class_exists( $class ) === false ) {
30
			throw new \LogicException( sprintf( 'Class "%1$s" not found', $class ), 400 );
31
		}
32
33
		$object = new $class( ...$args );
34
35
		if( $iface && !( $object instanceof $iface ) ) {
36
			throw new \LogicException( sprintf( 'Class "%1$s" does not implement "%2$s"', $class, $iface ), 400 );
37
		}
38
39
		return $object;
40
	}
41
42
43
	/**
44
	 * Tests if the code is valid.
45
	 *
46
	 * @param string $code New code for an item
47
	 * @param int $length Number of allowed characters
48
	 * @return string Item code
49
	 * @throws \RuntimeException If the code is invalid
50
	 */
51
	public static function code( string $code, int $length = 64 ) : string
52
	{
53
		if( strlen( $code ) > $length ) {
54
			throw new \RuntimeException( sprintf( 'Code is too long' ) );
55
		}
56
57
		if( preg_match( '/[ \x{0000}\x{0009}\x{000A}\x{000C}\x{000D}\x{0085}]+/u', $code ) === 1 ) {
58
			throw new \RuntimeException( sprintf( 'Code contains invalid characters: "%1$s"', $code ) );
59
		}
60
61
		return $code;
62
	}
63
64
65
	/**
66
	 * Tests if the country ID parameter represents an ISO country format.
67
	 *
68
	 * @param string|null $countryid Two letter ISO country format, e.g. DE
69
	 * @param bool $null True if null is allowed, false if not
70
	 * @return string|null Two letter ISO country ID or null for no country
71
	 * @throws \RuntimeException If the country ID is invalid
72
	 */
73
	public static function country( ?string $countryid, bool $null = true ) : ?string
74
	{
75
		if( $null === false && $countryid == null ) {
76
			throw new \RuntimeException( sprintf( 'Invalid ISO country code' ) );
77
		}
78
79
		if( $countryid != null )
80
		{
81
			if( preg_match( '/^[A-Za-z]{2}$/', $countryid ) !== 1 ) {
82
				throw new \RuntimeException( sprintf( 'Invalid ISO country code' ) );
83
			}
84
85
			return strtoupper( $countryid );
86
		}
87
88
		return null;
89
	}
90
91
92
	/**
93
	 * Tests if the currency ID parameter represents an ISO currency format.
94
	 *
95
	 * @param string|null $currencyid Three letter ISO currency format, e.g. EUR
96
	 * @param bool $null True if null is allowed, false if not
97
	 * @return string|null Three letter ISO currency ID or null for no currency
98
	 * @throws \RuntimeException If the currency ID is invalid
99
	 */
100
	public static function currency( ?string $currencyid, bool $null = true ) : ?string
101
	{
102
		if( $null === false && $currencyid == null ) {
103
			throw new \RuntimeException( sprintf( 'Invalid ISO currency code' ) );
104
		}
105
106
		if( $currencyid != null )
107
		{
108
			if( preg_match( '/^[A-Za-z]{3}$/', $currencyid ) !== 1 ) {
109
				throw new \RuntimeException( sprintf( 'Invalid ISO currency code' ) );
110
			}
111
112
			return strtoupper( $currencyid );
113
		}
114
115
		return null;
116
	}
117
118
119
	/**
120
	 * Tests if the date param represents an ISO format.
121
	 *
122
	 * @param string|null $date ISO date in YYYY-MM-DD format or null for no date
123
	 */
124
	public static function date( ?string $date ) : ?string
125
	{
126
		if( $date !== null && $date !== '' )
127
		{
128
			if( preg_match( '/^[0-9]{4}-[0-1][0-9]-[0-3][0-9]$/', (string) $date ) !== 1 ) {
129
				throw new \RuntimeException( sprintf( 'Invalid characters in date, ISO format "YYYY-MM-DD" expected' ) );
130
			}
131
132
			return (string) $date;
133
		}
134
135
		return null;
136
	}
137
138
139
	/**
140
	 * Tests if the date parameter represents an ISO format.
141
	 *
142
	 * @param string|null $date ISO date in yyyy-mm-dd HH:ii:ss format or null
143
	 * @return string|null Clean date or null for no date
144
	 * @throws \RuntimeException If the date is invalid
145
	 */
146
	public static function datetime( ?string $date ) : ?string
147
	{
148
		$regex = '/^[0-9]{4}-[0-1][0-9]-[0-3][0-9](( |T)[0-2][0-9]:[0-5][0-9](:[0-5][0-9])?)?$/';
149
150
		if( $date != null )
151
		{
152
			if( preg_match( $regex, (string) $date ) !== 1 ) {
153
				throw new \RuntimeException( sprintf( 'Invalid characters in date, ISO format "YYYY-MM-DD hh:mm:ss" expected' ) );
154
			}
155
156
			if( strlen( $date ) === 16 ) {
157
				$date .= ':00';
158
			}
159
160
			return str_replace( 'T', ' ', (string) $date );
161
		}
162
163
		return null;
164
	}
165
166
167
	/**
168
	 * Checks if the object implements the given interface
169
	 *
170
	 * @param object $object Object to check
171
	 * @param string $iface Name of the interface the object must implement
172
	 * @return object Same object as passed in
173
	 * @throws \LogicException If the object doesn't implement the interface
174
	 * @todo 2025.01 Allow list of interfaces to check for common and specific interfaces
175
	 */
176
	public static function implements( object $object, string $iface ) : object
177
	{
178
		if( !( $object instanceof $iface ) ) {
179
			throw new \LogicException( sprintf( 'Class "%1$s" does not implement "%2$s"', get_class( $object ), $iface ), 400 );
180
		}
181
182
		return $object;
183
	}
184
185
186
	/**
187
	 * Tests if the language ID parameter represents an ISO language format.
188
	 *
189
	 * @param string|null $langid ISO language format, e.g. de or de_DE
190
	 * @param bool $null True if null is allowed, false if not
191
	 * @return string|null ISO language ID or null for no language
192
	 * @throws \RuntimeException If the language ID is invalid
193
	 */
194
	public static function language( ?string $langid, bool $null = true ) : ?string
195
	{
196
		if( $null === false && $langid == null ) {
197
			throw new \RuntimeException( sprintf( 'Invalid ISO language code' ) );
198
		}
199
200
		if( $langid != null )
201
		{
202
			if( preg_match( '/^[a-zA-Z]{2}(_[a-zA-Z]{2})?$/', $langid ) !== 1 ) {
203
				throw new \RuntimeException( sprintf( 'Invalid ISO language code' ) );
204
			}
205
206
			$parts = explode( '_', $langid );
207
			$parts[0] = strtolower( $parts[0] );
208
209
			if( isset( $parts[1] ) ) {
210
				$parts[1] = strtoupper( $parts[1] );
211
			}
212
213
			return implode( '_', $parts );
214
		}
215
216
		return null;
217
	}
218
}
219