Failed Conditions
Push — newinternal ( 216d62...410e59 )
by Simon
05:28 queued 13s
created

PrecacheGeolocationTask::execute()   B

Complexity

Conditions 6
Paths 23

Size

Total Lines 77
Code Lines 47

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 47
c 0
b 0
f 0
dl 0
loc 77
rs 8.5341
cc 6
nc 23
nop 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/******************************************************************************
3
 * Wikipedia Account Creation Assistance tool                                 *
4
 *                                                                            *
5
 * All code in this file is released into the public domain by the ACC        *
6
 * Development Team. Please see team.json for a list of contributors.         *
7
 ******************************************************************************/
8
9
namespace Waca\ConsoleTasks;
10
11
use Exception;
12
use PDO;
13
use Waca\Tasks\ConsoleTaskBase;
14
15
class PrecacheGeolocationTask extends ConsoleTaskBase
16
{
17
    public function execute()
18
    {
19
        $database = $this->getDatabase();
20
        $locationProvider = $this->getLocationProvider();
21
22
        while (true) {
23
            echo "Beginning txn\n";
24
            $database->beginTransaction();
25
26
            try {
27
                echo ". Fetching data...\n";
28
29
                // fetch a bunch of un-geolocated IPs from the database.
30
                // Note we have to parse the forwardedip field in the database so we can test against the geolocation
31
                // table.
32
                //
33
                // This guarantees we get ten unlocated IPs back, unless there actually aren't 10 available.
34
                //
35
                // Alternatives include downloading a small set of forwarded IPs, splitting it in PHP, constructing an
36
                // IN() clause dynamically, sending that back to the database to check if there are geolocation entries,
37
                // then repeating until we have 10 to process - and the fact that we'd have to potentially retrieve all
38
                // IPs from the database before we find any at all. This way keeps all of that legwork in the database,
39
                // at the cost of a more complex query.
40
                $statement = $database->query(<<<SQL
41
                    SELECT /* PrecacheGeolocationTask */ p.prox
42
                    FROM (
43
                      SELECT trim(substring_index(substring_index(r.forwardedip, ',', n.n), ',', -1)) prox
44
                      FROM request r
45
                        INNER JOIN (
46
                          SELECT 1 n
47
                          UNION ALL SELECT 2
48
                          UNION ALL SELECT 3
49
                          UNION ALL SELECT 4
50
                          UNION ALL SELECT 5) n
51
                        ON char_length(r.forwardedip) - char_length(replace(r.forwardedip, ',', '')) >= n.n - 1
52
                      WHERE ip <> '127.0.0.1'
53
                    ) p
54
                    WHERE NOT EXISTS (SELECT 1 FROM geolocation g WHERE g.address = p.prox FOR UPDATE)
55
                    LIMIT 10;
56
SQL
57
                );
58
59
                $missingIps = $statement->fetchAll(PDO::FETCH_COLUMN);
60
61
                $count = count($missingIps);
62
                if ($count === 0) {
63
                    echo ". Found nothing to do.\n";
64
                    break;
65
                }
66
67
                echo ". Picked {$count} IP addresses\n";
68
69
                foreach ($missingIps as $ip) {
70
                    echo ". . Getting location for {$ip}...\n";
71
                    $data = json_encode($locationProvider->getIpLocation($ip));
72
                    echo ". . . {$data}\n";
73
                }
74
75
                echo ". IP location fetch complete.\n";
76
                $database->commit();
77
                echo ". Committed txn.\n";
78
            }
79
            catch (Exception $ex) {
80
                echo ". Encountered exception: " . $ex->getMessage() . "\n";
81
                $database->rollBack();
82
                echo ". Rolled back txn\n";
83
                throw $ex;
84
            }
85
            finally {
86
                if ($database->hasActiveTransaction()) {
87
                    $database->rollBack();
88
                    echo ". Rolled back txn\n";
89
                }
90
            }
91
        }
92
93
        echo "Done.\n";
94
    }
95
}