diff --git a/src/UnitConverter/Registry/UnitRegistry.php b/src/UnitConverter/Registry/UnitRegistry.php new file mode 100644 index 00000000..43bcc82d --- /dev/null +++ b/src/UnitConverter/Registry/UnitRegistry.php @@ -0,0 +1,165 @@ + + * @license MIT + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types = 1); + +namespace UnitConverter\Registry; + +use UnitConverter\Measure; +use UnitConverter\Unit\UnitInterface; + +/** + * The unit converter registry object. This object is used + * to store and retrieve instances of the UnitInterface. + * + * @version 1.0.0 + * @since 1.0.0 + * @author Jordan Brauer + */ +class UnitRegistry implements UnitRegistryInterface +{ + /** + * @var array $store A two-dimensional array containing available types of measuerment that each contain their available units of measure. + */ + protected $store = array(); + + /** + * Public constructor function for the unit registry. + * + * @param UnitInterface[] A one-dimensional array of UnitInterface objects to be registered upon construction. + * @return self + */ + public function __construct (array $units = array()) + { + $this->store = array( + Measure::LENGTH => array(), + Measure::AREA => array(), + Measure::VOLUME => array(), + Measure::WEIGHT => array(), + Measure::SPEED => array(), + Measure::ROTATION => array(), + Measure::TEMPERATURE => array(), + Measure::PRESSURE => array(), + Measure::TIME => array(), + Measure::ENERGY => array(), + ); + + if (count($units) > 0) + $this->registerUnits($units); + } + + public function isMeasurementRegistered (string $measurement) : bool + { + return array_key_exists($measurement, $this->store); + } + + public function isUnitRegistered (string $symbol) : bool + { + foreach ($this->store as $measurement => $units) { + if (array_key_exists($symbol, $units)) + return true; + } + + return false; + } + + public function loadUnit (string $symbol) : ?UnitInterface + { + foreach ($this->store as $measurement => $units) { + if (array_key_exists($symbol, $units)) + return $this->store[$measurement][$symbol]; + } + + return null; + } + + public function listMeasurements () : array + { + return array_keys($this->store); + } + + public function listUnits (string $measurement = null) : array + { + if (!$measurement) { + $registeredUnits = array(); + + foreach ($this->store as $measurements) { + foreach ($measurements as $unit) { + array_push($registeredUnits, $unit->getSymbol()); + } + } + + return $registeredUnits; + } + + return array_keys($this->store[$measurement]); + } + + public function registerMeasurement (string $measurement) : void + { + if (!$this->isMeasurementRegistered($measurement)) + $this->store[$measurement] = $measurement; + } + + public function registerMeasurements (array $measurements) : void + { + foreach ($measurements as $measurement) { + $this->registerMeasurement($measurement); + } + } + + public function registerUnit (UnitInterface $unit) : void + { + if (!$this->isMeasurementRegistered($unit->getUnitOf())) + throw new \ErrorException("Trying to register unit {$unit->getName()} to an unregisted measurement of {$unit->getUnitOf()}"); + + $this->store[$unit->getUnitOf()][$unit->getSymbol()] = $unit; + } + + public function registerUnits (array $units) : void + { + foreach ($units as $unit) { + $this->registerUnit($unit); + } + } + + public function unregisterMeasurement (string $measurement) : void + { + if (!$this->isMeasurementRegistered($measurement)) + throw new \ErrorException("Trying to unregister a nonexistent measurement type {$measurement}"); + + unset($this->store[$measurement]); + } + + public function unregisterMeasurements(array $measurements) : void + { + foreach ($measurements as $measurement) { + $this->unregisterMeasurement($measurement); + } + } + + public function unregisterUnit (string $symbol) : void + { + if ($this->isUnitRegistered($symbol) === false) + throw new \ErrorException("Trying to unregister a nonexistent unit {$symbol}"); + + $unit = $this->loadUnit($symbol); + unset($this->store[$unit->getUnitOf()][$symbol]); + } + + public function unregisterUnits (array $symbols) : void + { + foreach ($symbols as $unit) { + $this->unregisterUnit($unit); + } + } +} diff --git a/src/UnitConverter/Registry/UnitRegistryInterface.php b/src/UnitConverter/Registry/UnitRegistryInterface.php new file mode 100644 index 00000000..f9ff8fb2 --- /dev/null +++ b/src/UnitConverter/Registry/UnitRegistryInterface.php @@ -0,0 +1,140 @@ + + * @license MIT + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types = 1); + +namespace UnitConverter\Registry; + +use UnitConverter\Unit\UnitInterface; + +/** + * The interface for the unit converter registry that stores units + * and types of measurement. + * + * @version 1.0.0 + * @since 1.0.0 + * @author Jordan Brauer + */ +interface UnitRegistryInterface +{ + /** + * Determine if a measurement type is registered to the unit registry or not. + * + * @param string $measurement The name of the measurment being checked, e.g. "length". + */ + public function isMeasurementRegistered (string $measurement) : bool; + + /** + * Determine if a specific unit of measure is registered to the unit registry or not. + * + * @param string $symbol The symbol notation of the unit being checked, e.g., "cm". + */ + public function isUnitRegistered (string $symbol) : bool; + + /** + * Fetch a unit from the unit registry for use elsewhere. + * + * @param string $symbol The symbol notation of the unit being loaded. + * @return null|UnitInterface + */ + public function loadUnit (string $symbol) : ?UnitInterface; + + /** + * Return a one-dimensional array of currently supported measurement types. + * + * @return array + */ + public function listMeasurements () : array; + + /** + * Return a one-dimensional array of currently supported units. Optionally + * pass a string equal to a type of measurement (e.g. "length") to return + * only units of the specifed type. + * + * @param string $measurement + */ + public function listUnits (string $measurement = null) : array; + + /** + * Register a single measurement to the unit registry by passing a + * string as the argument + * + * @param string $measurement + * @return void + */ + public function registerMeasurement (string $measurement) : void; + + /** + * Register many measurements to the unit registry by passing an + * array of measurement strings as the argument + * + * @param array $measurements + * @return void + */ + public function registerMeasurements (array $measurements) : void; + + /** + * Register a single unit to the unit registry by passing an + * instance of a UnitInterface as it's argument + * + * @param UnitInterface $unit + * @throws ErrorException This will be thrown when an attempted unit registration is made on an unexisting measurement. + * @return void + */ + public function registerUnit (UnitInterface $unit) : void; + + /** + * Register many units to the unit registry by passing an array of unit + * classes as it's argument. + * + * @param UnitInterface[] $units + * @return void + */ + public function registerUnits (array $units) : void; + + /** + * Unegister a single measurement from the unit registry. + * + * @NOTE: Invoking this method will also unregister all + * units belonging to the measurement that is being unregistered. + * + * @param string $symbol + * @throws ErrorException An error exception will be thrown if you attempt to unregister a non-existing measurement type. + * @return void + */ + public function unregisterMeasurement (string $symbol) : void; + + /** + * Unegister many units from the unit registry + * + * @param string[] $symbols + * @return void + */ + public function unregisterMeasurements (array $symbols) : void; + + /** + * Unegister a single unit from the unit registry + * + * @param string $symbol + * @throws ErrorException An error exception will be thrown if you attempt to unregister a non-existing unit of measure. + * @return void + */ + public function unregisterUnit (string $symbol) : void; + + /** + * Unegister many units from the unit registry + * + * @param string[] $symbols + * @return void + */ + public function unregisterUnits (array $symbols) : void; +} diff --git a/tests/unit/UnitConverter/Registry/UnitRegistry.spec.php b/tests/unit/UnitConverter/Registry/UnitRegistry.spec.php new file mode 100644 index 00000000..6f62746b --- /dev/null +++ b/tests/unit/UnitConverter/Registry/UnitRegistry.spec.php @@ -0,0 +1,204 @@ + + * @license MIT + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types = 1); + +namespace UnitConverter\Tests\Unit\Registry; + +use PHPUnit\Framework\TestCase; +use UnitConverter\Registry\UnitRegistry; +use UnitConverter\Unit\UnitInterface; +use UnitConverter\Unit\AbstractUnit; +use UnitConverter\Unit\Length\{ + Centimeter, + Inch, + Meter, + Milimeter +}; + +/** + * @coversDefaultClass UnitConverter\UnitRegistry + * @author Jordan Brauer + */ +class UnitRegistrySpec extends TestCase +{ + protected function setUp () + { + $this->registry = new UnitRegistry(array( + new Centimeter, + new Inch, + )); + } + + protected function tearDown () + { + unset($this->registry); + } + + /** + * @test + * @covers ::isMeasurementRegistered + */ + public function assertMeasurementIsRegistered () + { + $this->assertTrue($this->registry->isMeasurementRegistered("length")); + $this->assertFalse($this->registry->isMeasurementRegistered("saiyanPower")); + } + + /** + * @test + * @covers ::isUnitRegistered + */ + public function assertUnitIsRegistered () + { + $this->assertTrue($this->registry->isUnitRegistered("cm")); + $this->assertFalse($this->registry->isUnitRegistered("yd")); + } + + /** + * @test + * @covers ::loadUnit + */ + public function assertUnitObjectIsLoaded () + { + $actual = $this->registry->loadUnit("cm"); + $expected = UnitInterface::class; + + $this->assertInstanceOf($expected, $actual); + } + + /** + * @test + * @covers ::listMeasurements + */ + public function assertListMeasurementsMethodReturnsArray () + { + $actual = $this->registry->listMeasurements(); + $expected = array( + "length", + "area", + "volume", + "weight", + "speed", + "rotation", + "temperature", + "pressure", + "time", + "energy", + ); + + $this->assertEquals($expected, $actual); + $this->assertInternalType("array", $actual); + $this->assertTrue((count($actual) > 0)); + } + + /** + * @test + * @covers ::listUnits + */ + public function assertListUnitsMethodReturnsArray () + { + $actual = $this->registry->listUnits(); + $expected = array( + "cm", + "in", + ); + + $this->assertEquals($expected, $actual); + $this->assertInternalType("array", $actual); + $this->assertTrue((count($actual) > 0)); + } + + /** + * @test + * @covers ::registerMeasurement + * @covers ::registerMeasurements + * @uses ::isMeasurementRegistered + */ + public function assertRegisterMeasurementMethodsAddItemsToUnitRegistry () + { + $this->assertFalse($this->registry->isMeasurementRegistered("data")); + $this->assertFalse($this->registry->isMeasurementRegistered("saiyanPower")); + $this->assertFalse($this->registry->isMeasurementRegistered("funniness")); + + $this->registry->registerMeasurement("data"); + $this->registry->registerMeasurements(["saiyanPower", "funniness"]); + + $this->assertTrue($this->registry->isMeasurementRegistered("data")); + $this->assertTrue($this->registry->isMeasurementRegistered("saiyanPower")); + $this->assertTrue($this->registry->isMeasurementRegistered("funniness")); + } + + /** + * @test + * @covers ::registerUnit + * @covers ::registerUnits + * @uses ::isUnitRegistered + */ + public function assertRegisterUnitMethodsAddItemsToUnitRegistry () + { + $this->assertFalse($this->registry->isUnitRegistered("sP")); + $this->assertFalse($this->registry->isUnitRegistered("m")); + $this->assertFalse($this->registry->isUnitRegistered("mm")); + + $this->registry->registerUnit(new class extends AbstractUnit { + protected $name = "saiyanPower"; + protected $symbol = "sP"; + protected $unitOf = "energy"; + protected $base = self::class; + protected $units = 9001; + }); + $this->registry->registerUnits([new Meter, new Milimeter]); + + $this->assertTrue($this->registry->isUnitRegistered("sP")); + $this->assertTrue($this->registry->isUnitRegistered("m")); + $this->assertTrue($this->registry->isUnitRegistered("mm")); + } + + /** + * @test + * @covers ::unregisterMeasurement + * @covers ::unregisterMeasurements + * @uses ::isMeasurementRegistered + */ + public function assertUnregisterMeasurementMethodsRemoveItemsFromUnitRegistry () + { + $this->assertTrue($this->registry->isMeasurementRegistered("length")); + $this->assertTrue($this->registry->isMeasurementRegistered("weight")); + $this->assertTrue($this->registry->isMeasurementRegistered("volume")); + + $this->registry->unregisterMeasurement("length"); + $this->registry->unregisterMeasurements(array("weight", "volume")); + + $this->assertFalse($this->registry->isMeasurementRegistered("length")); + $this->assertFalse($this->registry->isMeasurementRegistered("weight")); + $this->assertFalse($this->registry->isMeasurementRegistered("volume")); + } + + /** + * @test + * @covers ::unregisterUnit + * @covers ::unregisterUnits + * @uses ::isUnitRegistered + */ + public function assertUnregisterUnitMethodsRemoveItemsFromUnitRegistry () + { + $this->assertTrue($this->registry->isUnitRegistered("cm")); + $this->assertTrue($this->registry->isUnitRegistered("in")); + + $this->registry->unregisterUnit("cm"); + $this->registry->unregisterUnits(array("in")); + + $this->assertFalse($this->registry->isUnitRegistered("cm")); + $this->assertFalse($this->registry->isUnitRegistered("in")); + } +}