database = $in_database; $this->distance_calculator = $in_distance_calculator; $this->get_static = function($name) { return self::$$name; }; $this->get_static_extra = function($class_name, $name) { return $class_name::$$name; }; } public function get_all_devices($only_with_location) { $s = $this->get_static; $o = $this->get_static_extra; $data_repo_class = MariaDBMeasurementDataRepository::class; $data_repo_table_meta = $o($data_repo_class, "table_name_metadata"); $data_repo_col_datetime = "$data_repo_table_meta.{$o($data_repo_class, "column_metadata_datetime")}"; $data_repo_col_device_id = "$data_repo_table_meta.{$o($data_repo_class, "column_metadata_device_id")}"; $sql = "SELECT {$s("table_name")}.{$s("column_device_id")} AS id, {$s("table_name")}.{$s("column_device_name")} AS name, {$s("table_name")}.{$s("column_lat")} AS latitude, {$s("table_name")}.{$s("column_long")} AS longitude, {$s("table_name")}.{$s("column_altitude")} AS altitude, {$s("table_name")}.{$s("column_device_type")} AS type_id, {$s("table_name")}.{$s("column_last_seen")} AS last_seen FROM {$s("table_name")} JOIN $data_repo_table_meta ON $data_repo_col_device_id = {$s("table_name")}.{$s("column_device_id")} WHERE {$s("table_name")}.{$s("column_visible")} != 0"; if($only_with_location) $sql .= "\nWHERE {$s("column_lat")} IS NOT NULL AND {$s("column_long")} IS NOT NULL"; $sql .= " GROUP BY $data_repo_col_device_id;"; return $this->database->query($sql)->fetchAll(); } public function get_device_info_ext($device_id) { $s = $this->get_static; $o = $this->get_static_extra; $data_repo_class = MariaDBMeasurementDataRepository::class; $data_repo_table_meta = $o($data_repo_class, "table_name_metadata"); $data_repo_col_datetime = "$data_repo_table_meta.{$o($data_repo_class, "column_metadata_datetime")}"; $data_repo_col_device_id = "$data_repo_table_meta.{$o($data_repo_class, "column_metadata_device_id")}"; $query_result = $this->database->query( "SELECT {$s("table_name")}.{$s("column_device_id")} AS id, {$s("table_name")}.{$s("column_device_name")} AS name, {$s("table_name")}.{$s("column_lat")} AS latitude, {$s("table_name")}.{$s("column_long")} AS longitude, {$s("table_name")}.{$s("column_altitude")} AS altitude, {$s("table_name_type")}.*, {$s("table_name")}.{$s("column_last_seen")} AS last_seen FROM {$s("table_name")} JOIN {$s("table_name_type")} ON {$s("table_name")}.{$s("column_device_type")} = {$s("table_name_type")}.{$s("column_type_id")} JOIN $data_repo_table_meta ON $data_repo_col_device_id = {$s("table_name")}.{$s("column_device_id")} WHERE {$s("table_name")}.{$s("column_device_id")} = :device_id AND {$s("table_name")}.{$s("column_visible")} != 0;", [ "device_id" => $device_id ] )->fetch(); // gets the next row from the query $result = []; foreach($query_result as $key => $value) { // Hack! Filter out some useless columns // We do this so that we can return everything we know about the // device in a manner that means we don't need to alter this code // if additional columns are added later. if($key == self::$column_type_id) continue; $result[strtolower($key)] = $value; } return $result; } public function get_near_location(float $lat, float $long, int $count) { $s = $this->get_static; $o = $this->get_static_extra; $data_repo_class = MariaDBMeasurementDataRepository::class; $data_repo_table_meta = $o($data_repo_class, "table_name_metadata"); $data_repo_col_datetime = "$data_repo_table_meta.{$o($data_repo_class, "column_metadata_datetime")}"; $data_repo_col_device_id = "$data_repo_table_meta.{$o($data_repo_class, "column_metadata_device_id")}"; $result = $this->database->query( "SELECT {$s("table_name")}.{$s("column_device_id")} AS id, {$s("table_name")}.{$s("column_device_name")} AS name, {$s("table_name")}.{$s("column_lat")} AS latitude, {$s("table_name")}.{$s("column_long")} AS longitude, ST_DISTANCE_SPHERE(POINT(:latitude, :longitude), {$s("table_name")}.{$s("column_point")}) AS distance_calc, {$s("table_name")}.{$s("column_last_seen")} AS last_seen FROM {$s("table_name")} JOIN $data_repo_table_meta ON $data_repo_col_device_id = {$s("table_name")}.{$s("column_device_id")} WHERE {$s("table_name")}.{$s("column_point")} IS NOT NULL AND {$s("table_name")}.{$s("column_visible")} != 0 ORDER BY ST_DISTANCE_SPHERE(POINT(:latitude_again, :longitude_again), {$s("table_name")}.{$s("column_point")}) LIMIT :count;", [ "latitude" => $lat, "longitude" => $long, "latitude_again" => $lat, "longitude_again" => $long, "count" => $count ] )->fetchAll(); // Calculate the *actual* distance in metres. // This is complicated and requires nasty formulae, so we're using a library here // FUTURE: Apparently said library supports caching with PSR-6 - maybe we could take advantage of a PSR-6 implementation both here and elsewhere? $loc = new Coordinate($lat, $long); foreach($result as &$item) { $item["distance_actual"] = $this->distance_calculator->getDistance( $loc, new Coordinate( floatval($item["latitude"]), floatval($item["longitude"]) ) ); } return $result; } }