Skip to content

Commit d913107

Browse files
committed
Update Implementation to comply to ICU
1 parent 848bc23 commit d913107

File tree

4 files changed

+39
-60
lines changed

4 files changed

+39
-60
lines changed

src/IdnaResult.php renamed to src/IdnaInfo.php

Lines changed: 19 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,15 @@
55
namespace Pdp;
66

77
use function array_filter;
8-
use function array_keys;
9-
use function array_reduce;
108
use const ARRAY_FILTER_USE_KEY;
119

12-
final class IdnaResult
10+
/**
11+
* @see https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/uidna_8h.html
12+
*/
13+
final class IdnaInfo
1314
{
1415
/**
1516
* IDNA errors.
16-
*
17-
* @see https://unicode-org.github.io/icu-docs/apidoc/dev/icu4j/
1817
*/
1918
public const ERROR_EMPTY_LABEL = 1;
2019
public const ERROR_LABEL_TOO_LONG = 2;
@@ -54,18 +53,12 @@ final class IdnaResult
5453

5554
private bool $isTransitionalDifferent;
5655

57-
/**
58-
* @var array<int, string>
59-
*/
60-
private array $errors;
56+
private int $errors;
6157

62-
/**
63-
* @param array<int, string> $error
64-
*/
65-
private function __construct(string $result, bool $isTransitionalDifferent, array $error)
58+
private function __construct(string $result, bool $isTransitionalDifferent, int $errors)
6659
{
6760
$this->result = $result;
68-
$this->errors = $error;
61+
$this->errors = $errors;
6962
$this->isTransitionalDifferent = $isTransitionalDifferent;
7063
}
7164

@@ -74,23 +67,15 @@ private function __construct(string $result, bool $isTransitionalDifferent, arra
7467
*/
7568
public static function fromIntl(array $infos): self
7669
{
77-
return new self(
78-
$infos['result'],
79-
$infos['isTransitionalDifferent'],
80-
array_filter(
81-
self::ERRORS,
82-
fn (int $errorByte): bool => 0 !== ($errorByte & $infos['errors']),
83-
ARRAY_FILTER_USE_KEY
84-
)
85-
);
70+
return new self($infos['result'], $infos['isTransitionalDifferent'], $infos['errors']);
8671
}
8772

8873
/**
89-
* @param array{result:string, isTransitionalDifferent:bool, errors:array<int, string>} $properties
74+
* @param array{result:string, isTransitionalDifferent:bool, errors:int} $properties
9075
*/
9176
public static function __set_state(array $properties): self
9277
{
93-
return new self($properties['result'], $properties['isTransitionalDifferent'], $properties['errors']);
78+
return self::fromIntl($properties);
9479
}
9580

9681
public function result(): string
@@ -103,32 +88,25 @@ public function isTransitionalDifferent(): bool
10388
return $this->isTransitionalDifferent;
10489
}
10590

106-
/**
107-
* @return array<int, string>
108-
*/
109-
public function errors(): array
91+
public function errors(): int
11092
{
11193
return $this->errors;
11294
}
11395

11496
public function error(int $error): ?string
11597
{
116-
return $this->errors[$error] ?? null;
98+
return 0 === ($this->errors & $error) ? null : self::ERRORS[$error];
11799
}
118100

119101
/**
120-
* @return array{result:string, isTransitionalDifferent:bool, errors:int}
102+
* @return array<int, string>
121103
*/
122-
public function toIntl(): array
104+
public function errorList(): array
123105
{
124-
return [
125-
'result' => $this->result,
126-
'isTransitionalDifferent' => $this->isTransitionalDifferent,
127-
'errors' => array_reduce(
128-
array_keys($this->errors),
129-
fn (int $curry, int $errorByte): int => $curry | $errorByte,
130-
0
131-
),
132-
];
106+
return array_filter(
107+
self::ERRORS,
108+
fn (int $errorByte): bool => 0 !== ($errorByte & $this->errors),
109+
ARRAY_FILTER_USE_KEY
110+
);
133111
}
134112
}

src/IdnaResultTest.php renamed to src/IdnaInfoTest.php

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,27 @@
77
use PHPUnit\Framework\TestCase;
88
use function var_export;
99

