Completed
Push — 2.0-dev ( 2c252e...97b412 )
by Jan-Petter
02:13
created

CacheCoreSQL::cron()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 28
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 28
rs 8.5806
cc 4
eloc 15
nc 4
nop 1
1
<?php
2
namespace vipnytt\RobotsTxtParser\Client\SQL\Cache;
3
4
use PDO;
5
use vipnytt\RobotsTxtParser\Client\SQL\SQLInterface;
6
use vipnytt\RobotsTxtParser\Client\SQL\SQLTrait;
7
use vipnytt\RobotsTxtParser\RobotsTxtInterface;
8
use vipnytt\RobotsTxtParser\URI;
9
10
/**
11
 * Class CacheCoreSQL
12
 *
13
 * @package vipnytt\RobotsTxtParser\Client\SQL\Cache
14
 */
15
abstract class CacheCoreSQL implements RobotsTxtInterface, SQLInterface
16
{
17
    use SQLTrait;
18
19
    /**
20
     * Database connection
21
     * @var PDO
22
     */
23
    protected $pdo;
24
25
    /**
26
     * PDO driver
27
     * @var string
28
     */
29
    protected $driver;
30
31
    /**
32
     * GuzzleHTTP config
33
     * @var array
34
     */
35
    protected $guzzleConfig = [];
36
37
    /**
38
     * Byte limit
39
     * @var int
40
     */
41
    protected $byteLimit = self::BYTE_LIMIT;
42
43
    /**
44
     * CacheCoreSQL constructor.
45
     *
46
     * @param PDO $pdo
47
     * @param array $guzzleConfig
48
     * @param int|null $byteLimit
49
     */
50
    public function __construct(PDO $pdo, array $guzzleConfig = [], $byteLimit = self::BYTE_LIMIT)
51
    {
52
        $this->pdo = $this->pdoInitialize($pdo);
53
        $this->driver = $this->pdo->getAttribute(PDO::ATTR_DRIVER_NAME);
54
        if ($this->driver != 'mysql') {
55
            trigger_error('Unsupported database. Currently supports MySQL only. ' . self::README_SQL_CACHE, E_USER_WARNING);
56
        }
57
        $this->guzzleConfig = $guzzleConfig;
58
        $this->byteLimit = $byteLimit;
59
    }
60
61
    /**
62
     * Process the update queue
63
     *
64
     * @param int|null $workerID
65
     * @return bool
66
     */
67
    public function cron($workerID = null)
68
    {
69
        $worker = $this->setWorkerID($workerID);
70
        $result = true;
71
        while ($result) {
72
            $query = $this->pdo->prepare(<<<SQL
73
UPDATE robotstxt__cache0
74
SET worker = :workerID
75
WHERE worker IS NULL AND nextUpdate <= UNIX_TIMESTAMP()
76
ORDER BY nextUpdate ASC
77
LIMIT 1;
78
SELECT base
79
FROM robotstxt__cache0
80
WHERE worker = :worker;
81
SQL
82
            );
83
            $query->bindParam(':workerID', $worker, PDO::PARAM_INT);
84
            $query->execute();
85
            if ($query->rowCount() > 0) {
86
                while ($row = $query->fetch(PDO::FETCH_ASSOC)) {
87
                    $result = $this->push(new URI($row['base'], $this->guzzleConfig, $this->byteLimit));
88
                }
89
                continue;
90
            }
91
            return true;
92
        }
93
        return false;
94
    }
95
96
    /**
97
     * Set WorkerID
98
     *
99
     * @param int|null $workerID
100
     * @return int
101
     */
102
    protected function setWorkerID($workerID = null)
103
    {
104
        if (
105
            is_int($workerID) &&
106
            $workerID <= 255 &&
107
            $workerID >= 1
108
        ) {
109
            return $workerID;
110
        } elseif ($workerID !== null) {
111
            trigger_error('WorkerID out of range (1-255)', E_USER_WARNING);
112
        }
113
        return rand(1, 255);
114
    }
115
116
    /**
117
     * Update an robots.txt in the database
118
     *
119
     * @param URI $request
120
     * @return bool
121
     */
122
    public function push(URI $request)
123
    {
124
        $base = $request->getBaseUri();
125
        $statusCode = $request->getStatusCode();
126
        $nextUpdate = $request->nextUpdate();
127
        if (
128
            $statusCode >= 500 &&
129
            $statusCode < 600 &&
130
            mb_strpos($base, 'http') === 0
131
        ) {
132
            $query = $this->pdo->prepare(<<<SQL
133
SELECT validUntil
134
FROM robotstxt__cache0
135
WHERE base = :base;
136
SQL
137
            );
138
            $query->bindParam(':base', $base, PDO::PARAM_STR);
139
            $query->execute();
140
            if (
141
                $query->rowCount() > 0 &&
142
                ($existingValidUntil = $query->fetch(PDO::FETCH_ASSOC)['validUntil']) > time()
143
            ) {
144
                $nextUpdate = min($existingValidUntil, $nextUpdate);
145
                $query = $this->pdo->prepare(<<<SQL
146
UPDATE robotstxt__cache0
147
SET nextUpdate = :nextUpdate, worker = NULL
148
WHERE base = :base;
149
SQL
150
                );
151
                $query->bindParam(':base', $base, PDO::PARAM_STR);
152
                $query->bindParam(':nextUpdate', $nextUpdate, PDO::PARAM_INT);
153
                return $query->execute();
154
            }
155
        }
156
        $validUntil = $request->validUntil();
157
        $content = $request->getContents();
158
        $query = $this->pdo->prepare(<<<SQL
159
INSERT INTO robotstxt__cache0 (base, content, statusCode, validUntil, nextUpdate)
160
VALUES (:base, :content, :statusCode, :validUntil, :nextUpdate)
161
ON DUPLICATE KEY UPDATE content = :content, statusCode = :statusCode, validUntil = :validUntil,
162
  nextUpdate = :nextUpdate, worker = 0;
163
SQL
164
        );
165
        $query->bindParam(':base', $base, PDO::PARAM_STR);
166
        $query->bindParam(':content', $content, PDO::PARAM_STR);
167
        $query->bindParam(':statusCode', $statusCode, PDO::PARAM_INT);
168
        $query->bindParam(':validUntil', $validUntil, PDO::PARAM_INT);
169
        $query->bindParam(':nextUpdate', $nextUpdate, PDO::PARAM_INT);
170
        return $query->execute();
171
    }
172
}
173