Completed
Push — master ( c07126...706ec6 )
by Jan-Petter
04:09
created

AllowParser::removeOverlapping()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 15
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 1
Metric Value
c 1
b 1
f 1
dl 0
loc 15
rs 8.8571
cc 5
eloc 9
nc 4
nop 0
1
<?php
2
namespace vipnytt\RobotsTxtParser\Parser\Directives;
3
4
use vipnytt\RobotsTxtParser\Client\Directives\AllowClient;
5
use vipnytt\RobotsTxtParser\Exceptions;
6
use vipnytt\RobotsTxtParser\RobotsTxtInterface;
7
8
/**
9
 * Class AllowParser
10
 *
11
 * @package vipnytt\RobotsTxtParser\Parser\Directives
12
 */
13
class AllowParser implements ParserInterface, RobotsTxtInterface
14
{
15
    use DirectiveParserCommons;
16
17
    /**
18
     * Sub directives white list
19
     */
20
    const SUB_DIRECTIVES = [
21
        self::DIRECTIVE_CLEAN_PARAM,
22
        self::DIRECTIVE_HOST,
23
    ];
24
25
    /**
26
     * Directive
27
     * @var string
28
     */
29
    private $directive;
30
31
    /**
32
     * Path
33
     * @var array
34
     */
35
    private $path = [];
36
37
    /**
38
     * Sub-directive Clean-param
39
     * @var CleanParamParser
40
     */
41
    private $cleanParam;
42
43
    /**
44
     * Sub-directive Host
45
     * @var HostParser
46
     */
47
    private $host;
48
49
    /**
50
     * AllowParser constructor
51
     *
52
     * @param string $base
53
     * @param string $effective
54
     * @param string $directive
55
     */
56
    public function __construct($base, $effective, $directive)
57
    {
58
        $this->directive = $directive;
59
        $this->cleanParam = new CleanParamParser();
60
        $this->host = new HostParser($base, $effective, $this->directive);
61
    }
62
63
    /**
64
     * Add
65
     *
66
     * @param string $line
67
     * @return bool
68
     */
69
    public function add($line)
70
    {
71
        $pair = $this->generateRulePair($line, self::SUB_DIRECTIVES);
72
        switch ($pair['directive']) {
73
            case self::DIRECTIVE_CLEAN_PARAM:
74
                return $this->cleanParam->add($pair['value']);
75
            case self::DIRECTIVE_HOST:
76
                return $this->host->add($pair['value']);
77
        }
78
        return $this->addPath($line);
79
    }
80
81
    /**
82
     * Add plain path to allow/disallow
83
     *
84
     * @param string $path
85
     * @return bool
86
     */
87
    private function addPath($path)
88
    {
89
        foreach ([
90
                     $path,
91
                     '/',
92
                     '*',
93
                 ] as $testPath) {
94
            if (in_array($testPath, $this->path)) {
95
                return false;
96
            }
97
        }
98
        if ($this->isPath($path)) {
99
            $this->path[] = $path;
100
            $this->removeOverlapping();
101
        }
102
        return in_array($path, $this->path);
103
    }
104
105
    /**
106
     * Check if path is valid
107
     *
108
     * @param string $path
109
     * @return bool
110
     */
111
    private function isPath($path)
112
    {
113
        if (mb_strpos($path, '/') !== 0) {
114
            foreach (
115
                [
116
                    '*',
117
                    '?',
118
                ] as $char) {
119
                $path = str_replace($char, '/', $path);
120
            }
121
        }
122
        return mb_strpos($path, '/') === 0;
123
    }
124
125
    /**
126
     * Remove overlapping paths
127
     *
128
     * @return bool
129
     */
130
    private function removeOverlapping()
131
    {
132
        foreach ($this->path as $key1 => $path1) {
133
            foreach ($this->path as $key2 => $path2) {
134
                if (
135
                    $key1 !== $key2 &&
136
                    mb_strpos($path1, $path2) === 0
137
                ) {
138
                    unset($this->path[$key1]);
139
                    return $this->removeOverlapping();
140
                }
141
            }
142
        }
143
        return true;
144
    }
145
146
    /**
147
     * Render
148
     *
149
     * @return string[]
150
     */
151
    public function render()
152
    {
153
        $result = [];
154
        foreach (
155
            [
156
                $this->host->render(),
157
                $this->path,
158
                $this->cleanParam->render(),
159
            ] as $values
160
        ) {
161
            sort($values);
162
            foreach ($values as $value) {
163
                $result[] = $this->directive . ':' . $value;
164
            }
165
        }
166
        return $result;
167
    }
168
169
    /**
170
     * Client
171
     *
172
     * @return AllowClient
173
     */
174
    public function client()
175
    {
176
        return new AllowClient($this->path, $this->host->client(), $this->cleanParam->client());
177
    }
178
}
179