Completed
Push — master ( b23c5f...0489e6 )
by Jan-Petter
02:23
created

UserAgentParser::render()   B

Complexity

Conditions 4
Paths 6

Size

Total Lines 28
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
c 4
b 0
f 0
dl 0
loc 28
rs 8.5806
cc 4
eloc 22
nc 6
nop 0
1
<?php
2
namespace vipnytt\RobotsTxtParser\Parser\Directives;
3
4
use vipnytt\RobotsTxtParser\Client\Directives\UserAgentClient;
5
use vipnytt\RobotsTxtParser\RobotsTxtInterface;
6
use vipnytt\UserAgentParser as UAStringParser;
7
8
/**
9
 * Class UserAgentParser
10
 *
11
 * @package vipnytt\RobotsTxtParser\Parser\Directives
12
 */
13
class UserAgentParser implements ParserInterface, RobotsTxtInterface
14
{
15
    use DirectiveParserCommons;
16
17
    /**
18
     * Sub directives white list
19
     */
20
    const SUB_DIRECTIVES = [
21
        self::DIRECTIVE_ALLOW => 'allow',
22
        self::DIRECTIVE_CACHE_DELAY => 'cacheDelay',
23
        self::DIRECTIVE_COMMENT => 'comment',
24
        self::DIRECTIVE_CRAWL_DELAY => 'crawlDelay',
25
        self::DIRECTIVE_DISALLOW => 'disallow',
26
        self::DIRECTIVE_REQUEST_RATE => 'requestRate',
27
        self::DIRECTIVE_ROBOT_VERSION => 'robotVersion',
28
        self::DIRECTIVE_VISIT_TIME => 'visitTime',
29
    ];
30
31
    /**
32
     * Base uri
33
     * @var string
34
     */
35
    private $base;
36
37
    /**
38
     * User-agent handler
39
     * @var SubDirectiveHandler[]
40
     */
41
    private $handler = [];
42
43
    /**
44
     * Current User-agent(s)
45
     * @var string[]
46
     */
47
    private $current = [];
48
49
    /**
50
     * Append User-agent
51
     * @var bool
52
     */
53
    private $append = false;
54
55
    /**
56
     * User-agent directive count
57
     * @var int[]
58
     */
59
    private $count = [];
60
61
    /**
62
     * User-agent client cache
63
     * @var UserAgentClient[]
64
     */
65
    private $client = [];
66
67
    /**
68
     * UserAgent constructor.
69
     *
70
     * @param string $base
71
     */
72
    public function __construct($base)
73
    {
74
        $this->base = $base;
75
        $this->set(self::USER_AGENT);
76
        $this->append = false;
77
    }
78
79
    /**
80
     * Set new User-agent
81
     *
82
     * @param string $userAgent
83
     * @return bool
84
     */
85
    private function set($userAgent)
86
    {
87
        if (!$this->append) {
88
            $this->current = [];
89
        }
90
        if (in_array(self::USER_AGENT, $this->current)) {
91
            $this->current = [];
92
            $userAgent = self::USER_AGENT;
93
        }
94
        $userAgent = mb_strtolower($userAgent);
95
        $this->current[] = $userAgent;
96
        if (!in_array($userAgent, array_keys($this->handler))) {
97
            $this->handler[$userAgent] = new SubDirectiveHandler($this->base, $userAgent);
98
            $this->count[$userAgent] = 0;
99
        }
100
        $this->append = true;
101
        return true;
102
    }
103
104
    /**
105
     * Add
106
     *
107
     * @param string $line
108
     * @return bool
109
     */
110
    public function add($line)
111
    {
112
        if (($pair = $this->generateRulePair($line, array_merge(array_keys(self::SUB_DIRECTIVES), [self::DIRECTIVE_USER_AGENT]))) === false) {
113
            $this->append = false;
114
            return false;
115
        }
116
        if ($pair['directive'] === self::DIRECTIVE_USER_AGENT) {
117
            return $this->set($pair['value']);
118
        }
119
        $this->append = false;
120
        $result = [];
121
        foreach ($this->current as $userAgent) {
122
            $result[] = $this->handler[$userAgent]->{self::SUB_DIRECTIVES[$pair['directive']]}()->add($pair['value']);
123
            $this->count[$userAgent]++;
124
        }
125
        return in_array(true, $result, true);
126
    }
127
128
    /**
129
     * Render
130
     *
131
     * @return string[]
132
     */
133
    public function render()
134
    {
135
        $userAgents = $this->getUserAgents();
136
        $pair = [];
137
        foreach ($userAgents as $userAgent) {
138
            $pair[$userAgent] = array_merge(
139
                $this->handler[$userAgent]->robotVersion()->render(),
140
                $this->handler[$userAgent]->visitTime()->render(),
141
                $this->handler[$userAgent]->disallow()->render(),
142
                $this->handler[$userAgent]->allow()->render(),
143
                $this->handler[$userAgent]->crawlDelay()->render(),
144
                $this->handler[$userAgent]->cacheDelay()->render(),
145
                $this->handler[$userAgent]->requestRate()->render(),
146
                $this->handler[$userAgent]->comment()->render()
147
            );
148
        }
149
        $pair = array_filter($pair);
150
        $result = [];
151
        while (!empty($pair)) {
152
            $groupMembers = current($pair);
153
            foreach (array_keys($pair, $groupMembers) as $userAgent) {
154
                $result[] = self::DIRECTIVE_USER_AGENT . ':' . $userAgent;
155
                unset($pair[$userAgent]);
156
            }
157
            $result = array_merge($result, $groupMembers);
158
        }
159
        return $result;
160
    }
161
162
    /**
163
     * User-agent list
164
     *
165
     * @return string[]
166
     */
167
    public function getUserAgents()
168
    {
169
        $list = array_keys(array_filter($this->count));
170
        sort($list);
171
        return $list;
172
    }
173
174
    /**
175
     * Export
176
     *
177
     * @return array
178
     */
179
    public function export()
180
    {
181
        $array = [];
182
        foreach ($this->getUserAgents() as $userAgent) {
183
            $array[$userAgent] = $this->client($userAgent)->export();
184
        }
185
        return $array;
186
    }
187
188
    /**
189
     * Client
190
     *
191
     * @param string $userAgent
192
     * @param int|null $statusCode
193
     * @return UserAgentClient
194
     */
195
    public function client($userAgent = self::USER_AGENT, $statusCode = null)
196
    {
197
        if (isset($this->client[$userAgent])) {
198
            return $this->client[$userAgent];
199
        }
200
        $userAgent = mb_strtolower($userAgent);
201
        $userAgentParser = new UAStringParser($userAgent);
202
        if (($userAgentMatch = $userAgentParser->match($this->getUserAgents())) === false) {
203
            $userAgentMatch = self::USER_AGENT;
204
        }
205
        return $this->client[$userAgent] = new UserAgentClient($this->handler[$userAgentMatch], $this->base, $statusCode, $userAgent);
206
    }
207
}
208