Browse Source

Init commit

Joachim M. Giæver 4 years ago
parent
commit
569dbba25e

+ 1 - 0
.gitignore

@@ -1,6 +1,7 @@
 # ---> Composer
 # ---> Composer
 composer.phar
 composer.phar
 vendor/
 vendor/
+.phpcd/
 
 
 # Commit your application's lock file http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file
 # Commit your application's lock file http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file
 # You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file
 # You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file

+ 7 - 0
composer.json

@@ -0,0 +1,7 @@
+{
+    "autoload": {
+        "psr-4": {
+            "App\\": "src/"
+        }
+    }
+}

+ 15 - 0
index.php

@@ -0,0 +1,15 @@
+<?php
+
+require __DIR__ . '/vendor/autoload.php';
+
+$url = 'https://www.yr.no/place/Norway/Troms/Tromsø/Tromsø/forecast_hour_by_hour.xml';
+
+$forecast = new App\Yr\Forecast($url);
+
+echo '<pre>';
+var_dump($forecast->getLocation());
+foreach ($forecast->getTabular()->getBetween(
+    $forecast->getSunset(), $forecast->getSunrise()->add(new \DateInterval('P1D'))
+) as $time)
+    echo $time . "\n";
+?>

+ 58 - 0
src/Yr/Forecast.php

@@ -0,0 +1,58 @@
+<?php
+
+namespace App\Yr;
+
+use App\Yr\Forecast\Location;
+use App\Yr\Forecast\Tabular;
+
+final class Forecast {
+    private $xml;
+    private $location;
+
+    public function __construct(string $url) {
+        $this->xml = simplexml_load_file($url);
+        $this->location = new Location($this->xml->location);
+    }
+
+    public function getLocation(): Location {
+        return $this->location;
+    }
+
+    final public function getCredit(): array {
+        return [
+            'text' => (string)$this->xml->credit->link->attributes()['text'],
+            'url' => (string)$this->xml->credit->link->attributes()['url']
+        ];
+    }
+
+    public function getSunrise(): \DateTimeImmutable {
+        return (new \DateTimeImmutable($this->xml->sun['rise']));
+    }
+
+    public function getSunset(): \DateTimeImmutable {
+        return (new \DateTimeImmutable($this->xml->sun['seẗ́']));
+    }
+
+    public function getLinks(): \Generator {
+        foreach ($this->xml->links->children() as $link)
+            yield [
+                'id' => (string)$link->attributes()['id'],
+                'url' => (string)$link->attributes()['url'],
+            ];
+    }
+
+    public function getLastUpdate(): \DateTimeImmutable {
+        return new DateTimeImmutable($this->xml->meta->lastupdate);
+    }
+
+    public function getNextUpdate(): \DateTimeImmutable {
+        return new DateTimeImmutable($this->xml->meta->nextupdate);
+    }
+
+    public function getTabular(): Tabular {
+        return new Tabular($this->xml->forecast->tabular);
+    }
+
+}
+
+?>

+ 25 - 0
src/Yr/Forecast/Location.php

@@ -0,0 +1,25 @@
+<?php
+
+namespace App\Yr\Forecast;
+
+final class Location {
+    private $name;
+    private $type;
+    private $country;
+    private $tz;
+    private $loc = [];
+
+    public function __construct(\SimpleXMLElement $xml) {
+        $this->name = (string)$xml->name;
+        $this->type = (string)$xml->type;
+        $this->country = (string)$xml->country;
+        $this->tz = (string)$xml->timezone['id'];
+        $this->loc = [
+            'lat' => (float)$xml->location['latitude'],
+            'lng' => (float)$xml->location['longitude'],
+            'alt' => (float)$xml->location['altitude']
+        ];
+    }
+}
+
+?>

+ 45 - 0
src/Yr/Forecast/Tabular.php

@@ -0,0 +1,45 @@
+<?php
+
+namespace App\Yr\Forecast;
+
+use App\Yr\Forecast\Tabular\Statistics;
+use App\Yr\Forecast\Tabular\Time;
+
+class Tabular implements \IteratorAggregate {
+
+    private $time = [];
+    private $stats;
+
+    public function __construct(?\SimpleXMLElement $xml) {
+        $this->stats = new Statistics();
+
+        if ($xml != null)
+            foreach ($xml->time as $time)
+                $this->addTime(new Time($time));
+    }
+
+    protected function addTime(Time $time): self {
+        $this->time[] = $time;
+        $this->stats->analyse($time);
+        return $this;
+    }
+
+    public function getStatistics(): array {
+        return $this->stats;
+    }
+
+    public function getBetween(\DateTimeInterface $from, \DateTimeInterface $until): self {
+        $n = new Tabular(null);
+
+        foreach ($this as $time)
+            if ($time->getFrom() >= $from && $time->getUntil() <= $until)
+                $n->addTime($time);
+
+        return $n;
+    }
+
+    public function getIterator(): \Generator {
+        foreach ($this->time as $time)
+            yield $time;
+    }
+}

