1
|
|
|
<?php |
2
|
|
|
namespace vipnytt\RobotsTxtParser\Handler; |
3
|
|
|
|
4
|
|
|
use PDO; |
5
|
|
|
use vipnytt\RobotsTxtParser\Client; |
6
|
|
|
use vipnytt\RobotsTxtParser\Exceptions\SQLException; |
7
|
|
|
|
8
|
|
|
/** |
9
|
|
|
* Class DatabaseHandler |
10
|
|
|
* |
11
|
|
|
* @package vipnytt\RobotsTxtParser\Handler |
12
|
|
|
*/ |
13
|
|
|
final class DatabaseHandler |
14
|
|
|
{ |
15
|
|
|
/** |
16
|
|
|
* Cache table name |
17
|
|
|
*/ |
18
|
|
|
const TABLE_CACHE = 'robotstxt__cache1'; |
19
|
|
|
|
20
|
|
|
/** |
21
|
|
|
* Delay table name |
22
|
|
|
*/ |
23
|
|
|
const TABLE_DELAY = 'robotstxt__delay0'; |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* MySQL driver name |
27
|
|
|
*/ |
28
|
|
|
const DRIVER_MYSQL = 'mysql'; |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* Configuration data |
32
|
|
|
*/ |
33
|
|
|
private $config = [ |
34
|
|
|
null => [ // Class initialization |
35
|
|
|
self::DRIVER_MYSQL => [ |
36
|
|
|
'session_get' => 'SELECT @robotstxt;', |
37
|
|
|
'session_set' => 'SET @robotstxt = 1;', |
38
|
|
|
], |
39
|
|
|
], |
40
|
|
|
self::TABLE_CACHE => [ |
41
|
|
|
'readme' => 'https://github.com/VIPnytt/RobotsTxtParser/blob/master/docs/sql/cache.md', |
42
|
|
|
self::DRIVER_MYSQL => [ |
43
|
|
|
'file' => __DIR__ . '/../../res/Cache/MySQL.sql', |
44
|
|
|
'query' => 'SELECT 1 FROM robotstxt__cache1 LIMIT 1;', |
45
|
|
|
'session_get' => 'SELECT @robotstxt_cache;', |
46
|
|
|
'session_set' => 'SET @robotstxt_cache = 1;', |
47
|
|
|
], |
48
|
|
|
], |
49
|
|
|
self::TABLE_DELAY => [ |
50
|
|
|
'readme' => 'https://github.com/VIPnytt/RobotsTxtParser/blob/master/docs/sql/delay.md', |
51
|
|
|
self::DRIVER_MYSQL => [ |
52
|
|
|
'file' => __DIR__ . '/../../res/Delay/MySQL.sql', |
53
|
|
|
'query' => 'SELECT 1 FROM robotstxt__delay0 LIMIT 1;', |
54
|
|
|
'session_get' => 'SELECT @robotstxt_delay;', |
55
|
|
|
'session_set' => 'SET @robotstxt_delay = 1;', |
56
|
|
|
], |
57
|
|
|
] |
58
|
|
|
]; |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* Database handler |
62
|
|
|
* @var PDO |
63
|
|
|
*/ |
64
|
|
|
private $pdo; |
65
|
|
|
|
66
|
|
|
/** |
67
|
|
|
* Driver |
68
|
|
|
* @var string |
69
|
|
|
*/ |
70
|
|
|
private $driver; |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* Delay manager |
74
|
|
|
* @var Client\Delay\ManagerInterface |
75
|
|
|
*/ |
76
|
|
|
private $delayManager; |
77
|
|
|
|
78
|
|
|
/** |
79
|
|
|
* DriverHandler constructor. |
80
|
|
|
* |
81
|
|
|
* @param PDO $pdo |
82
|
|
|
*/ |
83
|
|
|
public function __construct(PDO $pdo) |
84
|
|
|
{ |
85
|
|
|
$this->pdo = $pdo; |
86
|
|
|
$this->driver = $this->pdo->getAttribute(PDO::ATTR_DRIVER_NAME); |
87
|
|
|
if (!$this->getSessionVar(null)) { |
88
|
|
|
if ($this->pdo->getAttribute(PDO::ATTR_ERRMODE) === PDO::ERRMODE_SILENT) { |
89
|
|
|
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING); |
90
|
|
|
} |
91
|
|
|
$this->pdo->setAttribute(PDO::ATTR_CASE, PDO::CASE_NATURAL); |
92
|
|
|
$this->pdo->setAttribute(PDO::ATTR_ORACLE_NULLS, PDO::NULL_NATURAL); |
93
|
|
|
$this->driverDependents(); |
94
|
|
|
$this->setSessionVar(null); |
95
|
|
|
} |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
/** |
99
|
|
|
* Get session variable |
100
|
|
|
* |
101
|
|
|
* @param string|null $table |
102
|
|
|
* @return bool |
103
|
|
|
*/ |
104
|
|
|
private function getSessionVar($table) |
105
|
|
|
{ |
106
|
|
|
if (!isset($this->config[$table][$this->driver]['session_get'])) { |
107
|
|
|
return false; |
108
|
|
|
} |
109
|
|
|
$query = $this->pdo->query($this->config[$table][$this->driver]['session_get']); |
110
|
|
|
return ( |
111
|
|
|
$query->rowCount() > 0 && |
112
|
|
|
$query->fetchColumn(0) !== null |
113
|
|
|
); |
114
|
|
|
} |
115
|
|
|
|
116
|
|
|
/** |
117
|
|
|
* Driver special treatment |
118
|
|
|
* |
119
|
|
|
* @return bool |
120
|
|
|
*/ |
121
|
|
|
private function driverDependents() |
122
|
|
|
{ |
123
|
|
|
switch ($this->driver) { |
124
|
|
|
case self::DRIVER_MYSQL: |
125
|
|
|
$this->pdo->exec('SET NAMES utf8'); |
126
|
|
|
break; |
127
|
|
|
} |
128
|
|
|
return true; |
129
|
|
|
} |
130
|
|
|
|
131
|
|
|
/** |
132
|
|
|
* Set session variable |
133
|
|
|
* |
134
|
|
|
* @param string|null $table |
135
|
|
|
* @return bool |
136
|
|
|
*/ |
137
|
|
|
private function setSessionVar($table) |
138
|
|
|
{ |
139
|
|
|
if (!isset($this->config[$table][$this->driver]['session_set'])) { |
140
|
|
|
return false; |
141
|
|
|
} |
142
|
|
|
return $this->pdo->exec($this->config[$table][$this->driver]['session_set']); |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
/** |
146
|
|
|
* Delay client |
147
|
|
|
* |
148
|
|
|
* @param string $baseUri |
149
|
|
|
* @param string $userAgent |
150
|
|
|
* @param float|int $delay |
151
|
|
|
* @return Client\Delay\ClientInterface |
152
|
|
|
* @throws SQLException |
153
|
|
|
*/ |
154
|
|
View Code Duplication |
public function delayClient($baseUri, $userAgent, $delay) |
|
|
|
|
155
|
|
|
{ |
156
|
|
|
switch ($this->driver) { |
157
|
|
|
case self::DRIVER_MYSQL: |
158
|
|
|
$this->initialCheck(self::TABLE_DELAY); |
159
|
|
|
return new Client\Delay\MySQL\Client($this->pdo, $baseUri, $userAgent, $delay); |
160
|
|
|
} |
161
|
|
|
throw new SQLException('Unsupported database. ' . $this->config[self::TABLE_DELAY]['readme']); |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
/** |
165
|
|
|
* Initial table setup check |
166
|
|
|
* |
167
|
|
|
* @param string $table |
168
|
|
|
* @return bool |
169
|
|
|
* @throws SQLException |
170
|
|
|
*/ |
171
|
|
|
private function initialCheck($table) |
172
|
|
|
{ |
173
|
|
|
if ($this->getSessionVar($table)) { |
174
|
|
|
return true; |
175
|
|
|
} |
176
|
|
|
try { |
177
|
|
|
$this->pdo->query($this->config[$table][$this->driver]['query']); |
178
|
|
|
} catch (\Exception $exception1) { |
179
|
|
|
try { |
180
|
|
|
$this->pdo->query(file_get_contents($this->config[$table][$this->driver]['file'])); |
181
|
|
|
} catch (\Exception $exception2) { |
182
|
|
|
throw new SQLException('Missing table `' . key($this->config[$table]) . '`. Setup instructions: ' . $this->config[$table]['readme']); |
183
|
|
|
} |
184
|
|
|
} |
185
|
|
|
$this->setSessionVar($table); |
186
|
|
|
return true; |
187
|
|
|
} |
188
|
|
|
|
189
|
|
|
/** |
190
|
|
|
* Cache manager |
191
|
|
|
* |
192
|
|
|
* @param array $curlOptions |
193
|
|
|
* @param int|null $byteLimit |
194
|
|
|
* @return Client\Cache\MySQL\Manager |
195
|
|
|
* @throws SQLException |
196
|
|
|
*/ |
197
|
|
View Code Duplication |
public function cacheManager(array $curlOptions, $byteLimit) |
|
|
|
|
198
|
|
|
{ |
199
|
|
|
switch ($this->driver) { |
200
|
|
|
case self::DRIVER_MYSQL: |
201
|
|
|
$this->initialCheck(self::TABLE_CACHE); |
202
|
|
|
return new Client\Cache\MySQL\Manager($this->pdo, $curlOptions, $byteLimit); |
203
|
|
|
} |
204
|
|
|
throw new SQLException('Unsupported database. ' . $this->config[self::TABLE_CACHE]['readme']); |
205
|
|
|
} |
206
|
|
|
|
207
|
|
|
/** |
208
|
|
|
* Delay manager |
209
|
|
|
* |
210
|
|
|
* @return Client\Delay\ManagerInterface |
211
|
|
|
* @throws SQLException |
212
|
|
|
*/ |
213
|
|
|
public function delayManager() |
214
|
|
|
{ |
215
|
|
|
if ($this->delayManager !== null) { |
216
|
|
|
return $this->delayManager; |
217
|
|
|
} |
218
|
|
|
switch ($this->driver) { |
219
|
|
|
case self::DRIVER_MYSQL: |
220
|
|
|
$this->initialCheck(self::TABLE_DELAY); |
221
|
|
|
return $this->delayManager = new Client\Delay\MySQL\Manager($this->pdo); |
222
|
|
|
} |
223
|
|
|
throw new SQLException('Unsupported database. ' . $this->config[self::TABLE_DELAY]['readme']); |
224
|
|
|
} |
225
|
|
|
} |
226
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.