nystudio107 /
craft-units
| 1 | <?php |
||
| 2 | /** |
||
| 3 | * Units plugin for Craft CMS |
||
| 4 | * |
||
| 5 | * A plugin for handling physical quantities and the units of measure in which they're represented. |
||
| 6 | * |
||
| 7 | * @link https://nystudio107.com/ |
||
|
0 ignored issues
–
show
Coding Style
introduced
by
Loading history...
|
|||
| 8 | * @copyright Copyright (c) nystudio107 |
||
|
0 ignored issues
–
show
|
|||
| 9 | */ |
||
|
0 ignored issues
–
show
|
|||
| 10 | |||
| 11 | namespace nystudio107\units\variables; |
||
| 12 | |||
| 13 | use nystudio107\units\helpers\ClassHelper; |
||
| 14 | use nystudio107\units\models\UnitsData; |
||
| 15 | use PhpUnitsOfMeasure\AbstractPhysicalQuantity; |
||
| 16 | use PhpUnitsOfMeasure\PhysicalQuantity\Acceleration; |
||
| 17 | use PhpUnitsOfMeasure\PhysicalQuantity\Angle; |
||
| 18 | use PhpUnitsOfMeasure\PhysicalQuantity\Area; |
||
| 19 | use PhpUnitsOfMeasure\PhysicalQuantity\ElectricCurrent; |
||
| 20 | use PhpUnitsOfMeasure\PhysicalQuantity\Energy; |
||
| 21 | use PhpUnitsOfMeasure\PhysicalQuantity\Length; |
||
| 22 | use PhpUnitsOfMeasure\PhysicalQuantity\LuminousIntensity; |
||
| 23 | use PhpUnitsOfMeasure\PhysicalQuantity\Mass; |
||
| 24 | use PhpUnitsOfMeasure\PhysicalQuantity\Pressure; |
||
| 25 | use PhpUnitsOfMeasure\PhysicalQuantity\Quantity; |
||
| 26 | use PhpUnitsOfMeasure\PhysicalQuantity\SolidAngle; |
||
| 27 | use PhpUnitsOfMeasure\PhysicalQuantity\Temperature; |
||
| 28 | use PhpUnitsOfMeasure\PhysicalQuantity\Time; |
||
| 29 | use PhpUnitsOfMeasure\PhysicalQuantity\Velocity; |
||
| 30 | use PhpUnitsOfMeasure\PhysicalQuantity\Volume; |
||
| 31 | use PhpUnitsOfMeasure\UnitOfMeasure; |
||
| 32 | use yii\base\InvalidArgumentException; |
||
| 33 | |||
| 34 | /** |
||
|
0 ignored issues
–
show
|
|||
| 35 | * @author nystudio107 |
||
|
0 ignored issues
–
show
Content of the @author tag must be in the form "Display Name <[email protected]>"
Loading history...
|
|||
| 36 | * @package Units |
||
|
0 ignored issues
–
show
|
|||
| 37 | * @since 1.0.0 |
||
|
0 ignored issues
–
show
|
|||
| 38 | * |
||
| 39 | * @method Acceleration acceleration($value, string $units) |
||
| 40 | * @method Angle angle($value, string $units) |
||
| 41 | * @method Area area($value, string $units) |
||
| 42 | * @method ElectricCurrent electricCurrent($value, string $units) |
||
| 43 | * @method Energy energy($value, string $units) |
||
| 44 | * @method Length length($value, string $units) |
||
| 45 | * @method LuminousIntensity luminousIntensity($value, string $units) |
||
| 46 | * @method Mass mass($value, string $units) |
||
| 47 | * @method Pressure pressure($value, string $units) |
||
| 48 | * @method Quantity quantity($value, string $units) |
||
| 49 | * @method SolidAngle solidAngle($value, string $units) |
||
| 50 | * @method Temperature temperature($value, string $units) |
||
| 51 | * @method Time time($value, string $units) |
||
| 52 | * @method Velocity velocity($value, string $units) |
||
| 53 | * @method Volume volume($value, string $units) |
||
| 54 | */ |
||
|
0 ignored issues
–
show
|
|||
| 55 | class UnitsVariable |
||
| 56 | { |
||
| 57 | // Public Properties |
||
| 58 | // ========================================================================= |
||
| 59 | |||
| 60 | /** |
||
|
0 ignored issues
–
show
|
|||
| 61 | * @var array |
||
| 62 | */ |
||
| 63 | public array $unitsClassMap = []; |
||
| 64 | |||
| 65 | // Public Methods |
||
| 66 | // ========================================================================= |
||
| 67 | |||
| 68 | /** |
||
| 69 | * If the passed in class exists in PhpUnitsOfMeasure\PhysicalQuantity |
||
| 70 | * return a new instance of the unit of measure |
||
| 71 | * |
||
| 72 | * @param $method |
||
|
0 ignored issues
–
show
|
|||
| 73 | * @param $args |
||
|
0 ignored issues
–
show
|
|||
| 74 | * |
||
| 75 | * @return UnitsData |
||
| 76 | * @throws InvalidArgumentException |
||
| 77 | */ |
||
| 78 | public function __call($method, $args): UnitsData |
||
| 79 | { |
||
| 80 | if (empty($this->unitsClassMap)) { |
||
| 81 | $this->unitsClassMap = ClassHelper::getClassesInNamespace(Length::class); |
||
| 82 | } |
||
| 83 | $unitsClassKey = ucfirst($method); |
||
| 84 | if (isset($this->unitsClassMap[$unitsClassKey])) { |
||
| 85 | [$value, $units] = $args; |
||
| 86 | $config = [ |
||
| 87 | 'unitsClass' => $this->unitsClassMap[$unitsClassKey], |
||
| 88 | 'value' => $value, |
||
| 89 | 'units' => $units, |
||
| 90 | ]; |
||
| 91 | |||
| 92 | return new UnitsData($config); |
||
| 93 | } |
||
| 94 | |||
| 95 | throw new InvalidArgumentException("Method {$method} doesn't exist"); |
||
| 96 | } |
||
| 97 | |||
| 98 | /** |
||
| 99 | * Outputs a floating point number as a fraction |
||
| 100 | * |
||
| 101 | * @param float $value |
||
|
0 ignored issues
–
show
|
|||
| 102 | * |
||
| 103 | * @return string |
||
| 104 | */ |
||
| 105 | public function fraction(float $value): string |
||
| 106 | { |
||
| 107 | [$whole, $decimal] = $this->float2parts($value); |
||
| 108 | |||
| 109 | return $whole . ' ' . $this->float2ratio($decimal); |
||
| 110 | } |
||
| 111 | |||
| 112 | /** |
||
| 113 | * Convert a floating point number to the whole and the decimal |
||
| 114 | * |
||
| 115 | * @param float $number |
||
|
0 ignored issues
–
show
|
|||
| 116 | * @param bool $returnUnsigned |
||
|
0 ignored issues
–
show
|
|||
| 117 | * |
||
| 118 | * @return array |
||
| 119 | */ |
||
| 120 | public function float2parts(float $number, bool $returnUnsigned = false): array |
||
| 121 | { |
||
| 122 | $negative = 1; |
||
| 123 | if ($number < 0) { |
||
| 124 | $negative = -1; |
||
| 125 | $number *= -1; |
||
| 126 | } |
||
| 127 | |||
| 128 | if ($returnUnsigned) { |
||
| 129 | return [ |
||
| 130 | floor($number), |
||
| 131 | $number - floor($number), |
||
| 132 | ]; |
||
| 133 | } |
||
| 134 | |||
| 135 | return [ |
||
| 136 | floor($number) * $negative, |
||
| 137 | ($number - floor($number)) * $negative, |
||
| 138 | ]; |
||
| 139 | } |
||
| 140 | |||
| 141 | /** |
||
| 142 | * Convert a floating point number to a ratio |
||
| 143 | * |
||
| 144 | * @param float $n |
||
|
0 ignored issues
–
show
|
|||
| 145 | * @param float $tolerance |
||
|
0 ignored issues
–
show
|
|||
| 146 | * |
||
| 147 | * @return string |
||
| 148 | */ |
||
| 149 | public function float2ratio(float $n, float $tolerance = 1.e-6): string |
||
| 150 | { |
||
| 151 | if ($n === 0.0) { |
||
|
0 ignored issues
–
show
|
|||
| 152 | return ''; |
||
| 153 | } |
||
| 154 | $h1 = 1; |
||
| 155 | $h2 = 0; |
||
| 156 | $k1 = 0; |
||
| 157 | $k2 = 1; |
||
| 158 | $b = 1 / $n; |
||
| 159 | do { |
||
| 160 | $b = 1 / $b; |
||
| 161 | $a = floor($b); |
||
| 162 | $aux = $h1; |
||
| 163 | $h1 = $a * $h1 + $h2; |
||
| 164 | $h2 = $aux; |
||
| 165 | $aux = $k1; |
||
| 166 | $k1 = $a * $k1 + $k2; |
||
| 167 | $k2 = $aux; |
||
| 168 | $b -= $a; |
||
| 169 | } while (abs($n - $h1 / $k1) > $n * $tolerance); |
||
| 170 | |||
| 171 | return "$h1/$k1"; |
||
| 172 | } |
||
| 173 | |||
| 174 | /** |
||
| 175 | * Return all of the available units |
||
| 176 | * |
||
| 177 | * @param bool $includeAliases whether to include aliases or not |
||
| 178 | * |
||
| 179 | * @return array |
||
| 180 | */ |
||
| 181 | public function allAvailableUnits(bool $includeAliases = false): array |
||
| 182 | { |
||
| 183 | $unitsList = []; |
||
| 184 | $units = ClassHelper::getClassesInNamespace(Length::class); |
||
| 185 | foreach ($units as $key => $value) { |
||
| 186 | /** @var AbstractPhysicalQuantity $value */ |
||
|
0 ignored issues
–
show
|
|||
| 187 | $unitsList[$key] = $this->availableUnits($value, $includeAliases); |
||
| 188 | } |
||
| 189 | ksort($unitsList); |
||
| 190 | |||
| 191 | return $unitsList; |
||
| 192 | } |
||
| 193 | |||
| 194 | /** |
||
| 195 | * Return the available units for a given AbstractPhysicalQuantity |
||
| 196 | * |
||
| 197 | * @param string $unitsClass |
||
|
0 ignored issues
–
show
|
|||
| 198 | * @param bool $includeAliases whether to include aliases or not |
||
|
0 ignored issues
–
show
|
|||
| 199 | * |
||
| 200 | * @return array |
||
| 201 | */ |
||
| 202 | public function availableUnits(string $unitsClass, bool $includeAliases = false): array |
||
| 203 | { |
||
| 204 | $availableUnits = []; |
||
| 205 | if (is_subclass_of($unitsClass, AbstractPhysicalQuantity::class)) { |
||
| 206 | /** @var array $units */ |
||
|
0 ignored issues
–
show
|
|||
| 207 | /** @var AbstractPhysicalQuantity $unitsClass */ |
||
|
0 ignored issues
–
show
|
|||
| 208 | $units = $unitsClass::getUnitDefinitions(); |
||
| 209 | /** @var UnitOfMeasure $unit */ |
||
|
0 ignored issues
–
show
|
|||
| 210 | foreach ($units as $unit) { |
||
| 211 | $name = $unit->getName(); |
||
| 212 | $aliases = $unit->getAliases(); |
||
| 213 | $availableUnits[$name] = $includeAliases ? $aliases : $aliases[0] ?? $name; |
||
| 214 | } |
||
| 215 | } |
||
| 216 | |||
| 217 | return $availableUnits; |
||
| 218 | } |
||
| 219 | } |
||
| 220 |