Refactor all of the unit conversion code

This commit is contained in:
Nabeel Shahzad
2018-04-07 20:52:12 -05:00
parent eae5989845
commit c102a0d858
25 changed files with 365 additions and 362 deletions

View File

@@ -62,9 +62,9 @@ class CreateSettingsTable extends Migration
$this->addSetting('units.distance', [ $this->addSetting('units.distance', [
'name' => 'Distance Units', 'name' => 'Distance Units',
'group' => 'units', 'group' => 'units',
'value' => 'NM', 'value' => 'nmi',
'type' => 'select', 'type' => 'select',
'options' => 'km=kilometers,mi=miles,NM=nautical miles', 'options' => 'km=kilometers,mi=miles,nmi=nautical miles',
'description' => 'The distance unit for display', 'description' => 'The distance unit for display',
]); ]);
@@ -116,9 +116,9 @@ class CreateSettingsTable extends Migration
$this->addSetting('units.temperature', [ $this->addSetting('units.temperature', [
'name' => 'Temperature Units', 'name' => 'Temperature Units',
'group' => 'units', 'group' => 'units',
'value' => 'f', 'value' => 'F',
'type' => 'select', 'type' => 'select',
'options' => 'f=Fahrenheit,c=Celsius', 'options' => 'F=Fahrenheit,C=Celsius',
'description' => 'The units for temperature', 'description' => 'The units for temperature',
]); ]);

View File

@@ -27,7 +27,7 @@ class Flight extends Resource
// Return multiple measures so the client can pick what they want // Return multiple measures so the client can pick what they want
if ($this->distance instanceof Distance) { if ($this->distance instanceof Distance) {
$flight['distance'] = $this->distance->toObject(); $flight['distance'] = $this->distance->units;
} }
$flight['airline'] = new Airline($this->airline); $flight['airline'] = new Airline($this->airline);

View File

@@ -9,7 +9,6 @@ class JournalTransaction extends Resource
public function toArray($request) public function toArray($request)
{ {
$transaction = parent::toArray($request); $transaction = parent::toArray($request);
return $transaction; return $transaction;
} }
} }

View File

@@ -19,15 +19,15 @@ class Pirep extends Resource
$pirep = parent::toArray($request); $pirep = parent::toArray($request);
if ($this->distance instanceof Distance) { if ($this->distance instanceof Distance) {
$pirep['distance'] = $this->distance->toObject(); $pirep['distance'] = $this->distance->units;
} }
if ($this->fuel_used instanceof Fuel) { if ($this->fuel_used instanceof Fuel) {
$pirep['fuel_used'] = $this->fuel_used->toObject(); $pirep['fuel_used'] = $this->fuel_used->units;
} }
if ($this->planned_distance instanceof Distance) { if ($this->planned_distance instanceof Distance) {
$pirep['planned_distance'] = $this->planned_distance->toObject(); $pirep['planned_distance'] = $this->planned_distance->units;
} }
/* /*

View File

@@ -5,9 +5,16 @@ namespace App\Interfaces;
/** /**
* Class Model * Class Model
* @property mixed $id * @property mixed $id
* @property bool $skip_mutator
* @package App\Interfaces * @package App\Interfaces
*/ */
abstract class Model extends \Illuminate\Database\Eloquent\Model abstract class Model extends \Illuminate\Database\Eloquent\Model
{ {
public const ID_MAX_LENGTH = 12; public const ID_MAX_LENGTH = 12;
/**
* For the factories, skip the mutators. Only apply to one instance
* @var bool
*/
public $skip_mutator = false;
} }

87
app/Interfaces/Unit.php Normal file
View File

@@ -0,0 +1,87 @@
<?php
namespace App\Interfaces;
use ArrayAccess;
/**
* Class Unit
* @package App\Interfaces
* @property mixed $instance
* @property string $unit
* @property array $units
*/
class Unit implements ArrayAccess
{
/**
* The unit this is kept as
*/
public $unit;
/**
* All of the units of this class
* @var array
*/
public $units;
/**
* Holds an instance of the PhpUnit type
* @var
*/
protected $instance;
/**
* @return mixed
*/
public function value()
{
return $this->__toString();
}
/**
* Implements ArrayAccess
* @param $offset
* @return bool
*/
public function offsetExists($offset)
{
return array_key_exists($offset, $this->units);
}
/**
* Implements ArrayAccess
* @param $offset
* @return mixed
*/
public function offsetGet($offset)
{
return $this->units[$offset];
}
/**
* Implements ArrayAccess
* @param $offset
* @param $value
*/
public function offsetSet($offset, $value)
{
$this->units[$offset] = $value;
}
/**
* Implements ArrayAccess
* @param $offset
*/
public function offsetUnset($offset)
{
$this->units[$offset] = null;
}
/**
* @return mixed
*/
public function __toString()
{
return (string) $this->units[$this->unit];
}
}

View File

