Jacek Kowalski
2019-06-30 bcd661488de087afab096c18aa55eda42e8c5226
Move functions into classes to make them autoloader-compatibile
5 files added
3 files modified
3 files deleted
535 ■■■■ changed files
config.php 7 ●●●●● patch | view | raw | blame | history
lib/BusTypes.php 53 ●●●●● patch | view | raw | blame | history
lib/Fetch.php 70 ●●●●● patch | view | raw | blame | history
lib/Output.php 64 ●●●●● patch | view | raw | blame | history
lib/TramTypes.php 54 ●●●●● patch | view | raw | blame | history
lib/VehicleTypes.php 26 ●●●●● patch | view | raw | blame | history
lib/fetch.php 68 ●●●●● patch | view | raw | blame | history
lib/output.php 62 ●●●●● patch | view | raw | blame | history
lib/vehicle_types.php 116 ●●●●● patch | view | raw | blame | history
parse.php 11 ●●●●● patch | view | raw | blame | history
regenerate.php 4 ●●● patch | view | raw | blame | history
config.php
@@ -1,4 +1,5 @@
<?php
$tramTypes = new TramTypes();
$sources = [
    'bus' => [
        'gtfsrt' => 'ftp://ztp.krakow.pl/VehiclePositions_A.pb',
@@ -8,7 +9,7 @@
        'database' => 'mapping_A.sqlite3',
        'result' => 'mapping_A.json',
        'result_vehicles' => 'vehicles_A.html',
        'mapper' => 'numToTypeB',
        'mapper' => new BusTypes(),
        'prefix' => 'b',
    ],
    'tram' => [
@@ -19,7 +20,7 @@
        'database' => 'mapping_T.sqlite3',
        'result' => 'mapping_T.json',
        'result_vehicles' => 'vehicles_T.html',
        'mapper' => 'numToTypeT',
        'mapper' => $tramTypes,
        'prefix' => 't',
    ],
    'tram2' => [
@@ -30,7 +31,7 @@
        'database' => 'mapping_T.sqlite3',
        'result' => 'mapping_T.json',
        'result_vehicles' => 'vehicles_T.html',
        'mapper' => 'numToTypeT',
        'mapper' => $tramTypes,
        'prefix' => 't',
    ],
]; 
lib/BusTypes.php
New file
@@ -0,0 +1,53 @@
<?php
class BusTypes extends VehicleTypes {
    public function __construct() {
        $data = <<<'END'
2    4    DN    Solaris Urbino 18 IV Electric
71    83    BH    Solaris Urbino 18 III Hybrid
84    96    BH    Volvo 7900A Hybrid
103    105    PA    Mercedes-Benz 516
106    112    DA    Autosan M09LE
113    121    BA    Autosan M09LE
122    128    DA    Autosan M09LE
129    139    BA    Autosan M09LE
141    146    PM    MAN NL283 Lion's City
200    200    DO    Mercedes Conecto
206    210    PO    Mercedes O530 C2 Hybrid
211    218    DO    Mercedes O530
219    243    PO    Mercedes O530 C2 Hybrid
244    269    DO    Mercedes O530 C2
270    299    BO    Mercedes O530 C2
301    338    DU    Solaris Urbino 12 IV
339    340    BU    Solaris Urbino 12 IV
341    345    DU    Solaris Urbino 12 III
400    403    BH    Solaris Urbino 12,9 III Hybrid
404    408    DH    Solaris Urbino 12,9 III Hybrid
501    510    BR    Solaris Urbino 18 IV
511    568    DR    Solaris Urbino 18 IV
569    579    BR    Solaris Urbino 18 IV
580    595    DR    Solaris Urbino 18 IV
601    601    DE    Solaris Urbino 12 III Electric
602    605    DE    Solaris Urbino 8,9LE Electric
606    606    DE    Solaris Urbino 12 III Electric
607    623    DE    Solaris Urbino 12 IV Electric
700    700    DC    Mercedes Conecto G
701    731    DC    Mercedes O530G
732    732    DC    Mercedes Conecto G
737    741    BR    Solaris Urbino 18 III
742    745    DR    Solaris Urbino 18 III
746    764    PR    Solaris Urbino 18 III
765    768    DR    Solaris Urbino 18 III
769    776    PR    Solaris Urbino 18 MetroStyle
777    777    DR    Solaris Urbino 18 III
778    797    PR    Solaris Urbino 18 IV
851    903    BU    Solaris Urbino 12 III
904    905    DU    Solaris Urbino 12 III
906    926    BU    Solaris Urbino 12 III
927    976    PU    Solaris Urbino 12 III
977    977    DU    Solaris Urbino 12 III
978    991    PU    Solaris Urbino 12 IV
992    997    BU    Solaris Urbino 12 IV
END;
        parent::__construct($data, 2);
    }
}
lib/Fetch.php
New file
@@ -0,0 +1,70 @@
<?php
class Fetch {
    static function ftp($url, $file = NULL) {
        $url = parse_url($url);
        if(!isset($url['scheme']) || $url['scheme'] != 'ftp') {
            throw new Exception('Only FTP URLs are supported');
        }
        if(!isset($url['host'])) {
            throw new Exception('Hostname not present in the URL');
        }
        if(!isset($url['path'])) {
            throw new Exception('Path component not present in the URL');
        }
        if(!isset($url['port'])) {
            $url['port'] = 21;
        }
        if(!isset($url['user'])) {
            $url['user'] = 'anonymous';
        }
        if(!isset($url['pass'])) {
            $url['pass'] = 'anonymous@mpk.jacekk.net';
        }
        if($file == NULL) {
            $file = basename($url['path']);
        }
        $localTime = -1;
        $localSize = -1;
        if(is_file($file)) {
            $localTime = filemtime($file);
            $localSize = filesize($file);
        }
        $ftp = FtpConnection::create($url['host'], $url['port'], $url['user'], $url['pass']);
        $remoteSize = $ftp->size($url['path']);
        $remoteTime = $ftp->mdtm($url['path']);
        $updated = FALSE;
        if($localTime < $remoteTime || ($localTime == $remoteTime && $localSize != $remoteSize)) {
            if(file_exists($file.'.tmp')) {
                unlink($file.'.tmp');
            }
            $ftp->get($file.'.tmp', $url['path'], FTP_BINARY);
            touch($file.'.tmp', $remoteTime);
            if(!rename($file.'.tmp', $file)) {
                throw new Exception('Temporary file rename failed');
            }
            $updated = TRUE;
        }
        return $updated;
    }
    static function generic($url, $file = NULL) {
        if($file == NULL) {
            $file = basename($url['url']);
        }
        $data = file_get_contents($url);
        if($data === FALSE) {
            throw new Exception('URL fetch failed');
        }
        if(file_put_contents($file.'.tmp', $data) === FALSE) {
            throw new Exception('Temporary file creation failed');
        }
        if(!rename($file.'.tmp', $file)) {
            throw new Exception('Temporary file rename failed');
        }
    }
}
lib/Output.php
New file
@@ -0,0 +1,64 @@
<?php
class Output {
    static function createMapping($db, VehicleTypes $vehicleTypes, $saveConfig = FALSE) {
        $mapping = [];
        foreach($db->getAll() as $vehicle) {
            $mapping[$vehicle['id']] = $vehicleTypes->getByNumber($vehicle['num']);
        }
        if($saveConfig) {
            $json = json_encode($mapping);
            if(!file_put_contents($saveConfig['result_temp'], $json)) {
                throw new Exception('Result save failed');
            }
            rename($saveConfig['result_temp'], $saveConfig['result']);
        }
        return $mapping;
    }
    function createVehiclesList($trips, $mapping, $saveConfig = FALSE) {
        $lines = [];
        $vehicles = [];
        foreach($trips as $trip) {
            $vehicle = $mapping[$trip['id']] ?? [];
            $vehicle += ['trip' => $trip['id']];
            $lines[$trip['line']][] = [
                'trip' => $trip,
                'vehicle' => $vehicle,
            ];
            $vehicles[$vehicle['type'] ?? '?'][] = $vehicle;
        }
        foreach($lines as &$line) {
            usort($line, function($a, $b) {
                return (substr($a['vehicle']['num'] ?? '', 2) <=> substr($b['vehicle']['num'] ?? '', 2));
            });
        }
        unset($line);
        ksort($lines);
        foreach($vehicles as &$vehicle) {
            usort($vehicle, function($a, $b) {
                return (substr($a['num'] ?? '', 2) <=> substr($b['num'] ?? '', 2));
            });
        }
        unset($vehicle);
        ksort($vehicles);
        if($saveConfig) {
            $twigLoader = new \Twig\Loader\FilesystemLoader(__DIR__.'/../templates');
            $twig = new \Twig\Environment($twigLoader);
            $vehiclesHtml = $twig->render('vehicles.html', [
                'lines' => $lines,
                'vehicles' => $vehicles,
                'prefix' => $saveConfig['prefix'],
            ]);
            if(!file_put_contents($saveConfig['result_vehicles_temp'], $vehiclesHtml)) {
                throw new Exception('Vehicles save failed');
            }
            rename($saveConfig['result_vehicles_temp'], $saveConfig['result_vehicles']);
        }
        return $lines;
    }
}
lib/TramTypes.php
New file
@@ -0,0 +1,54 @@
<?php
class TramTypes extends VehicleTypes {
    public function __construct() {
        $data = <<<'END'
101    107    HW    E1    0
108    113    RW    E1    0
114    126    HW    E1    0
127    127    RW    E1    0
128    130    HW    E1    0
131    132    RW    E1    0
133    133    HW    E1    0
134    134    RW    E1    0
135    136    HW    E1    0
137    139    RW    E1    0
140    147    HW    E1    0
148    150    RW    E1    0
151    152    HW    E1    0
153    153    RW    E1    0
154    154    HW    E1    0
155    155    RW    E1    0
156    158    HW    E1    0
159    159    RW    E1    0
160    174    HW    E1    0
201    245    RZ    105N    0
246    299    HZ    105N    0
301    310    RF    GT8S    0
311    311    RF    GT8N    1
312    312    RF    GT8S    0
313    313    RF    GT8C    1
314    317    RF    GT8S    0
318    329    RF    GT8N    1
401    440    HL    EU8N    1
451    456    HK    N8C-NF    1
457    461    HK    N8S-NF    1
462    462    HK    N8C-NF    1
601    614    RP    NGT6 (1)    2
615    626    RP    NGT6 (2)    2
627    650    RP    NGT6 (3)    2
801    824    RY    NGT8    2
899    899    RY    126N    2
901    914    RG    2014N    2
915    936    HG    2014N    2
999    999    HG    405N    1
END;
        parent::__construct($data);
    }
    public function getByNumber($id) {
        if((int)$id == 250) {
            $id = 410;
        }
        return parent::getByNumber($id);
    }
}
lib/VehicleTypes.php
New file
@@ -0,0 +1,26 @@
<?php
abstract class VehicleTypes {
    protected $typesByNumber = [];
    protected function __construct($data, $defaultLow=NULL) {
        $data = explode("\n", trim($data));
        foreach($data as $line) {
            $line = explode("\t", trim($line));
            for($i = (int)$line[0]; $i <= (int)$line[1]; $i++) {
                $this->typesByNumber[$i] = [
                    'num' => $line[2] . str_pad($i, 3, '0', STR_PAD_LEFT),
                    'type' => $line[3],
                    'low' => (int)(isset($line[4]) ? $line[4] : $defaultLow),
                ];
            }
        }
    }
    public function getByNumber($id) {
        return $this->typesByNumber[$id] ?? [
            'num' => '??'.$id,
            'type' => '?',
            'low' => NULL,
        ];
    }
}
lib/fetch.php
File was deleted
lib/output.php
File was deleted
lib/vehicle_types.php
File was deleted
parse.php
@@ -1,22 +1,19 @@
<?php
require_once(__DIR__.'/vendor/autoload.php');
require_once(__DIR__.'/lib/fetch.php');
require_once(__DIR__.'/lib/output.php');
require_once(__DIR__.'/lib/vehicle_types.php');
require_once(__DIR__.'/config.php');
foreach($sources as $name => $source) {
    $logger = new Monolog\Logger('fetch_'.$name);
    try {
        $logger->info('Fetching '.$name.' position data from FTP...');
        $updated = ftp_fetch_if_newer($source['gtfsrt'], $source['gtfsrt_file']);
        $updated = Fetch::ftp($source['gtfsrt'], $source['gtfsrt_file']);
        if(!$updated) {
            $logger->info('Nothing to do, remote file not newer than local one');
            continue;
        }
        
        $logger->info('Fetching '.$name.' position data from TTSS...');
        fetch($source['ttss'], $source['ttss_file']);
        Fetch::generic($source['ttss'], $source['ttss_file']);
        
        $logger->info('Loading data...');
        $mapper = new Mapper();
@@ -80,12 +77,12 @@
        
        $db->addMapping($mapping);
        
        $finalMapping = createMapping($db, $source['mapper'], $source);
        $finalMapping = Output::createMapping($db, $source['mapper'], $source);
        
        
        $logger->info('Creating vehicle list...');
        
        createVehiclesList($mapper->getTTSSTrips(), $finalMapping, $source);
        Output::createVehiclesList($mapper->getTTSSTrips(), $finalMapping, $source);
        
        $logger->info('Finished');
    } catch(Throwable $e) {
regenerate.php
@@ -1,7 +1,5 @@
<?php
require_once(__DIR__.'/vendor/autoload.php');
require_once(__DIR__.'/lib/output.php');
require_once(__DIR__.'/lib/vehicle_types.php');
require_once(__DIR__.'/config.php');
foreach($sources as $name => $source) {
@@ -9,7 +7,7 @@
    try {
        $logger->info('Regenerating '.$name.'...');
        $db = new Database($source['database']);
        createMapping($db, $source['mapper'], $source);
        Output::createMapping($db, $source['mapper'], $source);
        $logger->info('Finished');
    } catch(Throwable $e) {
        $logger->error($e->getMessage(), ['exception' => $e, 'exception_string' => (string)$e]);