+ 22 - 0
src/Yr/Forecast/Tabular/Statistics.php

@@ -0,0 +1,22 @@
+<?php
+
+namespace App\Yr\Forecast\Tabular;
+
+class Statistics {
+    private $temp = [];
+    private $wind = [];
+    private $count = 0;
+
+    public function __construct() {
+        $this->temp = $this->wind = [
+            'high' => null,
+            'low' => null,
+            'mean' => 0
+        ];
+    }
+
+    public function analyse(Time $t) {
+
+    }
+}
+?>

+ 82 - 0
src/Yr/Forecast/Tabular/Time.php

@@ -0,0 +1,82 @@
+<?php
+
+namespace App\Yr\Forecast\Tabular;
+
+use App\Yr\Forecast\Tabular\Time\Pressure;
+use App\Yr\Forecast\Tabular\Time\Symbol;
+use App\Yr\Forecast\Tabular\Time\Temperature;
+use App\Yr\Forecast\Tabular\Time\WindDirection;
+use App\Yr\Forecast\Tabular\Time\WindSpeed;
+
+final class Time implements \IteratorAggregate {
+
+    private $from;
+    private $until;
+    private $period;
+    private $symbol;
+    private $windDirection;
+
+    public function __construct(\SimpleXMLElement $xml) {
+        $this->from = new \DateTimeImmutable($xml['from']);
+        $this->until = new \DateTimeImmutable($xml['to']);
+        $this->period = (int)$xml['period'];
+        $this->symbol = new Symbol($xml->symbol);
+        $this->windDirection = new WindDirection($xml->windDirection);
+        $this->windSpeed= new WindSpeed($xml->windSpeed);
+        $this->temperature = new Temperature($xml->temperature);
+        $this->pressure = new Pressure($xml->pressure);
+    }
+
+    public function getPeriod(): int {
+        return $this->period;
+    }
+
+    public function getFrom(): \DateTimeImmutable {
+        return $this->from;
+    }
+
+    public function getUntil(): \DateTimeImmutable {
+        return $this->until;
+    }
+
+    public function getSymbol(): Symbol {
+        return $this->symbol;
+    }
+
+    public function getWindDirection(): WindDirection {
+        return $this->getWindDirection();
+    }
+
+    public function getWindSpeed(): WindSpeed {
+        return $this->windSpeed;
+    }
+
+    public function getTemperature(): Temperature {
+        return $this->temperature;
+    }
+
+    public function getPressure(): Pressure {
+        return $this->pressure;
+    }
+
+    public function getIterator(): \Generator {
+        foreach ([
+            $this->getSymbol(),
+            $this->getWindDirection(),
+            $this->getWindSpeed(),
+            $this->getTemperature(),
+            $this->getPressure(),
+        ] as $entity)
+            yield $entity;
+    }
+
+    public function __toString(): string {
+        return sprintf(
+            '%s - %s: %s, %s, %s, %s, %s',
+            $this->from->format('H:i'), $this->until->format('H:i'),
+            $this->symbol, $this->windDirection, $this->windSpeed,
+            $this->temperature, $this->pressure
+        );
+    }
+
+}

+ 41 - 0
src/Yr/Forecast/Tabular/Time/AbstractUnit.php

@@ -0,0 +1,41 @@
+<?php
+
+namespace App\Yr\Forecast\Tabular\Time;
+
+abstract class AbstractUnit implements DiffInterface {
+    const DEFAULT_VARIANCE = 2;
+
+    private $value;
+    private $unit;
+
+    public function __construct(float $value, string $unit) {
+        $this->value = $value;
+        $this->unit = $unit;
+    }
+
+    public function getValue(): float {
+        return $this->value;
+    }
+
+    public function getUnit(): string {
+        return $this->unit;
+    }
+
+    public function setThresholdValue(int $t): self {
+        $this->threshold = $t;
+    }
+
+    public function diff(DiffInterface $d): bool {
+        if ($d instanceof $this)
+            return abs($this->value - $d->getValue()) > static::DEFAULT_VARIANCE;
+
+        return false;
+    }
+
+    public function __toString(): string {
+        return sprintf(
+            "%s: %f %s", basename(str_replace(
+                '\\', DIRECTORY_SEPARATOR, get_class($this)
+            )), $this->value, $this->unit);
+    }
+}

+ 25 - 0
src/Yr/Forecast/Tabular/Time/DiffEntity.php