@@ -148,6 +148,9 @@ class Pirep extends Model
try { try {
$distance = (float) $this->attributes['distance']; $distance = (float) $this->attributes['distance'];
if ($this->skip_mutator) {
return $distance;
}
return new Distance($distance, config('phpvms.internal_units.distance')); return new Distance($distance, config('phpvms.internal_units.distance'));
} catch (NonNumericValue $e) { } catch (NonNumericValue $e) {
@@ -204,6 +207,9 @@ class Pirep extends Model
try { try {
$distance = (float) $this->attributes['planned_distance']; $distance = (float) $this->attributes['planned_distance'];
if ($this->skip_mutator) {
return $distance;
}
return new Distance($distance, config('phpvms.internal_units.distance')); return new Distance($distance, config('phpvms.internal_units.distance'));
} catch (NonNumericValue $e) { } catch (NonNumericValue $e) {

View File

@@ -37,7 +37,7 @@ class FlightExporter extends ImportExport
# Modify special fields # Modify special fields
$ret['airline'] = $ret['airline']->icao; $ret['airline'] = $ret['airline']->icao;
$ret['distance'] = $ret['distance']->toNumber(); $ret['distance'] = $ret['distance'][config('phpvms.internal_units.distance')];
$ret['dpt_airport'] = $flight->dpt_airport_id; $ret['dpt_airport'] = $flight->dpt_airport_id;
$ret['arr_airport'] = $flight->arr_airport_id; $ret['arr_airport'] = $flight->arr_airport_id;

View File

@@ -2,6 +2,10 @@
namespace App\Support; namespace App\Support;
use App\Support\Units\Altitude;
use App\Support\Units\Distance;
use App\Support\Units\Temperature;
/** /**
* Class Metar * Class Metar
* @package App\Support * @package App\Support
@@ -27,7 +31,7 @@ namespace App\Support;
or TAF. In addition to the return METAR parameters, the script also displays the or TAF. In addition to the return METAR parameters, the script also displays the
interpreted (easy to understand) information of these parameters. interpreted (easy to understand) information of these parameters.
*/ */
class Metar class Metar implements \ArrayAccess
{ {
/* /*
* Array of decoded result, by default all parameters is null. * Array of decoded result, by default all parameters is null.
@@ -64,17 +68,12 @@ class Metar
'clouds_report' => null, 'clouds_report' => null,
'clouds_report_ft' => null, 'clouds_report_ft' => null,
'cloud_height' => null, 'cloud_height' => null,
'cloud_height_ft' => null,
'cavok' => null, 'cavok' => null,
'temperature' => null, 'temperature' => null,
'temperature_f' => null,
'dew_point' => null, 'dew_point' => null,
'dew_point_f' => null,
'humidity' => null, 'humidity' => null,
'heat_index' => null, 'heat_index' => null,
'heat_index_f' => null,
'wind_chill' => null, 'wind_chill' => null,
'wind_chill_f' => null,
'barometer' => null, 'barometer' => null,
'barometer_in' => null, 'barometer_in' => null,
'barometer_mb' => null, 'barometer_mb' => null,
@@ -302,6 +301,7 @@ class Metar
*/ */
private $debug = []; private $debug = [];
private $debug_enabled; private $debug_enabled;
public $errors = []; public $errors = [];
@@ -310,8 +310,11 @@ class Metar
* Other variables. * Other variables.
*/ */
private $raw; private $raw;
private $raw_parts = []; private $raw_parts = [];
private $method = 0; private $method = 0;
private $part = 0; private $part = 0;
/** /**
@@ -433,9 +436,8 @@ class Metar
// Finally determine if it's VFR or IFR conditions // Finally determine if it's VFR or IFR conditions
// https://www.aviationweather.gov/cva/help // https://www.aviationweather.gov/cva/help
if($this->result['cavok'] if ($this->result['cavok']
|| ($this->result['cloud_height_ft'] > 3000 && $this->result['visibility_nm'] > 5)) || ($this->result['cloud_height']['ft'] > 3000 && $this->result['visibility_nm'] > 5)) {
{
$this->result['category'] = 'VFR'; $this->result['category'] = 'VFR';
} else { } else {
$this->result['category'] = 'IFR'; $this->result['category'] = 'IFR';
@@ -524,7 +526,6 @@ class Metar
if ($this->result[$parameter] !== null) { if ($this->result[$parameter] !== null) {
$this->result[$parameter] = ucfirst(ltrim($this->result[$parameter], ' '.$separator)); $this->result[$parameter] = ucfirst(ltrim($this->result[$parameter], ' '.$separator));
} }
//$this->set_debug('Add group report value "'.$report.'" for parameter: '.$parameter); //$this->set_debug('Add group report value "'.$report.'" for parameter: '.$parameter);
} }
@@ -559,8 +560,7 @@ class Metar
} }
if ($this->raw_parts[$this->part + 1] === 'COR' if ($this->raw_parts[$this->part + 1] === 'COR'
|| $this->raw_parts[$this->part + 1] === 'AMD') || $this->raw_parts[$this->part + 1] === 'AMD') {
{
$this->set_result_value('taf_flag', $this->raw_parts[$this->part + 1], true); $this->set_result_value('taf_flag', $this->raw_parts[$this->part + 1], true);
$this->part++; $this->part++;
} }
@@ -657,7 +657,6 @@ class Metar
$this->set_result_value('wind_direction_varies', false, true); $this->set_result_value('wind_direction_varies', false, true);
if ($found[1] === '///' && $found[2] === '//') { if ($found[1] === '///' && $found[2] === '//') {
} // handle the case where nothing is observed } // handle the case where nothing is observed
else { else {
$unit = $found[5]; $unit = $found[5];
@@ -721,6 +720,8 @@ class Metar
* if visibility is limited to an integer mile plus a fraction part. * if visibility is limited to an integer mile plus a fraction part.
* Format is mmSM for mm = statute miles, or m n/dSM for m = mile and n/d = fraction of a mile, * Format is mmSM for mm = statute miles, or m n/dSM for m = mile and n/d = fraction of a mile,
* or just a 4-digit number nnnn (with leading zeros) for nnnn = meters. * or just a 4-digit number nnnn (with leading zeros) for nnnn = meters.
* @throws \PhpUnitsOfMeasure\Exception\NonStringUnitName
* @throws \PhpUnitsOfMeasure\Exception\NonNumericValue
*/ */
private function get_visibility($part) private function get_visibility($part)
{ {
@@ -739,16 +740,13 @@ class Metar
// Cloud and visibilty OK or ICAO visibilty greater than 10 km // Cloud and visibilty OK or ICAO visibilty greater than 10 km
if ($found[1] === 'CAVOK' || $found[1] === '9999') { if ($found[1] === 'CAVOK' || $found[1] === '9999') {
$this->set_result_value('visibility', 10000); $this->set_result_value('visibility', new Distance(10000, 'm'));
$this->set_result_value('visibility_report', 'Greater than 10 km'); $this->set_result_value('visibility_report', 'Greater than 10 km');
if ($found[1] === 'CAVOK') { if ($found[1] === 'CAVOK') {
$this->set_result_value('cavok', true); $this->set_result_value('cavok', true);
$this->method += 4; // can skip the next 4 methods: visibility_min, runway_vr, present_weather, clouds $this->method += 4; // can skip the next 4 methods: visibility_min, runway_vr, present_weather, clouds
} }
} elseif ($found[1] === '////') {
}
elseif ($found[1] === '////') {
} // information not available } // information not available
else { else {
@@ -756,11 +754,8 @@ class Metar
// ICAO visibility (in meters) // ICAO visibility (in meters)
if (isset($found[2]) && !empty($found[2])) { if (isset($found[2]) && !empty($found[2])) {
$visibility = (int) $found[2]; $visibility = new Distance((int) $found[2], 'm');
$visibility_miles = $this->meters_to_nm($visibility); } // US visibility (in miles)
}
// US visibility (in miles)
else { else {
if (isset($found[3]) && !empty($found[3])) { if (isset($found[3]) && !empty($found[3])) {
$prefix = 'Less than '; $prefix = 'Less than ';
@@ -772,17 +767,15 @@ class Metar
$visibility = (int) $found[4]; $visibility = (int) $found[4];
} }
$visibility_miles = $visibility; $visibility = new Distance($visibility, 'mi');
$visibility = $this->convert_distance($visibility, 'SM'); // convert to meters
} }
$unit = ' meters'; $unit = ' meters';
if ($visibility <= 1) { if ($visibility['m'] <= 1) {
$unit = ' meter'; $unit = ' meter';
} }
$this->set_result_value('visibility', $visibility); $this->set_result_value('visibility', $visibility);
$this->set_result_value('visibility_nm', $visibility_miles);
$this->set_result_value('visibility_report', $prefix.$visibility.$unit); $this->set_result_value('visibility_report', $prefix.$visibility.$unit);
} }
@@ -822,6 +815,8 @@ class Metar
* and FT = the visibility in feet. * and FT = the visibility in feet.
* @param $part * @param $part
* @return bool * @return bool
* @throws \PhpUnitsOfMeasure\Exception\NonStringUnitName
* @throws \PhpUnitsOfMeasure\Exception\NonNumericValue
*/ */
private function get_runway_vr($part) private function get_runway_vr($part)
{ {
@@ -840,9 +835,9 @@ class Metar
return false; return false;
} }
$unit = 'M'; $unit = 'meter';
if (isset($found[6]) && $found[6] === 'FT') { if (isset($found[6]) && $found[6] === 'FT') {
$unit = 'FT'; $unit = 'feet';
} }
$observed = [ $observed = [
@@ -863,13 +858,13 @@ class Metar
// Runway visual range // Runway visual range
if (isset($found[6])) { if (isset($found[6])) {
if (!empty($found[4])) { if (!empty($found[4])) {
$observed['interval_min'] = $this->convert_distance($found[4], $unit); $observed['interval_min'] = new Distance($found[4], $unit);
$observed['interval_max'] = $this->convert_distance($found[6], $unit); $observed['interval_max'] = new Distance($found[6], $unit);
if (!empty($found[5])) { if (!empty($found[5])) {
$observed['variable_prefix'] = $found[5]; $observed['variable_prefix'] = $found[5];
} }
} else { } else {
$observed['variable'] = $this->convert_distance($found[6], $unit); $observed['variable'] = new Distance($found[6], $unit);
} }
} }
@@ -883,9 +878,7 @@ class Metar
} }
$report[] = $observed['variable'].$unit; $report[] = $observed['variable'].$unit;
} } elseif (null !== $observed['interval_min'] && null !== $observed['interval_max']) {
elseif (null !== $observed['interval_min'] && null !== $observed['interval_max']) {
if (isset(static::$rvr_prefix_codes[$observed['variable_prefix']])) { if (isset(static::$rvr_prefix_codes[$observed['variable_prefix']])) {
$report[] = 'varying from a min. of '.$observed['interval_min'].' meters until a max. of '. $report[] = 'varying from a min. of '.$observed['interval_min'].' meters until a max. of '.
static::$rvr_prefix_codes[$observed['variable_prefix']].' that '. static::$rvr_prefix_codes[$observed['variable_prefix']].' that '.
@@ -928,6 +921,8 @@ class Metar
* very low cloud layers. * very low cloud layers.
* @param $part * @param $part
* @return bool * @return bool
* @throws \PhpUnitsOfMeasure\Exception\NonStringUnitName
* @throws \PhpUnitsOfMeasure\Exception\NonNumericValue
*/ */
private function get_clouds($part) private function get_clouds($part)
{ {
@@ -943,7 +938,6 @@ class Metar
$observed = [ $observed = [
'amount' => null, 'amount' => null,
'height' => null, 'height' => null,
'height_ft' => null,
'type' => null, 'type' => null,
'report' => null, 'report' => null,
]; ];
@@ -953,18 +947,13 @@ class Metar
if (isset(static::$cloud_codes[$found[2]])) { if (isset(static::$cloud_codes[$found[2]])) {
$observed['amount'] = $found[2]; $observed['amount'] = $found[2];
} }
} } // Cloud cover observed
// Cloud cover observed
elseif (isset($found[5]) && !empty($found[5])) { elseif (isset($found[5]) && !empty($found[5])) {
$observed['height'] = new Altitude($found[5] * 100, 'feet');
$observed['height'] = $this->convert_distance($found[5] * 100, 'FT'); // convert feet to meters
$observed['height_ft'] = $this->meters_to_ft($observed['height']);
// Cloud height // Cloud height
if (null === $this->result['cloud_height'] || $observed['height'] < $this->result['cloud_height']) { if (null === $this->result['cloud_height']['m'] || $observed['height']['m'] < $this->result['cloud_height']['m']) {
$this->set_result_value('cloud_height', $observed['height']); $this->set_result_value('cloud_height', $observed['height']);
$this->set_result_value('cloud_height_ft', $observed['height_ft']);
} }
if (isset(static::$cloud_codes[$found[4]])) { if (isset(static::$cloud_codes[$found[4]])) {
@@ -978,7 +967,6 @@ class Metar
// Build clouds report // Build clouds report
if (null !== $observed['amount']) { if (null !== $observed['amount']) {
$report = []; $report = [];
$report_ft = []; $report_ft = [];
@@ -987,11 +975,11 @@ class Metar
if ($observed['height']) { if ($observed['height']) {
if (null !== $observed['type']) { if (null !== $observed['type']) {
$report[] = 'at '.$observed['height'].' meters, '.static::$cloud_type_codes[$observed['type']]; $report[] = 'at '.round($observed['height']['m'], 0).' meters, '.static::$cloud_type_codes[$observed['type']];
$report_ft[] = 'at '.$observed['height_ft'].' feet, '.static::$cloud_type_codes[$observed['type']]; $report_ft[] = 'at '.round($observed['height']['ft'], 0).' feet, '.static::$cloud_type_codes[$observed['type']];
} else { } else {
$report[] = 'at '.$observed['height'].' meters'; $report[] = 'at ' . round($observed['height']['m'], 0) . ' meters';
$report_ft[] = 'at '.$observed['height_ft'].' feet'; $report_ft[] = 'at ' . round($observed['height']['ft'], 0) . ' feet';
} }
} }
@@ -1015,6 +1003,8 @@ class Metar
* Format is tt/dd where tt = temperature and dd = dew point temperature. All units are * Format is tt/dd where tt = temperature and dd = dew point temperature. All units are
* in Celsius. A 'M' preceeding the tt or dd indicates a negative temperature. Some * in Celsius. A 'M' preceeding the tt or dd indicates a negative temperature. Some
* stations do not report dew point, so the format is tt/ or tt/XX. * stations do not report dew point, so the format is tt/ or tt/XX.
* @throws \PhpUnitsOfMeasure\Exception\NonStringUnitName
* @throws \PhpUnitsOfMeasure\Exception\NonNumericValue
*/ */
private function get_temperature($part) private function get_temperature($part)
{ {
@@ -1031,22 +1021,20 @@ class Metar
// Temperature // Temperature
$temperature_c = (int) str_replace('M', '-', $found[1]); $temperature_c = (int) str_replace('M', '-', $found[1]);
$temperature_f = round(1.8 * $temperature_c + 32); $temperature = new Temperature($temperature_c, 'C');
$this->set_result_value('temperature', $temperature_c); $this->set_result_value('temperature', $temperature);
$this->set_result_value('temperature_f', $temperature_f); $this->calculate_wind_chill($temperature['f']);
$this->calculate_wind_chill($temperature_f);
// Dew point // Dew point
if (isset($found[2]) && '' !== $found[2] && $found[2] != 'XX') { if (isset($found[2]) && '' !== $found[2] && $found[2] !== 'XX') {
$dew_point_c = (int) str_replace('M', '-', $found[2]); $dew_point_c = (int) str_replace('M', '-', $found[2]);
$dew_point_f = round(1.8 * $dew_point_c + 32); $dew_point = new Temperature($dew_point_c, 'C');
$rh = round(100 * (((112 - (0.1 * $temperature_c) + $dew_point_c) / (112 + (0.9 * $temperature_c))) ** 8)); $rh = round(100 * (((112 - (0.1 * $temperature_c) + $dew_point_c) / (112 + (0.9 * $temperature_c))) ** 8));
$this->set_result_value('dew_point', $dew_point_c); $this->set_result_value('dew_point', $dew_point);
$this->set_result_value('dew_point_f', $dew_point_f);
$this->set_result_value('humidity', $rh); $this->set_result_value('humidity', $rh);
$this->calculate_heat_index($temperature_f, $rh); $this->calculate_heat_index($temperature['f'], $rh);
} }
$this->method++; $this->method++;
@@ -1124,7 +1112,6 @@ class Metar
$observed['deposits'] = 0; // cleared $observed['deposits'] = 0; // cleared
} // Deposits observed } // Deposits observed
else { else {
// Type // Type
$deposits = $found[5]; $deposits = $found[5];
if (isset(static::$runway_deposits_codes[$deposits])) { if (isset(static::$runway_deposits_codes[$deposits])) {
@@ -1163,7 +1150,6 @@ class Metar
// Build runways report // Build runways report
$report = []; $report = [];
if (null !== $observed['deposits']) { if (null !== $observed['deposits']) {
$report[] = static::$runway_deposits_codes[$observed['deposits']]; $report[] = static::$runway_deposits_codes[$observed['deposits']];
if (null !== $observed['deposits_extent']) { if (null !== $observed['deposits_extent']) {
$report[] = 'contamination '.static::$runway_deposits_extent_codes[$observed['deposits_extent']]; $report[] = 'contamination '.static::$runway_deposits_extent_codes[$observed['deposits_extent']];
@@ -1537,6 +1523,8 @@ class Metar
* Calculate Heat Index based on temperature in F and relative humidity (65 = 65%) * Calculate Heat Index based on temperature in F and relative humidity (65 = 65%)
* @param $temperature_f * @param $temperature_f
* @param $rh * @param $rh
* @throws \PhpUnitsOfMeasure\Exception\NonNumericValue
* @throws \PhpUnitsOfMeasure\Exception\NonStringUnitName
*/ */
private function calculate_heat_index($temperature_f, $rh): void private function calculate_heat_index($temperature_f, $rh): void
{ {
@@ -1548,14 +1536,15 @@ class Metar
$hi_f = round($hi_f); $hi_f = round($hi_f);
$hi_c = round(($hi_f - 32) / 1.8); $hi_c = round(($hi_f - 32) / 1.8);
$this->set_result_value('heat_index', $hi_c); $this->set_result_value('heat_index', new Temperature($hi_c, 'C'));
$this->set_result_value('heat_index_f', $hi_f);
} }
} }
/** /**
* Calculate Wind Chill Temperature based on temperature in F * Calculate Wind Chill Temperature based on temperature in F
* and wind speed in miles per hour. * and wind speed in miles per hour.
* @throws \PhpUnitsOfMeasure\Exception\NonNumericValue
* @throws \PhpUnitsOfMeasure\Exception\NonStringUnitName
*/ */
private function calculate_wind_chill($temperature_f): void private function calculate_wind_chill($temperature_f): void
{ {
@@ -1567,8 +1556,7 @@ class Metar
$chill_f = round($chill_f); $chill_f = round($chill_f);
$chill_c = round(($chill_f - 32) / 1.8); $chill_c = round(($chill_f - 32) / 1.8);
$this->set_result_value('wind_chill', $chill_c); $this->set_result_value('wind_chill', new Temperature($chill_c, 'C'));
$this->set_result_value('wind_chill_f', $chill_f);
} }
} }
} }
@@ -1649,4 +1637,66 @@ class Metar
return null; return null;
} }
/**
* Whether a offset exists
* @link http://php.net/manual/en/arrayaccess.offsetexists.php
* @param mixed $offset <p>
* An offset to check for.
* </p>
* @return boolean true on success or false on failure.
* </p>
* <p>
* The return value will be casted to boolean if non-boolean was returned.
* @since 5.0.0
*/
public function offsetExists($offset)
{
return array_key_exists($offset, $this->result);
}
/**
* Offset to retrieve
* @link http://php.net/manual/en/arrayaccess.offsetget.php
* @param mixed $offset <p>
* The offset to retrieve.
* </p>
* @return mixed Can return all value types.
* @since 5.0.0
*/
public function offsetGet($offset)
{
return $this->result[$offset];
}
/**
* Offset to set
* @link http://php.net/manual/en/arrayaccess.offsetset.php
* @param mixed $offset <p>
* The offset to assign the value to.
* </p>
* @param mixed $value <p>
* The value to set.
* </p>
* @return void
* @since 5.0.0
*/
public function offsetSet($offset, $value)
{
$this->result[$offset] = $value;
}
/**
* Offset to unset
* @link http://php.net/manual/en/arrayaccess.offsetunset.php
* @param mixed $offset <p>
* The offset to unset.
* </p>
* @return void
* @since 5.0.0
*/
public function offsetUnset($offset)
{
$this->result[$offset] = null;
}
} }

View File

@@ -2,52 +2,29 @@
namespace App\Support\Units; namespace App\Support\Units;
use Illuminate\Contracts\Support\Arrayable; use App\Interfaces\Unit;
use PhpUnitsOfMeasure\PhysicalQuantity\Length;
/** /**
* Wrap the converter class
* @package App\Support\Units * @package App\Support\Units
*/ */
class Altitude extends \PhpUnitsOfMeasure\PhysicalQuantity\Length implements Arrayable class Altitude extends Unit
{ {
/** /**
* @return string * @param float $value
* @param string $unit
* @throws \PhpUnitsOfMeasure\Exception\NonNumericValue
* @throws \PhpUnitsOfMeasure\Exception\NonStringUnitName
*/ */
public function __toString() public function __construct(float $value, string $unit)
{ {
$unit = setting('units.altitude'); $this->unit = setting('units.altitude');
$value = $this->toUnit($unit); $this->instance = new Length($value, $unit);
return (string) round($value, 2); $this->units = [
} 'm' => round($this->instance->toUnit('meters'), 2),
'km' => round($this->instance->toUnit('meters') / 1000, 2),
/** 'ft' => round($this->instance->toUnit('feet'), 2),
* Return value in native unit as integer
* @return array
*/
public function toNumber()
{
return $this->toArray();
}
/**
* For the HTTP Resource call
*/
public function toObject()
{
return [
'ft' => round($this->toUnit('feet'), 2),
'm' => round($this->toUnit('meters') / 1000, 2),
]; ];
} }
/**
* Get the instance as an array.
*/
public function toArray()
{
return round($this->toUnit(
config('phpvms.internal_units.altitude')
), 2);
}
} }

View File

@@ -2,53 +2,31 @@
namespace App\Support\Units; namespace App\Support\Units;
use Illuminate\Contracts\Support\Arrayable; use App\Interfaces\Unit;
use PhpUnitsOfMeasure\PhysicalQuantity\Length;
/** /**
* Wrap the converter class
* @package App\Support\Units * @package App\Support\Units
*/ */
class Distance extends \PhpUnitsOfMeasure\PhysicalQuantity\Length implements Arrayable class Distance extends Unit
{ {
/** /**
* @return string * Distance constructor.
* @param float $value
* @param string $unit
* @throws \PhpUnitsOfMeasure\Exception\NonNumericValue
* @throws \PhpUnitsOfMeasure\Exception\NonStringUnitName
*/ */
public function __toString() public function __construct(float $value, string $unit)
{ {
$unit = setting('units.distance'); $this->unit = setting('units.distance');
$value = $this->toUnit($unit); $this->instance = new Length($value, $unit);
return (string) round($value, 2); $this->units = [
} 'mi' => round($this->instance->toUnit('miles'), 2),
'nmi' => round($this->instance->toUnit('nmi'), 2),
/** 'm' => round($this->instance->toUnit('meters'), 2),
* Return value in native unit as integer 'km' => round($this->instance->toUnit('meters') / 1000, 2),
* @return array
*/
public function toNumber()
{
return $this->toArray();
}
/**
* For the HTTP Resource call
*/
public function toObject(): array
{
return [
'mi' => round($this->toUnit('miles'), 2),
'nmi' => round($this->toUnit('nmi'), 2),
'km' => round($this->toUnit('meters') / 1000, 2),
]; ];
} }
/**
* Get the instance as an array.
*/
public function toArray()
{
return round($this->toUnit(
config('phpvms.internal_units.distance')
), 2);
}
} }

View File

@@ -2,53 +2,28 @@
namespace App\Support\Units; namespace App\Support\Units;
use Illuminate\Contracts\Support\Arrayable; use App\Interfaces\Unit;
use PhpUnitsOfMeasure\PhysicalQuantity\Mass;
/** /**
* Class Mass
* @package App\Support\Units * @package App\Support\Units
*/ */
class Fuel extends \PhpUnitsOfMeasure\PhysicalQuantity\Mass implements Arrayable class Fuel extends Unit
{ {
/** /**
* @return string * @param float $value
* @param string $unit
* @throws \PhpUnitsOfMeasure\Exception\NonNumericValue
* @throws \PhpUnitsOfMeasure\Exception\NonStringUnitName
*/ */
public function __toString() public function __construct(float $value, string $unit)
{ {
$unit = setting('units.fuel'); $this->unit = setting('units.fuel');
$value = $this->toUnit($unit); $this->instance = new Mass($value, $unit);
return (string) round($value, 2); $this->units = [
} 'kg' => round($this->instance->toUnit('kg'), 2),
'lbs' => round($this->instance->toUnit('lbs'), 2),
/**
* Return value in native unit as integer
* @return array
*/
public function toNumber()
{
return $this->toArray();
}
/**
* For the HTTP Resource call
*/
public function toObject()
{
return [
'kg' => round($this->toUnit('kg'), 2),
'lbs' => round($this->toUnit('lbs'), 2),
]; ];
} }
/**
* Get the instance as an array.
* @return array
*/
public function toArray()
{
return round($this->toUnit(
config('phpvms.internal_units.fuel')
), 2);
}
} }

View File

@@ -2,53 +2,28 @@
namespace App\Support\Units; namespace App\Support\Units;
use Illuminate\Contracts\Support\Arrayable; use App\Interfaces\Unit;
use PhpUnitsOfMeasure\PhysicalQuantity\Mass as MassUnit;
/** /**
* Class Mass
* @package App\Support\Units * @package App\Support\Units
*/ */
class Mass extends \PhpUnitsOfMeasure\PhysicalQuantity\Mass implements Arrayable class Mass extends Unit
{ {
/** /**
* @return string * @param float $value
* @param string $unit
* @throws \PhpUnitsOfMeasure\Exception\NonNumericValue
* @throws \PhpUnitsOfMeasure\Exception\NonStringUnitName
*/ */
public function __toString() public function __construct(float $value, string $unit)
{ {
$unit = setting('units.weight'); $this->unit = setting('units.weight');
$value = $this->toUnit($unit); $this->instance = new MassUnit($value, $unit);
return (string) round($value, 2); $this->units = [
} 'kg' => round($this->instance->toUnit('kg'), 2),
'lbs' => round($this->instance->toUnit('lbs'), 2),
/**
* Return value in native unit as integer
* @return array
*/
public function toNumber()
{
return $this->toArray();
}
/**
* For the HTTP Resource call
*/
public function toObject()
{
return [
'kg' => round($this->toUnit('kg'), 2),
'lbs' => round($this->toUnit('lbs'), 2),
]; ];
} }
/**
* Get the instance as an array.
* @return array
*/
public function toArray()
{
return round($this->toUnit(
config('phpvms.internal_units.mass')
), 2);
}
} }

View File

@@ -2,50 +2,31 @@
namespace App\Support\Units; namespace App\Support\Units;
use Illuminate\Contracts\Support\Arrayable; use App\Interfaces\Unit;
use PhpUnitsOfMeasure\PhysicalQuantity\Temperature as TemperatureUnit;
/** /**
* Wrap the converter class * Composition for the converter
* @package App\Support\Units * @package App\Support\Units
*/ */
class Temperature extends \PhpUnitsOfMeasure\PhysicalQuantity\Temperature implements Arrayable class Temperature extends Unit
{ {
/** /**
* @return string * @param float $value
* @param string $unit
* @throws \PhpUnitsOfMeasure\Exception\NonNumericValue
* @throws \PhpUnitsOfMeasure\Exception\NonStringUnitName
*/ */
public function __toString() public function __construct(float $value, string $unit)
{ {
$unit = strtoupper(setting('units.temperature')); $this->unit = setting('units.temperature');
$value = $this->toUnit($unit); $this->instance = new TemperatureUnit($value, $unit);
return (string) round($value, 2); $this->units = [
} 'F' => round($this->instance->toUnit('F'), 2),
'f' => round($this->instance->toUnit('F'), 2),
/** 'C' => round($this->instance->toUnit('C'), 2),
* Return value in native unit as integer 'c' => round($this->instance->toUnit('C'), 2),
* @return array
*/
public function toNumber()
{
return $this->toArray();
}
/**
* For the HTTP Resource call
*/
public function toObject()
{
return [
'f' => round($this->toUnit('F'), 2),
'c' => round($this->toUnit('C') / 1000, 2),
]; ];
} }
/**
* Get the instance as an array.
*/
public function toArray()
{
return $this->__toString();
}
} }

View File

@@ -11,7 +11,7 @@ use Illuminate\Contracts\Support\Arrayable;
class Time implements Arrayable class Time implements Arrayable
{ {
public $hours, public $hours,
$minutes; $minutes;
/** /**
* @param $minutes * @param $minutes

View File

@@ -2,52 +2,29 @@
namespace App\Support\Units; namespace App\Support\Units;
use Illuminate\Contracts\Support\Arrayable; use App\Interfaces\Unit;
use PhpUnitsOfMeasure\PhysicalQuantity\Velocity as VelocityUnit;
/** /**
* Class Velocity * Class Velocity
* @package App\Support\Units * @package App\Support\Units
*/ */
class Velocity extends \PhpUnitsOfMeasure\PhysicalQuantity\Velocity implements Arrayable class Velocity extends Unit
{ {
/** /**
* @return string * @param float $value
* @param string $unit
* @throws \PhpUnitsOfMeasure\Exception\NonNumericValue
* @throws \PhpUnitsOfMeasure\Exception\NonStringUnitName
*/ */
public function __toString() public function __construct(float $value, string $unit)
{ {
$unit = setting('units.speed'); $this->unit = setting('units.speed');
$value = $this->toUnit($unit); $this->instance = new VelocityUnit($value, $unit);
return (string) round($value, 2); $this->units = [
} 'knots' => round($this->instance->toUnit('knots'), 2),
'km/h' => round($this->instance->toUnit('km/h'), 2),
/**
* Return value in native unit as integer
* @return array
*/
public function toNumber()
{
return $this->toArray();
}
/**
* For the HTTP Resource call
*/
public function toObject()
{
return [
'knots' => round($this->toUnit('knots'), 2),
'km/h' => round($this->toUnit('km/h'), 2),
]; ];
} }
/**
* Get the instance as an array.
*/
public function toArray()
{
return round($this->toUnit(
config('phpvms.internal_units.velocity')
), 2);
}
} }

View File

@@ -2,52 +2,29 @@
namespace App\Support\Units; namespace App\Support\Units;
use Illuminate\Contracts\Support\Arrayable; use App\Interfaces\Unit;
use PhpUnitsOfMeasure\PhysicalQuantity\Volume as VolumeUnit;
/** /**
* Wrap the converter class * Wrap the converter class
* @package App\Support\Units * @package App\Support\Units
*/ */
class Volume extends \PhpUnitsOfMeasure\PhysicalQuantity\Volume implements Arrayable class Volume extends Unit
{ {
/** /**
* @return string * @param float $value
* @param string $unit
* @throws \PhpUnitsOfMeasure\Exception\NonNumericValue
* @throws \PhpUnitsOfMeasure\Exception\NonStringUnitName
*/ */
public function __toString() public function __construct(float $value, string $unit)
{ {
$unit = setting('units.volume'); $this->unit = setting('units.volume');
$value = $this->toUnit($unit); $this->instance = new VolumeUnit($value, $unit);
return (string) round($value, 2); $this->units = [
} 'gal' => round($this->instance->toUnit('gal'), 2),
'liters' => round($this->instance->toUnit('liters'), 2),
/**
* Return value in native unit as integer
* @return array
*/
public function toNumber()
{
return $this->toArray();
}
/**
* For the HTTP Resource call
*/
public function toObject()
{
return [
'gal' => round($this->toUnit('gal'), 2),
'liters' => round($this->toUnit('liters'), 2),
]; ];
} }
/**
* Get the instance as an array.
*/
public function toArray()
{
return round($this->toUnit(
config('phpvms.internal_units.volume')
), 2);
}
} }

View File

@@ -33,7 +33,7 @@ class Weather extends Widget
$raw_metar = $metar_class->get_metar($this->config['icao']); $raw_metar = $metar_class->get_metar($this->config['icao']);
if ($raw_metar && $raw_metar !== '') { if ($raw_metar && $raw_metar !== '') {
$metar = Metar::parse($raw_metar); $metar = new Metar($raw_metar);
} }
return view('widgets.weather', [ return view('widgets.weather', [

View File

@@ -7,8 +7,8 @@
convertNoticesToExceptions="false" convertNoticesToExceptions="false"
convertWarningsToExceptions="false" convertWarningsToExceptions="false"
beStrictAboutOutputDuringTests="false" beStrictAboutOutputDuringTests="false"
printerClass="Codedungeon\PHPUnitPrettyResultPrinter\Printer"
beStrictAboutTestsThatDoNotTestAnything="false"> beStrictAboutTestsThatDoNotTestAnything="false">
<!--printerClass="Codedungeon\PHPUnitPrettyResultPrinter\Printer"-->
<testsuites> <testsuites>
<testsuite name="Application Test Suite"> <testsuite name="Application Test Suite">
<directory suffix="Test.php">./tests</directory> <directory suffix="Test.php">./tests</directory>

View File

@@ -66,7 +66,7 @@
{{ Widget::Weather([ {{ Widget::Weather([
'icao' => $flight->dpt_airport_id, 'icao' => $flight->dpt_airport_id,
]) }} ]) }}
<br />
<h5>{{$flight->arr_airport_id}} METAR</h5> <h5>{{$flight->arr_airport_id}} METAR</h5>
{{ Widget::Weather([ {{ Widget::Weather([
'icao' => $flight->arr_airport_id, 'icao' => $flight->arr_airport_id,

View File

@@ -12,21 +12,10 @@ https://api.checkwx.com/#metar-decoded
<td>Conditions</td> <td>Conditions</td>
<td> <td>
{{ $metar['category'] }} {{ $metar['category'] }}
&nbsp; {{ $metar['temperature'][$unit_temp] }}
@if($unit_temp === 'c')
{{$metar['temperature']}}
@else
{{$metar['temperature_f']}}
@endif
°{{strtoupper($unit_temp)}} °{{strtoupper($unit_temp)}}
@if($metar['visibility']) @if($metar['visibility'])
,&nbsp; , visibility {{ $metar['visibility'][$unit_dist] }}
visibility
@if($unit_dist === 'km')
{{$metar['visibility'] / 1000}}
@else
{{$metar['visibility_nm']}}
@endif
@endif @endif
{{$unit_dist}} {{$unit_dist}}
@@ -34,6 +23,12 @@ https://api.checkwx.com/#metar-decoded
,&nbsp; ,&nbsp;
{{ $metar['humidity'] }}% humidity {{ $metar['humidity'] }}% humidity
@endif @endif
@if($metar['dew_point'])
,&nbsp;dew point
{{ $metar['dew_point'][$unit_temp] }}
°{{strtoupper($unit_temp)}}
@endif
</td> </td>
</tr> </tr>
<tr> <tr>

View File

@@ -47,22 +47,21 @@ class MetarTest extends TestCase
$this->assertEquals(280, $parsed['wind_direction']); $this->assertEquals(280, $parsed['wind_direction']);
$this->assertEquals('W', $parsed['wind_direction_label']); $this->assertEquals('W', $parsed['wind_direction_label']);
$this->assertEquals(false, $parsed['wind_direction_varies']); $this->assertEquals(false, $parsed['wind_direction_varies']);
$this->assertEquals(16093, $parsed['visibility']); $this->assertEquals(16093.44, $parsed['visibility']['m']);
$this->assertEquals('16093 meters', $parsed['visibility_report']);
$this->assertEquals('Dry', $parsed['present_weather_report']); $this->assertEquals('Dry', $parsed['present_weather_report']);
$this->assertCount(4, $parsed['clouds']); $this->assertCount(4, $parsed['clouds']);
$this->assertEquals( $this->assertEquals(
'A few at 1676 meters; scattered at 2896 meters; broken sky at 3353 meters; broken sky at 7010 meters', 'A few at 1676 meters; scattered at 2896 meters; broken sky at 3353 meters; broken sky at 7010 meters',
$parsed['clouds_report']); $parsed['clouds_report']);
$this->assertEquals(1676, $parsed['cloud_height']); $this->assertEquals(1676.4, $parsed['cloud_height']['m']);
$this->assertEquals(false, $parsed['cavok']); $this->assertEquals(false, $parsed['cavok']);
$this->assertEquals(12, $parsed['temperature']); $this->assertEquals(12, $parsed['temperature']['c']);
$this->assertEquals(54, $parsed['temperature_f']); $this->assertEquals(53.6, $parsed['temperature']['f']);
$this->assertEquals(-4, $parsed['dew_point']); $this->assertEquals(-4, $parsed['dew_point']['c']);
$this->assertEquals(25, $parsed['dew_point_f']); $this->assertEquals(24.8, $parsed['dew_point']['f']);
$this->assertEquals(33, $parsed['humidity']); $this->assertEquals(33, $parsed['humidity']);
$this->assertEquals(29.58, $parsed['barometer']); $this->assertEquals(29.58, $parsed['barometer']);

View File

@@ -132,15 +132,15 @@ class PIREPTest extends TestCase
// Check that it has the fuel units // Check that it has the fuel units
$this->assertHasKeys($body['fuel_used'], ['lbs', 'kg']); $this->assertHasKeys($body['fuel_used'], ['lbs', 'kg']);
$this->assertEquals($pirep->fuel_used->toNumber(), $body['fuel_used']['lbs']); $this->assertEquals($pirep->fuel_used['lbs'], $body['fuel_used']['lbs']);
// Check that it has the distance units // Check that it has the distance units
$this->assertHasKeys($body['distance'], ['km', 'nmi', 'mi']); $this->assertHasKeys($body['distance'], ['km', 'nmi', 'mi']);
$this->assertEquals($pirep->distance->toNumber(), $body['distance']['nmi']); $this->assertEquals($pirep->distance['nmi'], $body['distance']['nmi']);
// Check the planned_distance field // Check the planned_distance field
$this->assertHasKeys($body['planned_distance'], ['km', 'nmi', 'mi']); $this->assertHasKeys($body['planned_distance'], ['km', 'nmi', 'mi']);
$this->assertEquals($pirep->planned_distance->toNumber(), $body['planned_distance']['nmi']); $this->assertEquals($pirep->planned_distance['nmi'], $body['planned_distance']['nmi']);
} }
/** /**

View File

@@ -110,6 +110,23 @@ class TestCase extends Illuminate\Foundation\Testing\TestCase
return $method->invokeArgs($object, $parameters); return $method->invokeArgs($object, $parameters);
} }
/**
* Transform any data that's passed in. E.g, make sure that any mutator
* classes (e.g, units) are not passed in as the mutator class
* @param array $data
* @return array
*/
protected function transformData(array $data): array
{
foreach($data as $key => $value) {
if (is_subclass_of($value, App\Interfaces\Unit::class)) {
$data[$key] = $value->__toString();
}
}
return $data;
}
/** /**
* Override the GET call to inject the user API key * Override the GET call to inject the user API key
* @param string $uri * @param string $uri
@@ -137,6 +154,7 @@ class TestCase extends Illuminate\Foundation\Testing\TestCase
*/ */
public function post($uri, array $data = [], array $headers = [], $user=null) public function post($uri, array $data = [], array $headers = [], $user=null)
{ {
$data = $this->transformData($data);
$req = parent::post($uri, $data, $this->headers($user, $headers)); $req = parent::post($uri, $data, $this->headers($user, $headers));
if ($req->isClientError() || $req->isServerError()) { if ($req->isClientError() || $req->isServerError()) {
Log::error('POST Error: ' . $uri, $req->json()); Log::error('POST Error: ' . $uri, $req->json());
@@ -155,7 +173,7 @@ class TestCase extends Illuminate\Foundation\Testing\TestCase
*/ */
public function put($uri, array $data = [], array $headers = [], $user = null) public function put($uri, array $data = [], array $headers = [], $user = null)
{ {
$req = parent::put($uri, $data, $this->headers($user, $headers)); $req = parent::put($uri, $this->transformData($data), $this->headers($user, $headers));
if ($req->isClientError() || $req->isServerError()) { if ($req->isClientError() || $req->isServerError()) {
Log::error('PUT Error: ' . $uri, $req->json()); Log::error('PUT Error: ' . $uri, $req->json());
} }
@@ -173,7 +191,7 @@ class TestCase extends Illuminate\Foundation\Testing\TestCase
*/ */
public function delete($uri, array $data = [], array $headers = [], $user=null) public function delete($uri, array $data = [], array $headers = [], $user=null)
{ {
$req = parent::delete($uri, $data, $this->headers($user, $headers)); $req = parent::delete($uri, $this->transformData($data), $this->headers($user, $headers));
if ($req->isClientError() || $req->isServerError()) { if ($req->isClientError() || $req->isServerError()) {
Log::error('DELETE Error: ' . $uri, $req->json()); Log::error('DELETE Error: ' . $uri, $req->json());
} }

View File

@@ -21,9 +21,11 @@ trait TestData
]); ]);
// Return a Pirep model // Return a Pirep model
return factory(\App\Models\Pirep::class)->make([ $pirep = factory(\App\Models\Pirep::class)->make([
'aircraft_id' => $subfleet['aircraft']->random()->id 'aircraft_id' => $subfleet['aircraft']->random()->id
]); ]);
return $pirep;
} }
/** /**