Skip to content

Commit 093426b

Browse files
committed
feat: add support for custom units
1 parent 7a54ff5 commit 093426b

29 files changed

+536
-376
lines changed

.editorconfig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
root = true
2+
3+
[*]
4+
indent_style = space
5+
indent_size = 4
6+
end_of_line = lf
7+
charset = utf-8
8+
trim_trailing_whitespace = true
9+
insert_final_newline = true
10+
11+
[*.md]
12+
trim_trailing_whitespace = false

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,23 @@ $addGrams = $massUnit->add(new Time\Second(60) );
175175
// throws a PhpUnitConversion\Exception\UnsupportedUnitException
176176
```
177177

178+
## Adding custom units
179+
```
180+
use PhpUnitConversion\Map as UnitMap;
181+
182+
/* You can add custom units by calling the add method on UnitMap.
183+
* The first argument should be the path to a directory containing UnitTypes files with
184+
* the corresponding Unit files in a subfolder.
185+
* The second argument is the namespace that you use in your files
186+
*/
187+
UnitMap::add('YOUR_UNITS_DIR_OR_FILE', 'YOUR_UNITS_NAMESPACE');
188+
189+
/* If you only want add one unit to an existing unit type, add a third argument with the class name
190+
* of the unit type you want your unit to add to
191+
*/
192+
UnitMap::add('/path/to/TwoTableSpoons.php', '\\MyUnits', PhpUnitConversion\Unit\Volume::class);
193+
```
194+
178195
## Contributing
179196

180197
Please check [Contributing](CONTRIBUTING.md) for details.

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
}
4444
},
4545
"scripts": {
46-
"cs": "vendor/bin/phpcs src/*",
46+
"cs": "vendor/bin/phpcs src/* tests/*",
4747
"test:standard": "vendor/bin/phpunit --testsuite Standard_Tests",
4848
"test:all": "vendor/bin/phpunit"
4949
}

src/Map.php

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
<?php
2+
namespace PhpUnitConversion;
3+
4+
use PhpUnitConversion\Unit;
5+
6+
abstract class Map
7+
{
8+
const PHP_EXTENSION = '.php';
9+
10+
/** @var array */
11+
protected static $paths = [[__DIR__ . '/Unit/', __NAMESPACE__ . '\\Unit', false, null]];
12+
13+
/** @var array */
14+
public static $map = [];
15+
16+
/** @var array */
17+
public static $values = [];
18+
19+
public static function &value($mapType)
20+
{
21+
return static::$values[$mapType];
22+
}
23+
24+
/**
25+
* @param string $path
26+
* @param string $namespace
27+
* @param string $unitType
28+
* @return void
29+
*/
30+
public static function add($path, $namespace = '', $unitType = '')
31+
{
32+
self::$paths[] = [$path, $namespace, false, $unitType];
33+
}
34+
35+
/**
36+
* @return void
37+
*/
38+
public static function reset()
39+
{
40+
self::$map = [];
41+
self::$values = [];
42+
}
43+
44+
/**
45+
* @return void
46+
*/
47+
public static function clear()
48+
{
49+
self::reset();
50+
self::$paths = [];
51+
}
52+
53+
/**
54+
* @return boolean
55+
*/
56+
public static function load()
57+
{
58+
$newlyLoaded = false;
59+
foreach (self::$paths as $k => list($path, $namespace, $loaded, $unitType)) {
60+
if (!$loaded) {
61+
if (self::loadPath($path, $namespace, $unitType)) {
62+
self::$paths[$k][2] = true;
63+
$newlyLoaded = true;
64+
}
65+
}
66+
}
67+
return $newlyLoaded;
68+
}
69+
70+
/**
71+
* @param string $path
72+
* @param string $namespace
73+
* @return string
74+
*/
75+
public static function loadPath($path, $namespace = '', $unitType = '')
76+
{
77+
if (is_file($path)) {
78+
$classes = self::loadFile($path, $namespace);
79+
80+
if (!is_array($classes)) {
81+
$classes = [$unitType => [$classes]];
82+
}
83+
} elseif (is_dir($path)) {
84+
$classes = self::loadDirectory($path, $namespace);
85+
}
86+
87+
self::$map = self::$map + $classes;
88+
89+
return count($classes) > 0;
90+
}
91+
92+
/**
93+
* @param string $directory
94+
* @param string $namespace
95+
* @return array
96+
*/
97+
public static function loadDirectory($directory, $namespace = '')
98+
{
99+
$classes = [];
100+
foreach (glob($directory . '/*' . self::PHP_EXTENSION) as $file) {
101+
$className = self::loadFile($file, $namespace, $directory);
102+
103+
if (is_array($className)) {
104+
$classes = $classes + $className;
105+
} elseif (is_string($className)) {
106+
$classes[] = $className;
107+
}
108+
}
109+
return $classes;
110+
}
111+
112+
/**
113+
* @param string $file
114+
* @param string $namespace
115+
* @return string|array
116+
*/
117+
public static function loadFile($file, $namespace = '')
118+
{
119+
if (file_exists($file)) {
120+
$fileName = basename($file, self::PHP_EXTENSION);
121+
$className = rtrim($namespace, '\\') . '\\' . $fileName;
122+
123+
if (class_exists($className) && is_a($className, Unit::class, true)) {
124+
$directory = substr($file, 0, -1 * strlen(self::PHP_EXTENSION));
125+
if (file_exists($directory) && is_dir($directory)) {
126+
return [$className => self::loadDirectory($directory, $className)];
127+
} else {
128+
return $className;
129+
}
130+
}
131+
}
132+
133+
return false;
134+
}
135+
}

src/Map/Factor.php

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
namespace PhpUnitConversion\Map;
3+
4+
use PhpUnitConversion\Map;
5+
6+
abstract class Factor extends Map
7+
{
8+
/**
9+
* @return array
10+
*/
11+
public static function get()
12+
{
13+
$factors = &static::value('factor');
14+
15+
if (static::load() || empty($factors)) {
16+
$factors = [];
17+
18+
foreach (static::$map as $unitType => $units) {
19+
foreach ($units as $unitClass) {
20+
if (class_exists($unitClass)) {
21+
if (!array_key_exists($unitClass::TYPE, $factors)) {
22+
$factors[$unitClass::TYPE] = [];
23+
}
24+
25+
/** @var Unit $unitObject */
26+
$unitObject = new $unitClass(1);
27+
$factors[$unitClass::TYPE][$unitClass] = $unitObject->to($unitClass::BASE_UNIT)->getValue();
28+
}
29+
}
30+
}
31+
32+
foreach ($factors as &$unitFactors) {
33+
asort($unitFactors);
34+
}
35+
}
36+
37+
return $factors;
38+
}
39+
40+
/**
41+
* @return array
42+
*/
43+
public static function byType($type)
44+
{
45+
$factors = static::get();
46+
return $factors[$type];
47+
}
48+
}

src/Map/Label.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
namespace PhpUnitConversion\Map;
3+
4+
use PhpUnitConversion\Map;
5+
6+
abstract class Label extends Map
7+
{
8+
/**
9+
* @return array
10+
*/
11+
public static function get()
12+
{
13+
$labels = &static::value('label');
14+
15+
if (static::load() || empty($labels)) {
16+
$labels = [];
17+
18+
foreach (static::$map as $unitType => $units) {
19+
foreach ($units as $unitClass) {
20+
if (!array_key_exists($unitClass::TYPE, $labels)) {
21+
$labels[$unitClass::TYPE] = [];
22+
}
23+
24+
if (!empty($unitClass::LABEL)) {
25+
$labels[$unitClass::TYPE][$unitClass::LABEL] = $unitClass;
26+
}
27+
}
28+
}
29+
}
30+
31+
return $labels;
32+
}
33+
}

src/Map/Symbol.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
namespace PhpUnitConversion\Map;
3+
4+
use PhpUnitConversion\Map;
5+
6+
abstract class Symbol extends Map
7+
{
8+
/**
9+
* @return array
10+
*/
11+
public static function get()
12+
{
13+
$symbols = &static::value('symbol');
14+
15+
if (static::load() || empty($symbols)) {
16+
$symbols = [];
17+
18+
foreach (static::$map as $unitType => $units) {
19+
foreach ($units as $unitClass) {
20+
if (!array_key_exists($unitClass::TYPE, $symbols)) {
21+
$symbols[$unitClass::TYPE] = [];
22+
}
23+
24+
if (!empty($unitClass::SYMBOL)) {
25+
$symbols[$unitClass::TYPE][$unitClass::SYMBOL] = $unitClass;
26+
}
27+
}
28+
}
29+
}
30+
31+
return $symbols;
32+
}
33+
}

src/Map/Type.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
namespace PhpUnitConversion\Map;
3+
4+
use PhpUnitConversion\Map;
5+
6+
abstract class Type extends Map
7+
{
8+
/**
9+
* @return array
10+
*/
11+
public static function get()
12+
{
13+
$types = &static::value('type');
14+
15+
if (static::load() || empty($types)) {
16+
$types = [];
17+
18+
foreach (array_keys(static::$map) as $unitTypeClass) {
19+
if (class_exists($unitTypeClass)) {
20+
$types[$unitTypeClass::TYPE] = $unitTypeClass;
21+
}
22+
}
23+
}
24+
25+
return $types;
26+
}
27+
28+
/**
29+
* @return string
30+
*/
31+
public static function byType($type)
32+
{
33+
$types = static::get();
34+
return $types[$type];
35+
}
36+
}

src/Map/Unit.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
namespace PhpUnitConversion\Map;
3+
4+
use PhpUnitConversion\Map;
5+
6+
abstract class Unit extends Map
7+
{
8+
/**
9+
* @return array
10+
*/
11+
public static function get($type = null)
12+
{
13+
static $all = [];
14+
15+
if (static::load() || empty($all)) {
16+
foreach (static::$map as $units) {
17+
$all = array_merge($all, $units);
18+
}
19+
}
20+
21+
return $all;
22+
}
23+
24+
/**
25+
* @return array
26+
*/
27+
public static function byType($type)
28+
{
29+
static::load();
30+
31+
foreach (static::$map as $unitTypeClass => $units) {
32+
if ($unitTypeClass::TYPE === $type) {
33+
return $units;
34+
}
35+
}
36+
37+
return false;
38+
}
39+
}

0 commit comments

Comments
 (0)