Completed
Push — master ( bf3f49...eab63b )
by Christian
03:22
created

Chain::setLogger()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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