Jacek Kowalski
2020-01-27 4136546b927f78a475cb36b442c051ecaadb605e
Show when the vehicles were last seen in TTSS
8 files modified
145 ■■■■ changed files
composer.json 3 ●●●● patch | view | raw | blame | history
config.php 7 ●●●●● patch | view | raw | blame | history
lib/Database.php 42 ●●●● patch | view | raw | blame | history
lib/Mapper.php 24 ●●●● patch | view | raw | blame | history
lib/Output.php 29 ●●●● patch | view | raw | blame | history
parse.php 12 ●●●● patch | view | raw | blame | history
regenerate.php 6 ●●●● patch | view | raw | blame | history
templates/vehicles.html 22 ●●●●● patch | view | raw | blame | history
composer.json
@@ -7,6 +7,7 @@
    "require": {
        "google/gtfs-realtime-bindings": "^0.0.2",
        "monolog/monolog": "^1.24",
        "twig/twig": "^2.0"
        "twig/twig": "^2.0",
        "twig/extensions": "^1.5"
    }
}
config.php
@@ -1,5 +1,4 @@
<?php
$tramTypes = new TramTypes();
$sources = [
    'bus' => [
        'gtfsrt' => 'ftp://zdmk.krakow.pl/VehiclePositions_A.pb',
@@ -9,18 +8,18 @@
        'database' => 'mapping_A.sqlite3',
        'result' => 'mapping_A.json',
        'result_vehicles' => 'vehicles_A.html',
        'mapper' => new BusTypes(),
        'vehicle_types' => new BusTypes(),
        'prefix' => 'b',
    ],
    'tram' => [
        'gtfsrt' => 'ftp://zdmk.krakow.pl/VehiclePositions_T.pb',
        'gtfsrt' => 'http://gtfs.ztp.krakow.pl/VehiclePositions_T.pb',
        'gtfsrt_file' => 'VehiclePositions_T.pb',
        'ttss' => 'http://www.ttss.krakow.pl/internetservice/geoserviceDispatcher/services/vehicleinfo/vehicles?positionType=CORRECTED',
        'ttss_file' => 'vehicles_T.json',
        'database' => 'mapping_T.sqlite3',
        'result' => 'mapping_T.json',
        'result_vehicles' => 'vehicles_T.html',
        'mapper' => $tramTypes,
        'vehicle_types' => new TramTypes(),
        'prefix' => 't',
    ],
];
lib/Database.php
@@ -10,13 +10,23 @@
        $this->pdo = new PDO('sqlite:'.$file);
        $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        
        $this->pdo->query('CREATE TABLE IF NOT EXISTS vehicles (
        $this->pdo->query('CREATE TABLE IF NOT EXISTS vehicles2 (
            id INT PRIMARY KEY,
            num INT UNIQUE,
            weight INT
            weight INT,
            line VARCHAR,
            date INT
        )');
        try {
            $this->beginTransaction();
            $this->pdo->query('INSERT INTO vehicles2 SELECT id, num, weight, \'?\', \''.time().'\' FROM vehicles');
            $this->commit();
            $this->pdo->query('DROP TABLE vehicles');
        } catch(PDOException $e) {
            $this->rollback();
        }
        
        $this->addStatement = $this->pdo->prepare('INSERT OR REPLACE INTO vehicles (id, num, weight) VALUES (:id, :num, :weight)');
        $this->addStatement = $this->pdo->prepare('INSERT OR REPLACE INTO vehicles2 (id, num, weight, line, date) VALUES (:id, :num, :weight, :line, :date)');
        
        $this->_cacheClear();
    }
