name]; } /** * Get enum label. * * @return string */ public function label(): string { return self::toLabels()[$this->name]; } /** * Get enum name. * * @return string */ public function name(): string { return $this->name; } // * STATIC FETCH METHODS /** * Get enum labels. * * @return array */ public static function toLabels(): array { if (empty(self::getCache('labels'))) { $labels = self::getLabelsConstant(); $array = []; \array_map(function ($enum) use (&$array, $labels) { if (!\is_null($labels) and !isset($labels[$enum->name])) { throw new \Error('Missing definition label ' . self::class . " for {$enum->name}"); } $array = array_merge($array, [$enum->name => __( !\is_null($labels) ? $labels[$enum->name] : ucfirst($enum->name) )]); }, self::cases()); self::setCache('labels', $array); } return self::getCache('labels'); } /** * Get enum values. * * @return array */ public static function toValues(): array { if (empty(self::getCache('values'))) { $array = []; \array_map(function ($enum) use (&$array) { $array = array_merge($array, [$enum->name => $enum->value]); }, self::cases()); self::setCache('values', $array); } return self::getCache('values'); } /** * Get enums. * * @return array */ public static function all(): array { return self::cases(); } /** * Get enums. * * @return array */ public static function toArray(): array { if (empty(self::getCache('enums'))) { $definitions = self::getCustomDefinitions(); $array = []; $inflector = InflectorFactory::create()->build(); \array_map(function ($enum) use (&$array, $definitions, $inflector) { $baseArray = [ 'name' => $enum->name, 'label' => $enum->label(), 'value' => $enum->value, ]; foreach ($definitions as $index => $elements) { $index = $inflector->singularize(strtolower($index)); if (!isset($elements[$enum->name])) { throw new \Error("Missing definition {$index} " . self::class . " for {$enum->name}"); } $baseArray[$index] = $elements[$enum->name]; } $array = array_merge($array, [$enum->name => (object)$baseArray]); }, self::cases()); self::setCache('enums', $array); } //end if return self::getCache('enums'); } /** * Fetch enum using value. * * @param \App\Traits\Enums\BaseEnum|integer|string $value * @param string $field * @return \App\Traits\Enums\BaseEnum|null */ public static function make(self|int|string $value, string $field = 'value'): self|null { return !\is_object($value) ? self::cases()[array_search($value, array_column(self::cases(), $field))] : $value; } /** * Test if 2 enum are equals. * * @param object ...$others * @return boolean * @throws \Error If provided element are not enums taht extends BaseEnum. */ public function equals(object ...$others): bool { foreach ($others as $other) { if (!\in_array(BaseEnum::class, $this->classUsesRecursive($other))) { throw new \Error(__METHOD__ . ' requires $enum to use ' . BaseEnum::class); } if ( get_class($this) === get_class($other) && $this->value === $other->value ) { return true; } } return false; } /** * Serialize to json. * * @return mixed */ public function jsonSerialize(): mixed { return $this->value; } // * CACHE /** * Get cache array. * * @param string $index * @return array */ private static function getCache(string $index): array { self::initCache(); if (!isset($GLOBALS[self::class]['props'][$index])) { $GLOBALS[self::class]['props'][$index] = []; } return $GLOBALS[self::class]['props'][$index]; } /** * Set cache array. * * @param string $index * @param array $items * @return void */ private static function setCache(string $index, array $items): void { self::initCache(); if (!isset($GLOBALS[self::class]['props'][$index])) { $GLOBALS[self::class]['props'][$index] = []; } $GLOBALS[self::class]['props'][$index] = $items; } /** * Init cache if needed. * * @return void */ private static function initCache(): void { if (!isset($GLOBALS[self::class])) { $GLOBALS[self::class] = [ 'props' => [ 'enums' => [], 'values' => [], 'labels' => [] ], 'customProps' => null ]; } } // * PRIVATE /** * Fetch the LABELS constant if exists. * * @return array|null */ private static function getLabelsConstant(): array|null { $class_name = self::class; try { $constant_reflex = new \ReflectionClassConstant($class_name, 'LABELS'); return $constant_reflex->getValue(); } catch (\ReflectionException $e) { return null; } } /** * Get custom constants. * * @return array */ private static function getCustomDefinitions(): array { // ? Has custom props in cache ? if (!isset($GLOBALS[self::class]) or \is_null($GLOBALS[self::class]['customProps'])) { $names = []; \array_map(function (self $enum) use (&$names) { $names = array_merge($names, [$enum->name => $enum]); }, self::cases()); $GLOBALS[self::class]['customProps'] = \array_filter( (new \ReflectionClass(self::class))->getConstants(), function (mixed $constant, string $key) use ($names) { if ($key === 'LABELS' or !\is_array($constant)) { return false; } return count(\array_filter( array_flip($constant), function (string $name) use ($names) { return array_key_exists($name, $names); } )); }, ARRAY_FILTER_USE_BOTH ); } //end if return $GLOBALS[self::class]['customProps']; } /** * Returns all traits used by a class, its parent classes and trait of their traits. * * @param object|string $class * @return array */ private function classUsesRecursive($class) { if (is_object($class)) { $class = get_class($class); } $results = []; foreach (array_reverse(class_parents($class) ?: []) + [$class => $class] as $class) { $results += $this->traitUsesRecursive($class); } return array_unique($results); } /** * Returns all traits used by a trait and its traits. * * @param object|string $trait * @return array */ private function traitUsesRecursive($trait) { $traits = class_uses($trait) ?: []; foreach ($traits as $trait) { $traits += $this->traitUsesRecursive($trait); } return $traits; } }