@@ -0,0 +1,25 @@
+<?php
+
+namespace App\Yr\Forecast\Tabular\Time;
+
+class DiffEntity implements DiffInterface {
+
+    private $time;
+    private $entity;
+
+    public function __construct(Time $t, DiffInterface $d) {
+        $this->time = $t;
+        $this->entity = $d;
+    }
+
+    public function getOccuringTime(): \DateTimeInterface {
+        return $time->getFrom();
+    }
+
+    public function diff(DiffInterface $d): bool {
+        if ($d instanceof get_class($this->entity))
+            return $this->entity->diff($d);
+
+        return false;
+    }
+}

+ 8 - 0
src/Yr/Forecast/Tabular/Time/DiffInterface.php

@@ -0,0 +1,8 @@
+<?php
+
+namespace App\Yr\Forecast\Tabular\Time;
+
+interface DiffInterface {
+    public function diff(DiffInterface $e): bool;
+}
+

+ 14 - 0
src/Yr/Forecast/Tabular/Time/Pressure.php

@@ -0,0 +1,14 @@
+<?php
+
+namespace App\Yr\Forecast\Tabular\Time;
+
+
+class Pressure extends AbstractUnit {
+    public function __construct(\SimpleXMLElement $xml) {
+        parent::__construct(
+            (float)$xml['value'],
+            (string)$xml['unit']
+        );
+    }
+}
+

+ 45 - 0
src/Yr/Forecast/Tabular/Time/Symbol.php

@@ -0,0 +1,45 @@
+<?php
+
+namespace App\Yr\Forecast\Tabular\Time;
+
+class Symbol implements DiffInterface {
+
+    private $number;
+    private $numberEx;
+    private $name;
+    private $var;
+
+    public function __construct(\SimpleXMLElement $xml) {
+        $this->number = (int)$xml['number'];
+        $this->numberEx = (int)$xml['numberEx'];
+        $this->name = (string)$xml['name'];
+        $this->var = (string)$xml['var'];
+    }
+
+    public function getNumber(): int {
+        return $this->number;
+    }
+
+    public function getName(): string {
+        return $this->name;
+    }
+
+    public function getVar(): string {
+        return $this->var;
+    }
+
+    public function diff(DiffInterface $s): bool {
+        if ($s instanceof Symbol)
+            return $this->number != $s->getNumber();
+
+        return false;
+    }
+
+    public function __toString(): string {
+        return sprintf(
+            "%s (%d, %d, %s)", $this->name,
+            $this->number, $this->numberEx,
+            $this->var
+        );
+    }
+}

+ 13 - 0
src/Yr/Forecast/Tabular/Time/Temperature.php

@@ -0,0 +1,13 @@
+<?php
+
+namespace App\Yr\Forecast\Tabular\Time;
+
+class Temperature extends AbstractUnit {
+    public function __construct(\SimpleXMLElement $xml) {
+        parent::__construct(
+            (float)$xml['value'],
+            (string)$xml['unit']
+        );
+    }
+}
+

+ 27 - 0
src/Yr/Forecast/Tabular/Time/WindDirection.php

@@ -0,0 +1,27 @@
+<?php
+
+namespace App\Yr\Forecast\Tabular\Time;
+
+class WindDirection extends AbstractUnit{
+    private $name;
+
+    public function __construct(\SimpleXMLElement $xml) {
+        parent::__construct(
+            (float)$xml['deg'],
+            (string)$xml['code']
+        );
+
+        $this->name = (string)$xml['name'];
+    }
+
+    public function diff(DiffInterface $d): bool {
+        if (parent::diff($d))
+            return $this->getUnit() != $f->getUnit();
+        return false;
+    }
+
+    public function getName(): string {
+        return $this->name;
+    }
+
+}

+ 44 - 0
src/Yr/Forecast/Tabular/Time/WindSpeed.php

@@ -0,0 +1,44 @@
+<?php
+
+namespace App\Yr\Forecast\Tabular\Time;
+
+class WindSpeed extends AbstractUnit {
+    const DEFAULT_VARIANCE = (4.9 / 3.5);
+
+    const UNIT_MPS = 'mp/s';
+    const UNIT_FTS = 'ft/s';
+    const UNIT_KMH = 'km/h';
+    const UNIT_KNOTS = 'knots';
+
+    private $name;
+
+    public function __construct(\SimpleXMLElement $xml){
+        parent::__construct(
+            (float)$xml['mps'], self::UNIT_MPS
+        );
+
+        $this->name = (string)$xml['name'];
+    }
+
+    public function convertTo(string $unit): int {
+        switch ($unit) {
+        case self::UNIT_KNOTS:
+            return $this->getValue() * 1.9438445;
+        case self::UNIT_FTS:
+            return $this->getValue() * 3.28084;
+        case self::UNIT_KMH:
+            return $this->getValue() * 3.6;
+        }
+    }
+
+    public function getName(): string {
+        return $this->name;
+    }
+
+    public function __toString(): string {
+        return sprintf(
+            '%s (%s)', parent::__toString(), $this->name
+        );
+    }
+}
+