10-
final class IdnaResultTest extends TestCase
10+
final class IdnaInfoTest extends TestCase
1111
{
1212
public function testDomainInternalPhpMethod(): void
1313
{
1414
$infos = ['result' => 'foo.bar', 'isTransitionalDifferent' => false, 'errors' => 0];
15-
$result = IdnaResult::fromIntl($infos);
15+
$result = IdnaInfo::fromIntl($infos);
1616
$generateResult = eval('return '.var_export($result, true).';');
1717

1818
self::assertEquals($result, $generateResult);
19-
self::assertSame($infos, $generateResult->toIntl());
2019
}
2120

2221
public function testItCanBeInstantiatedFromArray(): void
2322
{
2423
$infos = ['result' => '', 'isTransitionalDifferent' => false, 'errors' => 0];
25-
$result = IdnaResult::fromIntl($infos);
24+
$result = IdnaInfo::fromIntl($infos);
2625

2726
self::assertSame('', $result->result());
2827
self::assertFalse($result->isTransitionalDifferent());
29-
self::assertCount(0, $result->errors());
30-
self::assertNull($result->error(IdnaResult::ERROR_BIDI));
28+
self::assertSame(0, $result->errors());
29+
self::assertNull($result->error(IdnaInfo::ERROR_BIDI));
30+
self::assertCount(0, $result->errorList());
3131
}
3232

3333
public function testInvalidSyntaxAfterIDNConversion(): void
@@ -36,9 +36,10 @@ public function testInvalidSyntaxAfterIDNConversion(): void
3636
IntlIdna::toAscii('%00.com', IntlIdna::IDNA2008_ASCII);
3737
} catch (SyntaxError $exception) {
3838
$result = $exception->fetchIdnaResult();
39-
self::assertInstanceOf(IdnaResult::class, $result);
40-
self::assertCount(1, $result->errors());
41-
self::assertNotEmpty($result->error(IdnaResult::ERROR_DISALLOWED));
39+
self::assertInstanceOf(IdnaInfo::class, $result);
40+
self::assertSame(IdnaInfo::ERROR_DISALLOWED, $result->errors());
41+
self::assertIsString($result->error(IdnaInfo::ERROR_DISALLOWED));
42+
self::assertCount(1, $result->errorList());
4243
}
4344
}
4445
}

src/IntlIdna.php

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,11 @@ final class IntlIdna
4242
*
4343
* @throws SyntaxError if the string can not be converted to ASCII using IDN UTS46 algorithm
4444
*/
45-
public static function toAscii(string $domain, int $option): IdnaResult
45+
public static function toAscii(string $domain, int $option): IdnaInfo
4646
{
4747
$domain = rawurldecode($domain);
4848
if (1 !== preg_match(self::REGEXP_IDNA_PATTERN, $domain)) {
49-
return IdnaResult::fromIntl([
49+
return IdnaInfo::fromIntl([
5050
'result' => strtolower($domain),
5151
'isTransitionalDifferent' => false,
5252
'errors' => 0,
@@ -65,10 +65,10 @@ public static function toAscii(string $domain, int $option): IdnaResult
6565
*
6666
* @throws SyntaxError if the string can not be converted to UNICODE using IDN UTS46 algorithm
6767
*/
68-
public static function toUnicode(string $domain, int $option): IdnaResult
68+
public static function toUnicode(string $domain, int $option): IdnaInfo
6969
{
7070
if (false === strpos($domain, 'xn--')) {
71-
return IdnaResult::fromIntl([
71+
return IdnaInfo::fromIntl([
7272
'result' => $domain,
7373
'isTransitionalDifferent' => false,
7474
'errors' => 0,
@@ -83,10 +83,10 @@ public static function toUnicode(string $domain, int $option): IdnaResult
8383
/**
8484
* @param array{result:string, isTransitionalDifferent:bool, errors:int} $infos
8585
*/
86-
private static function createIdnaResult(string $domain, array $infos): IdnaResult
86+
private static function createIdnaResult(string $domain, array $infos): IdnaInfo
8787
{
88-
$result = IdnaResult::fromIntl($infos);
89-
if ([] !== $result->errors()) {
88+
$result = IdnaInfo::fromIntl($infos);
89+
if (0 !== $result->errors()) {
9090
throw SyntaxError::dueToIDNAError($domain, $result);
9191
}
9292

src/SyntaxError.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88

99
class SyntaxError extends InvalidArgumentException implements CannotProcessHost
1010
{
11-
private ?IdnaResult $idnaResult;
11+
private ?IdnaInfo $idnaResult;
1212

13-
public function fetchIdnaResult(): ?IdnaResult
13+
public function fetchIdnaResult(): ?IdnaInfo
1414
{
1515
return $this->idnaResult;
1616
}
@@ -25,7 +25,7 @@ public static function dueToInvalidLength(string $domain): self
2525
return new self('The host `'.$domain.'` is invalid: its length is longer than 255 bytes in its storage form.');
2626
}
2727

28-
public static function dueToIDNAError(string $domain, IdnaResult $result): self
28+
public static function dueToIDNAError(string $domain, IdnaInfo $result): self
2929
{
3030
$exception = new self('The host `'.$domain.'` is invalid for IDN conversion.');
3131
$exception->idnaResult = $result;

0 commit comments

Comments
 (0)