Completed
Push — master ( 0591fe...b215f8 )
by Jan-Petter
03:21
created

AllowParser::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

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