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
![]() |
|||
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]>"
![]() |
|||
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 |