Created
November 21, 2016 23:58
-
-
Save Sibicle/8cea02cc937c2ab5d2720c067e0f6a82 to your computer and use it in GitHub Desktop.
Hazmat Classifier
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace SparkLib\HazmatClassifier; | |
use \Exception; | |
use \SparkLib\HazmatClassifier\LiIonBattery, | |
\SparkLib\HazmatClassifier\LiMetalBattery; | |
abstract class Battery { | |
// Battery chemistries | |
const LI_ION = 1; | |
const LI_METAL = 2; | |
// Battery packaging type | |
const BATTERY_ONLY = 1; | |
const PACKED_EQUIPMENT = 2; | |
const CONTAINED_EQUIPMENT = 3; | |
// Battery size | |
const SMALL = 1; | |
const MEDIUM = 2; | |
const LARGE = 3; | |
// | |
// Classification limits: | |
// More than 2.5 kilograms of small batteries per package | |
// | |
const Q_SM = 2.5; | |
// | |
// More than 2 medium batteries per package | |
// | |
const Q_CELL_MED = 8; | |
// | |
// More than 2 medium batteries per package | |
// | |
const Q_BATT_MED = 2; | |
protected $weight; | |
protected $voltage; | |
protected $charge; | |
protected $cells; | |
protected $packaging; | |
protected $exempt = false; | |
abstract protected function getLithiumContent(); | |
abstract protected function iataSize(); | |
abstract protected function iataClassification(); | |
abstract protected function dotClassification(); | |
abstract protected function getChemistry(); | |
public function __construct ($params = null) | |
{ | |
if ($params !== null) | |
{ | |
if (isset($params['weight'])) | |
$this->setWeight($params['weight']); | |
if (isset($params['voltage'])) | |
$this->setVoltage($params['voltage']); | |
if (isset($params['charge'])) | |
$this->setCharge($params['charge']); | |
if (isset($params['cells'])) | |
$this->setCells($params['cells']); | |
if (isset($params['packaging'])) | |
$this->setPackaging($params['packaging']); | |
if (isset($params['exempt'])) | |
$this->setExempt($params['exempt']); | |
} | |
else | |
{ | |
$this->setCells(1); | |
$this->setPackaging(self::BATTERY_ONLY); | |
} | |
} | |
public static function create ($chemistry) | |
{ | |
if ($chemistry == static::LI_ION) | |
return new LiIonBattery(); | |
else if ($chemistry == static::LI_METAL) | |
return new LiMetalBattery(); | |
} | |
public function setWeight($weight) | |
{ | |
if (! is_numeric($weight) || $weight < 0) | |
throw new Exception('Invalid battery weight.'); | |
$this->weight = $weight; | |
return $this; | |
} | |
public function setCells($cells) | |
{ | |
if (! is_integer($cells) || $cells < 1) | |
throw new Exception('Invalid number of battery cells.'); | |
$this->cells = $cells; | |
return $this; | |
} | |
// ... | |
public function getWeight() | |
{ | |
return $this->weight; | |
} | |
public function isLiIon() | |
{ | |
return $this instanceOf LiIonBattery; | |
} | |
public function isLiMetal() | |
{ | |
return $this instanceOf LiMetalBattery; | |
} | |
public function getCells() | |
{ | |
return $this->cells; | |
} | |
public function isBattery() | |
{ | |
return $this->cells > 1; | |
} | |
// ... | |
public function getEnergy() | |
{ | |
return $this->voltage * $this->charge; | |
} | |
public function getPackaging() | |
{ | |
return $this->packaging; | |
} | |
public function isBatteryOnly() | |
{ | |
return $this->packaging == static::BATTERY_ONLY; | |
} | |
// ... | |
public function validateBattery() | |
{ | |
if ($this->weight === null) | |
throw new Exception('Weight must be set.'); | |
if ($this->voltage === null) | |
throw new Exception('Voltage must be set.'); | |
if ($this->charge === null) | |
throw new Exception('Charge must be set.'); | |
if ($this->cells === null) | |
throw new Exception('Cells must be set.'); | |
if ($this->packaging === null) | |
throw new Exception('Packaging must be set.'); | |
} | |
public function qValue() | |
{ | |
$this->validateBattery(); | |
if ($this->isSmall()) | |
return $this->getWeight() / static::Q_SM; | |
else if ($this->isMedium() && $this->isCell()) | |
return 1 / static::Q_CELL_MED; | |
else if ($this->isMedium() && $this->isBattery()) | |
return 1 / static::Q_BATT_MED; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace SparkLib\HazmatClassifier; | |
use \Exception; | |
use \SparkLib\HazmatClassifier\HazmatClassifier, | |
\SparkLib\HazmatClassifier\Package, | |
\SparkLib\HazmatClassifier\LineItem, | |
\SparkLib\HazmatClassifier\Battery; | |
class IataClassifier extends HazmatClassifier { | |
// No classification required | |
const IATA_NONE = 000; | |
// Lithium ion | |
const IATA_965_IA = 111; | |
const IATA_965_IB = 112; | |
const IATA_965_II = 113; | |
// Lithium ion packed with equipment | |
const IATA_966_I = 121; | |
const IATA_966_II = 122; | |
// Lithium ion contained in equipment | |
const IATA_967_I = 131; | |
const IATA_967_II = 132; | |
// ... etc ... | |
protected static $classNames = [ | |
self::IATA_NONE => 'IATA None', | |
self::IATA_965_IA => 'IATA 965 IA', | |
self::IATA_965_IB => 'IATA 965 IB', | |
self::IATA_965_II => 'IATA 965 II', | |
]; | |
// Li Ion Classes | |
private $liIonClasses = [ | |
self::IATA_965_IA, | |
self::IATA_965_IB, | |
]; | |
// ... | |
protected function classify() | |
{ | |
$p = $this->package; | |
// | |
// If the package has no batteries, it has no IATA classification | |
// | |
if (! $p->hasBatteries()) { | |
$this->classification = self::IATA_NONE; | |
} | |
// | |
// If there are batteries of multiple packaging types, it is too much for | |
// the poor classifier to handle, and it should be classified as IATA | |
// Multiple. | |
// | |
else if ($p->hasMultiplePackagingTypes()) { | |
$this->classification = self::IATA_MULTIPLE; | |
} | |
// | |
// If there are batteries of multiple chemestries ( ion / metal ) it is | |
// too much for the poor classifier to handle, and it should be classified | |
// as IATA Multiple. | |
// | |
else if ($p->hasMultipleChemistries()) { | |
$this->classification = self::IATA_MULTIPLE; | |
} | |
// | |
// If there are batteries of multiple sizes ( i.e. more or less than | |
// 2.5 kWh, etc. ), it is too much for the poor classifier to handle, and | |
// it should be classified as IATA Multiple. | |
// | |
else if ($p->hasMultipleSizes()) { | |
$this->classification = self::IATA_MULTIPLE; | |
} | |
// | |
// If none of the above criteria are met, it should be classified based on | |
// the classification of the largest battery in the package. | |
// | |
else { | |
$this->classification = $p->largestBattery()->iataClassification(); | |
} | |
// | |
// All packages with any type of classification require a declaration | |
// | |
if ($this->getClassification() != self::IATA_NONE) { | |
$this->setBatteryDecRequired(); | |
} | |
// | |
// Set the appropriate sticker for lithium ion | |
// | |
if ($this->isLiIonClass()) { | |
$this->setStickerLiIonRequired(); | |
} | |
// | |
// Or for lithium metal | |
// | |
else if ($this->isLiMetalClass()) { | |
$this->setStickerLiMetalRequired(); | |
} | |
// ... | |
if ($p->hasSmallAndMediumBatteries()) { | |
$this->bumpClassTwoClassification(); | |
} | |
// | |
// The weight of the small batteries is too large | |
// | |
else if ($p->hasSmallBattery() && $p->calcBatteryWeight() > Battery::Q_SM) { | |
$this->bumpClassTwoClassification(); | |
} | |
// ... | |
} | |
public function isRestrictedClass() | |
{ | |
return $this->getClassification() != static::IATA_NONE; | |
} | |
public static function idToClassificationName($class) | |
{ | |
if (array_key_exists($class, self::$classNames)) | |
return self::$classNames[$class]; | |
} | |
private function isLiIonClass() | |
{ | |
return $this->isClassificationType($this->liIonClasses); | |
} | |
private function isLiMetalClass() | |
{ | |
return $this->isClassificationType($this->liMetalClasses); | |
} | |
// ... | |
private function bumpClassTwoClassification() | |
{ | |
if ($this->getClassification() == self::IATA_965_II) | |
{ | |
$this->classification = self::IATA_965_IB; | |
$this->setStickerHazardRequired(); | |
} | |
else if ($this->getClassification() == self::IATA_968_II) | |
{ | |
$this->classification = self::IATA_968_IB; | |
$this->setStickerHazardRequired(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace SparkLib\HazmatClassifier; | |
use \Exception; | |
use \SparkLib\HazmatClassifier\Battery, | |
\SparkLib\HazmatClassifier\IataClassifier; | |
class LiIonBattery extends Battery | |
{ | |
// Classification cutoffs | |
const LI_ION_SM = 2.7; | |
const LI_ION_CELL = 20.0; | |
const LI_ION_BATT = 100.0; | |
public static function create($chemistry = null) | |
{ | |
return new static; | |
} | |
public function getChemistry() | |
{ | |
return Battery::LI_ION; | |
} | |
public function getLithiumContent() | |
{ | |
return $this->getEnergy() * 0.3; | |
} | |
public function dotClassification() | |
{ | |
switch ($this->getPackaging()) { | |
case Battery::BATTERY_ONLY : return DotClassifier::UN_3480; | |
case Battery::PACKED_EQUIPMENT : return DotClassifier::UN_3481_P; | |
case Battery::CONTAINED_EQUIPMENT : return DotClassifier::UN_3481_C; | |
} | |
} | |
public function iataSize() | |
{ | |
if ($this->getEnergy() <= static::LI_ION_SM) | |
return static::SMALL; | |
else if ($this->isCell() && $this->getEnergy() <= static::LI_ION_CELL) | |
return static::MEDIUM; | |
else if ($this->isBattery() && $this->getEnergy() <= static::LI_ION_BATT) | |
return static::MEDIUM; | |
else | |
return static::LARGE; | |
} | |
public function iataClassification() | |
{ | |
switch ($this->getPackaging()) | |
{ | |
case Battery::BATTERY_ONLY : | |
switch ($this->iataSize()) { | |
case static::SMALL : return IataClassifier::IATA_965_II; | |
case static::MEDIUM : return IataClassifier::IATA_965_II; | |
case static::LARGE : return IataClassifier::IATA_965_IA; | |
} | |
case Battery::PACKED_EQUIPMENT : | |
switch ($this->iataSize()) { | |
case static::SMALL : return IataClassifier::IATA_966_II; | |
case static::MEDIUM : return IataClassifier::IATA_966_II; | |
case static::LARGE : return IataClassifier::IATA_966_I; | |
} | |
case Battery::CONTAINED_EQUIPMENT : | |
switch ($this->iataSize()) { | |
case static::SMALL : return IataClassifier::IATA_967_II; | |
case static::MEDIUM : return IataClassifier::IATA_967_II; | |
case static::LARGE : return IataClassifier::IATA_967_I; | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment