Passed
Push — master ( d65c20...a7ba41 )
by Christian
02:11
created

Chain::withFirstResults()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 0
dl 0
loc 6
rs 10
c 0
b 0
f 0
1
<?php
2
namespace RemotelyLiving\PHPDNS\Resolvers;
3
4
use RemotelyLiving\PHPDNS\Entities\DNSRecord;
5
use RemotelyLiving\PHPDNS\Entities\DNSRecordCollection;
6
use RemotelyLiving\PHPDNS\Entities\DNSRecordType;
7
use RemotelyLiving\PHPDNS\Entities\Hostname;
8
use RemotelyLiving\PHPDNS\Observability\Interfaces\Observable;
9
use RemotelyLiving\PHPDNS\Resolvers\Exceptions\QueryFailure;
10
use RemotelyLiving\PHPDNS\Resolvers\Interfaces;
11
use RemotelyLiving\PHPDNS\Resolvers\Interfaces\Resolver;
12
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
13
14
class Chain extends ResolverAbstract implements Interfaces\Chain
15
{
16
    const STRATEGY_FIRST_TO_FIND = 0;
17
    const STRATEGY_ALL_RESULTS = 1;
18
    const STRATEGY_CONSENSUS = 2;
19
20
    /**
21
     * @var \RemotelyLiving\PHPDNS\Resolvers\Interfaces\Resolver[]
22
     */
23
    private $resolvers;
24
25
    /**
26
     * @var int
27
     */
28
    private $callThroughStrategy = self::STRATEGY_FIRST_TO_FIND;
29
30
    public function __construct(array $resolvers = [])
31
    {
32
        foreach ($resolvers as $resolver) {
33
            $this->pushResolver($resolver);
34
        }
35
    }
36
37
    public function pushResolver(Resolver...$resolvers): void
38
    {
39
        foreach ($resolvers as $resolver) {
40
            $this->resolvers[] = $resolver;
41
        }
42
    }
43
44
    public function withAllResults(): Interfaces\Chain
45
    {
46
        $all = new self($this->resolvers);
47
        $all->callThroughStrategy = self::STRATEGY_ALL_RESULTS;
48
49
        return $all;
50
    }
51
52
    public function withFirstResults(): Interfaces\Chain
53
    {
54
        $first = new self($this->resolvers);
55
        $first->callThroughStrategy = self::STRATEGY_FIRST_TO_FIND;
56
57
        return $first;
58
    }
59
60
    public function withConsensusResults(): Interfaces\Chain
61
    {
62
        $consensus = new self($this->resolvers);
63
        $consensus->callThroughStrategy = self::STRATEGY_CONSENSUS;
64
65
        return $consensus;
66
    }
67
68
    public function randomly(): Interfaces\Chain
69
    {
70
        $randomized = clone $this;
71
        shuffle($randomized->resolvers);
72
73
        return $randomized;
74
    }
75
76
    public function addSubscriber(EventSubscriberInterface $subscriber): void
77
    {
78
        foreach ($this->resolvers as $resolver) {
79
            if ($resolver instanceof Observable) {
80
                $resolver->addSubscriber($subscriber);
81
            }
82
        }
83
    }
84
85
    public function addListener(string $eventName, callable $listener, int $priority = 0): void
86
    {
87
        foreach ($this->resolvers as $resolver) {
88
            if ($resolver instanceof Observable) {
89
                $resolver->addListener($eventName, $listener, $priority);
90
            }
91
        }
92
    }
93
94
    public function hasRecord(DNSRecord $record): bool
95
    {
96
        foreach ($this->resolvers as $resolver) {
97
            if ($resolver->hasRecord($record)) {
98
                return true;
99
            }
100
        }
101
102
        return false;
103
    }
104
105
    protected function doQuery(Hostname $hostname, DNSRecordType $recordType): DNSRecordCollection
106
    {
107
        $merged = [];
108
109
        foreach ($this->resolvers as $resolver) {
110
            try {
111
                $records = $resolver->getRecords($hostname, $recordType);
112
            } catch (QueryFailure $e) {
113
                continue;
114
            }
115
116
            if ($this->callThroughStrategy === self::STRATEGY_FIRST_TO_FIND && !$records->isEmpty()) {
117
                return $records;
118
            }
119
120
            /** @var DNSRecord $record */
121
            foreach ($records as $record) {
122
                $merged[] = $record;
123
            }
124
        }
125
126
        $collection = new DNSRecordCollection(...$merged);
127
128
        return ($this->callThroughStrategy === self::STRATEGY_CONSENSUS)
129
            ? $collection->withUniqueValuesExcluded()
130
            : $collection->withUniqueValues();
131
    }
132
}
133