SpareParts /
Enum
| 1 | <?php |
||
| 2 | namespace SpareParts\Enum\Set\Converter; |
||
| 3 | |||
| 4 | use SpareParts\Enum\Enum; |
||
| 5 | use SpareParts\Enum\Exception\EnumSetMustContainEnumsException; |
||
| 6 | use SpareParts\Enum\Set\ISet; |
||
| 7 | use SpareParts\Enum\Set\ImmutableSet; |
||
| 8 | |||
| 9 | class BitMaskConverter implements IEnumSetConverter |
||
| 10 | { |
||
| 11 | /** |
||
| 12 | * @var string |
||
| 13 | */ |
||
| 14 | private $enumClass; |
||
| 15 | |||
| 16 | /** |
||
| 17 | * @var array |
||
| 18 | */ |
||
| 19 | private $mapping; |
||
| 20 | |||
| 21 | /** |
||
| 22 | * @param Enum[] $enumValuesMap |
||
| 23 | */ |
||
| 24 | 13 | public function __construct(iterable $enumValuesMap) |
|
| 25 | { |
||
| 26 | 13 | if (!count($enumValuesMap)) { |
|
| 27 | 1 | throw new EnumSetMustContainEnumsException('You have to provide converter mapping.'); |
|
| 28 | } |
||
| 29 | 12 | $this->mapping = $this->prepareInnerMapping($enumValuesMap); |
|
| 30 | 9 | } |
|
| 31 | |||
| 32 | /** |
||
| 33 | * @param int $values A number representing a bit mask |
||
| 34 | * @return ISet |
||
| 35 | */ |
||
| 36 | 5 | public function convertToEnumSet($values) : ISet |
|
| 37 | { |
||
| 38 | 5 | $bitValue = (int) $values; |
|
| 39 | |||
| 40 | 5 | $set = []; |
|
| 41 | 5 | foreach ($this->mapping as $value => $bit) { |
|
| 42 | 5 | if ($bitValue & $bit) { |
|
| 43 | 5 | $set[] = call_user_func([$this->enumClass, 'instance'], $value); |
|
| 44 | } |
||
| 45 | } |
||
| 46 | 5 | return new ImmutableSet($this->enumClass, $set); |
|
| 47 | } |
||
| 48 | |||
| 49 | 4 | public function convertFromEnumSet(ISet $enumSet): int |
|
| 50 | { |
||
| 51 | 4 | $bitValue = 0; |
|
| 52 | /** @var Enum $value */ |
||
| 53 | 4 | foreach ($enumSet as $value) { |
|
| 54 | 3 | $bitValue = $bitValue | $this->mapping[(string) $value]; |
|
| 55 | } |
||
| 56 | 4 | return $bitValue; |
|
| 57 | } |
||
| 58 | |||
| 59 | 12 | private function prepareInnerMapping(iterable $enumValuesMap): array |
|
| 60 | { |
||
| 61 | // translate enum values to bit values mapping |
||
| 62 | 12 | $innerMapping = []; |
|
| 63 | 12 | $shift = 0; |
|
| 64 | 12 | foreach ($enumValuesMap as $value) { |
|
| 65 | 12 | $this->updateEnumClass($value); |
|
| 66 | |||
| 67 | 11 | $innerMapping[(string)$value] = 1 << $shift; |
|
| 68 | 11 | $shift++; |
|
| 69 | } |
||
| 70 | 9 | return $innerMapping; |
|
| 71 | } |
||
| 72 | |||
| 73 | 11 | private function updateEnumClass(Enum $value): void |
|
| 74 | { |
||
| 75 | // try to guess enum class |
||
| 76 | 11 | if (is_null($this->enumClass)) { |
|
|
0 ignored issues
–
show
introduced
by
Loading history...
|
|||
| 77 | 11 | $this->enumClass = get_class($value); |
|
| 78 | } |
||
| 79 | 11 | if (!is_object($value) || !($value instanceof $this->enumClass)) { |
|
| 80 | 1 | throw new EnumSetMustContainEnumsException(sprintf("Expected `%s`, got `%s`", $this->enumClass, $this->printVar($value))); |
|
| 81 | } |
||
| 82 | 11 | } |
|
| 83 | |||
| 84 | /** |
||
| 85 | * @param mixed $value |
||
| 86 | * @return string |
||
| 87 | */ |
||
| 88 | 1 | private function printVar($value): string |
|
| 89 | { |
||
| 90 | 1 | return is_object($value) ? get_class($value) : var_export($value, true); |
|
| 91 | } |
||
| 92 | } |
||
| 93 |