@@ -35,7 +45,7 @@
    
    protected function _cachePopulate() {
        if($this->cacheId === NULL) {
            $st = $this->pdo->prepare('SELECT * FROM vehicles');
            $st = $this->pdo->prepare('SELECT * FROM vehicles2');
            $st->execute();
            $result = $st->fetchAll(PDO::FETCH_ASSOC);
            
@@ -58,9 +68,14 @@
        $this->cacheNum = NULL;
    }
    
    public function getAll() {
    public function getAllById() {
        $this->_cachePopulate();
        return $this->cacheId;
    }
    public function getAllByNum() {
        $this->_cachePopulate();
        return $this->cacheNum;
    }
    
    public function getById($id) {
@@ -74,25 +89,28 @@
    }
    
    public function clear() {
        $this->pdo->query('DELETE FROM vehicles');
        $this->pdo->query('DELETE FROM vehicles2');
        $this->_cacheClear();
    }
    
    public function add($id, $num, $weight) {
    public function add($id, $num, $weight, $line = NULL, $date = NULL) {
        $vehicle = [
            'id' => (string)$id,
            'num' => (string)$num,
            'weight' => (string)$weight
            'weight' => (string)$weight,
            'line' => (string)($line ?? ''),
            'date' => (string)($date ?? time()),
        ];
        $this->addStatement->execute($vehicle);
        $this->_cacheAdd($vehicle);
    }
    
    public function addMapping($mapping) {
    public function addMapping($vehiclesMapping, Mapper $mapper) {
        $this->beginTransaction();
        $weight = count($mapping);
        foreach($mapping as $id => $num) {
            $this->add($id, $num, $weight);
        $weight = count($vehiclesMapping);
        foreach($vehiclesMapping as $id => $num) {
            $trip = $mapper->getTTSSVehicleTrip($id);
            $this->add($id, $num, $weight, ($trip['line'] ?? '?') . ' ' . ($trip['direction'] ?? '?'));
        }
        $this->commit();
    }
lib/Mapper.php
@@ -4,6 +4,7 @@
class Mapper {
    private $ttssDate = NULL;
    private $ttssTrips = [];
    private $ttssVehicleToTrip = [];
    private $gtfsrtDate = NULL;
    private $gtfsrtTrips = [];
    private $logger = NULL;
@@ -35,18 +36,15 @@
            if(!isset($vehicle->latitude) || !$vehicle->latitude) continue;
            if(!isset($vehicle->longitude) || !$vehicle->longitude) continue;
            list($line, $direction) = explode(' ', $vehicle->name, 2);
            foreach($this->specialNames as $specialName) {
                if(substr($vehicle->name, -strlen($specialName)) == $specialName) {
                    continue;
                }
            }
            $this->ttssTrips[(string)$vehicle->tripId] = [
            $trip = [
                'id' => (string)$vehicle->id,
                'line' => $line,
                'direction' => $direction,
                'latitude' => (float)$vehicle->latitude / 3600000.0,
                'longitude' => (float)$vehicle->longitude / 3600000.0,
            ];
            $this->ttssTrips[(string)$vehicle->tripId] = $trip;
            $this->ttssVehicleToTrip[(string)$vehicle->id] = $trip;
        }
        ksort($this->ttssTrips);
    }
@@ -57,6 +55,18 @@
    
    public function getTTSSTrips() {
        return $this->ttssTrips;
    }
    public function getTTSSVehicleToTrip() {
        return $this->ttssVehicleToTrip;
    }
    public function getTTSSTrip($id) {
        return $this->ttssTrips[$id] ?? NULL;
    }
    public function getTTSSVehicleTrip($id) {
        return $this->ttssVehicleToTrip[$id] ?? NULL;
    }
    
    public function loadGTFSRT($file) {
@@ -130,7 +140,7 @@
        return $bestOffset;
    }
    
    public function mapUsingOffset($offset) {
    public function mapVehicleIdsUsingOffset($offset) {
        $result = [];
        foreach($this->gtfsrtTrips as $gtfsTripId => $gtfsTrip) {
            $ttssTripId = $gtfsTripId + $offset;
lib/Output.php
@@ -1,9 +1,19 @@
<?php
class Output {
    static function createMapping($db, VehicleTypes $vehicleTypes, $saveConfig = FALSE) {
    private $db;
    private $mapper;
    private $vehicleTypes;
    function __construct(Database $db, Mapper $mapper, VehicleTypes $vehicleTypes) {
        $this->db = $db;
        $this->mapper = $mapper;
        $this->vehicleTypes = $vehicleTypes;
    }
    function createMapping($saveConfig = FALSE) {
        $mapping = [];
        foreach($db->getAll() as $vehicle) {
            $mapping[$vehicle['id']] = $vehicleTypes->getByNumber($vehicle['num']);
        foreach($this->db->getAllById() as $vehicle) {
            $mapping[$vehicle['id']] = $this->vehicleTypes->getByNumber($vehicle['num']);
        }
        
        if($saveConfig) {
@@ -17,11 +27,13 @@
        return $mapping;
    }
    
    function createVehiclesList($trips, $mapping, $saveConfig = FALSE) {
    function createVehiclesList($fullMapping, $saveConfig = FALSE) {
        $trips = $this->mapper->getTTSSTrips();
        $lines = [];
        $vehicles = [];
        foreach($trips as $trip) {
            $vehicle = $mapping[$trip['id']] ?? [];
            $vehicle = $fullMapping[$trip['id']] ?? [];
            $vehicle += ['trip' => $trip['id']];
            $lines[$trip['line']][] = [
                'trip' => $trip,
@@ -29,6 +41,7 @@
            ];
            $vehicles[$vehicle['type'] ?? '?'][] = $vehicle;
        }
        foreach($lines as &$line) {
            usort($line, function($a, $b) {
                return (substr($a['vehicle']['num'] ?? '', 2) <=> substr($b['vehicle']['num'] ?? '', 2)); 
@@ -36,6 +49,7 @@
        }
        unset($line);
        ksort($lines);
        foreach($vehicles as &$vehicle) {
            usort($vehicle, function($a, $b) {
                return (substr($a['num'] ?? '', 2) <=> substr($b['num'] ?? '', 2));
@@ -44,14 +58,19 @@
        unset($vehicle);
        ksort($vehicles);
        
        $dbMapping = $this->db->getAllByNum();
        ksort($dbMapping);
        if($saveConfig) {
            $twigLoader = new \Twig\Loader\FilesystemLoader(__DIR__.'/../templates');
            $twig = new \Twig\Environment($twigLoader);
            $twig->addExtension(new Twig_Extensions_Extension_Date());
            
            $vehiclesHtml = $twig->render('vehicles.html', [
                'lines' => $lines,
                'vehicles' => $vehicles,
                'prefix' => $saveConfig['prefix'],
                'mapping' => $dbMapping,
            ]);
            if(!file_put_contents($saveConfig['result_vehicles_temp'], $vehiclesHtml)) {
                throw new Exception('Vehicles save failed');
parse.php
@@ -39,7 +39,7 @@
        }
        
        $logger->info('Got offset '.$offset.', creating mapping...');
        $mapping = $mapper->mapUsingOffset($offset);
        $mapping = $mapper->mapVehicleIdsUsingOffset($offset);
        
        $logger->info('Checking the data for correctness...');
        $weight = count($mapping);
@@ -72,17 +72,17 @@
            throw new Exception('Ignoring result due to better data already present');
        }
        
        $output = new Output($db, $mapper, $source['vehicle_types']);
        
        $logger->info('Creating mapping...');
        $logger->info('Saving mapping...');
        
        $db->addMapping($mapping);
        $db->addMapping($mapping, $mapper);
        
        $finalMapping = Output::createMapping($db, $source['mapper'], $source);
        $fullMapping = $output->createMapping($source);
        
        $logger->info('Creating vehicle list...');
        
        Output::createVehiclesList($mapper->getTTSSTrips(), $finalMapping, $source);
        $output->createVehiclesList($fullMapping, $source);
        
        $logger->info('Finished');
    } catch(Throwable $e) {
regenerate.php
@@ -7,7 +7,11 @@
    try {
        $logger->info('Regenerating '.$name.'...');
        $db = new Database($source['database']);
        Output::createMapping($db, $source['mapper'], $source);
        $mapper = new Mapper();
        $mapper->loadTTSS($source['ttss_file']);
        $output = new Output($db, $mapper, $source['vehicle_types']);
        $fullMapping = $output->createMapping($source);
        $output->createVehiclesList($fullMapping, $source);
        $logger->info('Finished');
    } catch(Throwable $e) {
        $logger->error($e->getMessage(), ['exception' => $e, 'exception_string' => (string)$e]);
templates/vehicles.html
@@ -80,6 +80,28 @@
{% endfor %}
</table>
<table>
<caption>Vehicles in TTSS</caption>
<thead>
<tr>
<th>Vehicle</th> <th>Line</th> <th>Last seen</th>
</tr>
</thead>
{% for map in mapping %}
<tr>
<td>
{{ map.num | e }}
</td>
<td>
{{ map.line | default('?') | e }}
</td>
<td>
{{ map.date | time_diff | default('now') }}
</td>
</tr>
{% endfor %}
</table>
Generated at {{ "now" | date("Y-m-d H:i:s P") }}
</table>