Skip to content

Commit 219b379

Browse files
committed
Improve Domain modification methods
Domain::withLabel now accepts a domain Domain::withoutLabels now accept an optional variadic argument to ease usage
1 parent 8afba51 commit 219b379

File tree

4 files changed

+75
-36
lines changed

4 files changed

+75
-36
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ All Notable changes to `PHP Domain Parser` **5.x** series will be documented in
1212
- `Pdp\Domain::withPublicSuffix` updates the `Pdp\Domain` public suffix part.
1313
- `Pdp\Domain::withSubDomain` updates the `Pdp\Domain` sub domain part.
1414
- `Pdp\Domain::withLabel` adds a new label to the `Pdp\Domain`.
15-
- `Pdp\Domain::withoutLabel` removes a label from the `Pdp\Domain`.
15+
- `Pdp\Domain::withoutLabels` removes labels from the `Pdp\Domain`.
1616
- `Pdp\Domain::resolve` attach a public suffix to the `Pdp\Domain`.
1717
- `Pdp\Domain::isResolvable` tells whether the current `Pdp\Domain` can have a public suffix attached to it or not.
1818
- `Pdp\PublicSuffix::createFromDomain` returns a new `Pdp\PublicSuffix` object from a `Pdp\Domain`object

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ public function Domain::toUnicode(): self
113113
public function Domain::withPublicSuffix($publicSuffix): self
114114
public function Domain::withSubDomain($subDomain): self
115115
public function Domain::withLabel(int $key, $label): self
116-
public function Domain::withoutLabel(int $key): self
116+
public function Domain::withoutLabels(int $key, int ...$keys): self
117117
public function Domain::resolve($publicSuffix): self
118118
~~~
119119

src/Domain.php

Lines changed: 42 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
namespace Pdp;
1717

1818
use JsonSerializable;
19+
use TypeError;
1920

2021
/**
2122
* Domain Value Object.
@@ -428,14 +429,14 @@ public function resolve($publicSuffix): self
428429
*/
429430
public function withSubDomain($subDomain): self
430431
{
431-
if (!$subDomain instanceof PublicSuffix) {
432-
$subDomain = new PublicSuffix($subDomain);
433-
}
434-
435432
if (null === $this->publicSuffix->getContent()) {
436433
throw new Exception('A subdomain can not be added to a domain without a public suffix part.');
437434
}
438435

436+
if (!$subDomain instanceof PublicSuffix) {
437+
$subDomain = new PublicSuffix($subDomain);
438+
}
439+
439440
$subDomain = $this->normalize($subDomain);
440441
if ($this->subDomain === $subDomain->getContent()) {
441442
return $this;
@@ -497,12 +498,12 @@ public function withPublicSuffix($publicSuffix): self
497498
*/
498499
public function withLabel(int $key, $label): self
499500
{
500-
if (!$label instanceof Domain) {
501-
$label = new Domain($label);
501+
if (null === $label) {
502+
throw new TypeError('The label must be a scalar or a stringable object `NULL` given');
502503
}
503504

504-
if (1 != count($label)) {
505-
throw new Exception(sprintf('The label `%s` is invalid', (string) $label));
505+
if (!$label instanceof Domain) {
506+
$label = new Domain($label);
506507
}
507508

508509
$nb_labels = count($this->labels);
@@ -544,29 +545,49 @@ public function withLabel(int $key, $label): self
544545
* If $key is negative, the removed label will be the label at $key position from the end.
545546
*
546547
* @param int $key
548+
* @param int ...$keys remaining keys to remove
547549
*
548550
* @throws Exception If the key is out of bounds
549551
*
550552
* @return self
551553
*/
552-
public function withoutLabel(int $key): self
554+
public function withoutLabels(int $key, int ...$keys): self
553555
{
556+
array_unshift($keys, $key);
554557
$nb_labels = count($this->labels);
555-
$offset = filter_var($key, FILTER_VALIDATE_INT, ['options' => ['min_range' => - $nb_labels, 'max_range' => $nb_labels - 1]]);
556-
if (false === $offset) {
557-
throw new Exception(sprintf('the given key `%s` is invalid', $key));
558-
}
558+
$options = ['options' => ['min_range' => - $nb_labels, 'max_range' => $nb_labels - 1]];
559+
$mapper = function (int $key) use ($options, $nb_labels): int {
560+
if (false === ($offset = filter_var($key, FILTER_VALIDATE_INT, $options))) {
561+
throw new Exception(sprintf('the key `%s` is invalid', $key));
562+
}
559563

560-
if (0 > $offset) {
561-
$offset = $nb_labels + $offset;
564+
if (0 > $offset) {
565+
return $nb_labels + $offset;
566+
}
567+
568+
return $offset;
569+
};
570+
571+
$deleted_keys = array_keys(array_count_values(array_map($mapper, $keys)));
572+
573+
$filter = function ($key) use ($deleted_keys): bool {
574+
return !in_array($key, $deleted_keys, true);
575+
};
576+
577+
$labels = array_filter($this->labels, $filter, ARRAY_FILTER_USE_KEY);
578+
if (empty($labels)) {
579+
return new self();
562580
}
563581

564-
$labels = $this->labels;
565-
unset($labels[$offset]);
582+
$domain = implode('.', array_reverse(array_values($labels)));
583+
$publicSuffixContent = $this->publicSuffix->getContent();
566584

567-
return new self(
568-
implode('.', array_reverse(array_values($labels))),
569-
null === $this->publicSuffix->getLabel($offset) ? $this->publicSuffix : null
570-
);
585+
if (null === $publicSuffixContent ||
586+
'.'.$publicSuffixContent !== substr($domain, - strlen($publicSuffixContent) - 1)
587+
) {
588+
return new self($domain);
589+
}
590+
591+
return new self($domain, $this->publicSuffix);
571592
}
572593
}

tests/DomainTest.php

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use Pdp\PublicSuffix;
2121
use Pdp\Rules;
2222
use PHPUnit\Framework\TestCase;
23+
use TypeError;
2324

2425
/**
2526
* @coversDefaultClass Pdp\Domain
@@ -760,25 +761,34 @@ public function withLabelWorksProvider()
760761
'isICANN' => true,
761762
'isPrivate' => false,
762763
],
764+
'replace a domain with multiple label' => [
765+
'domain' => $base_domain,
766+
'key' => -1,
767+
'label' => 'www.shop',
768+
'expected' => 'www.shop.example.com',
769+
'isKnown' => true,
770+
'isICANN' => true,
771+
'isPrivate' => false,
772+
],
763773
];
764774
}
765775

766776
/**
767777
* @covers ::withLabel
768778
*/
769-
public function testWithLabelFailsWithInvalidKey()
779+
public function testWithLabelFailsWithTypeError()
770780
{
771-
$this->expectException(Exception::class);
772-
(new Domain('example.com'))->withLabel(-4, 'www');
781+
$this->expectException(TypeError::class);
782+
(new Domain('example.com'))->withLabel(-4, null);
773783
}
774784

775785
/**
776786
* @covers ::withLabel
777787
*/
778-
public function testWithLabelFailsWithInvalidLabel1()
788+
public function testWithLabelFailsWithInvalidKey()
779789
{
780790
$this->expectException(Exception::class);
781-
(new Domain('example.com'))->withLabel(-1, 'www.shop');
791+
(new Domain('example.com'))->withLabel(-4, 'www');
782792
}
783793

784794
/**
@@ -791,8 +801,8 @@ public function testWithLabelFailsWithInvalidLabel2()
791801
}
792802

793803
/**
794-
* @covers ::withoutLabel
795-
* @dataProvider withoutLabelWorksProvider
804+
* @covers ::withoutLabels
805+
* @dataProvider withoutLabelsWorksProvider
796806
*
797807
* @param Domain $domain
798808
* @param int $key
@@ -801,22 +811,22 @@ public function testWithLabelFailsWithInvalidLabel2()
801811
* @param bool $isICANN
802812
* @param bool $isPrivate
803813
*/
804-
public function testWithoutLabelWorks(
814+
public function testWithoutLabelsWorks(
805815
Domain $domain,
806816
int $key,
807817
$expected,
808818
bool $isKnown,
809819
bool $isICANN,
810820
bool $isPrivate
811821
) {
812-
$result = $domain->withoutLabel($key);
822+
$result = $domain->withoutLabels($key);
813823
$this->assertSame($expected, $result->getContent());
814824
$this->assertSame($isKnown, $result->isKnown());
815825
$this->assertSame($isICANN, $result->isICANN());
816826
$this->assertSame($isPrivate, $result->isPrivate());
817827
}
818828

819-
public function withoutLabelWorksProvider()
829+
public function withoutLabelsWorksProvider()
820830
{
821831
$base_domain = new Domain('www.example.com', new PublicSuffix('com', Rules::ICANN_DOMAINS));
822832

@@ -857,11 +867,19 @@ public function withoutLabelWorksProvider()
857867
}
858868

859869
/**
860-
* @covers ::withoutLabel
870+
* @covers ::withoutLabels
861871
*/
862-
public function testWithoutLabelFailsWithInvalidKey()
872+
public function testWithoutLabelsFailsWithInvalidKey()
863873
{
864874
$this->expectException(Exception::class);
865-
(new Domain('example.com'))->withoutLabel(-3);
875+
(new Domain('example.com'))->withoutLabels(-3);
876+
}
877+
878+
/**
879+
* @covers ::withoutLabels
880+
*/
881+
public function testWithoutLabelsWorksWithMultipleKeys()
882+
{
883+
$this->assertNull((new Domain('www.example.com'))->withoutLabels(0, 1, 2)->getContent());
866884
}
867885
}

0 commit comments

Comments
 (0)