diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 17af793..701a8e3 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -5,14 +5,17 @@ on: push jobs: testing: runs-on: ubuntu-latest - container: - image: lazerg/laravel:php81 + strategy: + matrix: + php: ['8.1', '8.2', '8.3', '8.4', '8.5'] steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v4 + - name: Setup PHP + uses: shivammathur/setup-php@v2 with: - fetch-depth: 1 - - name: install composer dependencies [by @lazerg] - run: | - composer install --no-scripts - - name: Run Tests [by @lazerg] - run: php -d memory_limit=2048M ./vendor/bin/pest \ No newline at end of file + php-version: ${{ matrix.php }} + coverage: none + - name: Install composer dependencies + run: composer update --no-interaction --prefer-dist + - name: Run Tests + run: ./vendor/bin/pest diff --git a/.gitignore b/.gitignore index 0af3a88..0b0ba30 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ vendor/ composer.lock .phpunit.result.cache +.phpunit.cache/ diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..0a5e6d8 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,90 @@ +# Laravel Enum Pro - Development Guide + +## Coding Rules + +### Performance First +- Use native PHP functions (`array_column`, `array_map`, `array_combine`, `array_filter`, `array_keys`, `array_values`, `implode`, etc.) for better performance +- Only use `Collection` when the method's return type requires it +- Base methods should return arrays, Collection methods should wrap them with `collect()` + +### Method Organization +Order methods from base (native PHP) to derived (Collection): +1. `toArray()` methods first - use native PHP functions +2. `toString()` methods - use native PHP with array methods +3. Collection methods - wrap array methods with `collect()` +4. Lookup methods last + +### Example Pattern +```php +// 1. Base method - native PHP +public static function namesToArray(): array +{ + return array_column(self::cases(), 'name'); +} + +// 2. String method - uses base +public static function namesToString(string $separator = ', '): string +{ + return implode($separator, self::namesToArray()); +} + +// 3. Collection method - wraps base +public static function names(): Collection +{ + return collect(self::namesToArray()); +} +``` + +## Testing Rules + +### Use Pest with `it()` syntax +- Use `it()` instead of `test()` for BDD-style readability +- Start descriptions with "can" for success cases: `it('can get...')` +- Start descriptions with "throws" for exception cases: `it('throws exception when...')` + +### Test Naming Convention +```php +// Success cases - describe capability +it('can get all enum names as a collection', function () { ... }); +it('can get enum value by its name with case-insensitive lookup', function () { ... }); + +// Exception cases - describe failure condition +it('throws exception when requesting more random values than available', function () { ... }); +it('throws exception when calling non-existent case as static method', function () { ... }); +``` + +### Best Practices +- Chain expectations with `->and()` for multiple assertions +- Keep test descriptions clear and specific +- Describe what the method does, not how it does it +- Include context (e.g., "as a collection", "as an array", "by its value") +- Use `use Tests\DifficultyEnum;` at top of test files + +## Project Structure + +``` +src/ +├── EnumPro.php # Main trait (combines all) +├── EnumNames.php # Name methods +├── EnumValues.php # Value methods +├── EnumOptions.php # Options/selections for forms +├── EnumRandom.php # Random selection +├── EnumStaticCalls.php # Magic methods +└── Exceptions/ + ├── UndefinedCaseException.php + └── TooManyRandomValuesException.php + +tests/ +├── DifficultyEnum.php # Test enum fixture +├── EnumNamesTest.php +├── EnumValuesTest.php +├── EnumOptionsTest.php +├── EnumRandomTest.php +└── EnumStaticCallsTest.php +``` + +## Testing + +```bash +./vendor/bin/pest +``` diff --git a/README.md b/README.md index 7000faa..6c881e3 100644 --- a/README.md +++ b/README.md @@ -3,20 +3,12 @@ ![Laravel Enum Pro](./wallpaper/wallpaper.png) [![Latest Version](https://img.shields.io/packagist/v/lazerg/laravel-enum-pro.svg?style=flat-square)](https://packagist.org/packages/lazerg/laravel-enum-pro) +[![PHP Version](https://img.shields.io/packagist/php-v/lazerg/laravel-enum-pro?style=flat-square)](https://packagist.org/packages/lazerg/laravel-enum-pro) [![Downloads](https://img.shields.io/packagist/dm/lazerg/laravel-enum-pro.svg?style=flat-square)](https://packagist.org/packages/lazerg/laravel-enum-pro) -[![Repository Size](https://img.shields.io/github/repo-size/lazerg/laravel-enum-pro?style=flat-square)](https://github.com/lazerg/laravel-enum-pro) -[![Last Commit](https://img.shields.io/github/last-commit/lazerg/laravel-enum-pro?style=flat-square)](https://github.com/lazerg/laravel-enum-pro) +[![Total Downloads](https://img.shields.io/packagist/dt/lazerg/laravel-enum-pro?style=flat-square)](https://packagist.org/packages/lazerg/laravel-enum-pro) [![Packagist Stars](https://img.shields.io/packagist/stars/lazerg/laravel-enum-pro?style=flat-square)](https://packagist.org/packages/lazerg/laravel-enum-pro) -`Laravel Enum Pro` is a simple trait that extends PHP 8.1+ enums with helpful utilities for Laravel applications. It lets you access enum data in a variety of convenient ways while keeping your code clean and expressive. - -## Features - -- Works directly with native PHP enums -- Access case values via static method calls -- Retrieve enum names and values as collections, arrays or strings -- Generate random values for testing and factories -- Build option and selection lists for form inputs +A powerful trait that supercharges PHP 8.1+ enums with Laravel-friendly utilities. Get values, names, random cases, and form-ready options with a clean, fluent API. ## Installation @@ -24,12 +16,10 @@ composer require lazerg/laravel-enum-pro ``` -## Basic Usage - -Create an enum and include the trait: +## Enum Example ```php -enum LevelTypes: int +enum DifficultyEnum: int { use \Lazerg\LaravelEnumPro\EnumPro; @@ -41,71 +31,102 @@ enum LevelTypes: int } ``` -### Accessing Values +## Accessing Value ```php -LevelTypes::VERY_EASY(); // 1 -LevelTypes::valueOf('very easy'); // 1 +// 1 +DifficultyEnum::VERY_EASY(); + +// 3 +DifficultyEnum::MEDIUM(); + +// 5 +DifficultyEnum::VERY_STRONG(); + +// 3 +$enum = DifficultyEnum::MEDIUM; +$enum(); ``` -### Working With Names +## Accessing Name ```php -LevelTypes::names(); // Collection: ['VERY_EASY', 'EASY', 'MEDIUM', 'STRONG', 'VERY_STRONG'] -LevelTypes::namesToArray(); // ['VERY_EASY', 'EASY', 'MEDIUM', 'STRONG', 'VERY_STRONG'] -LevelTypes::namesToString(); // "VERY_EASY, EASY, MEDIUM, STRONG, VERY_STRONG" -LevelTypes::nameOf(1); // 'VERY_EASY' +// ['VERY_EASY', 'EASY', 'MEDIUM', 'STRONG', 'VERY_STRONG'] +DifficultyEnum::namesToArray(); + +// 'VERY_EASY, EASY, MEDIUM, STRONG, VERY_STRONG' +DifficultyEnum::namesToString(); + +// Collection(['VERY_EASY', 'EASY', 'MEDIUM', 'STRONG', 'VERY_STRONG']) +DifficultyEnum::names(); + +// 'MEDIUM' +DifficultyEnum::nameOf(3); ``` -### Working With Values +## Accessing Values ```php -LevelTypes::values(); // Collection: [1, 2, 3, 4, 5] -LevelTypes::valuesToArray(); // [1, 2, 3, 4, 5] -LevelTypes::valuesToString(); // "1,2,3,4,5" +// [1, 2, 3, 4, 5] +DifficultyEnum::valuesToArray(); + +// '1,2,3,4,5' +DifficultyEnum::valuesToString(); + +// Collection([1, 2, 3, 4, 5]) +DifficultyEnum::values(); + +// 1 +DifficultyEnum::valueOf('VERY_EASY'); + +// 3 (case-insensitive) +DifficultyEnum::valueOf('medium'); + +// 5 (spaces converted to underscores) +DifficultyEnum::valueOf('Very strong'); ``` -### Randomization +## Accessing Options ```php -LevelTypes::random(); // Collection with one random value -LevelTypes::randomArray(); // Array with one random value -LevelTypes::randomFirst(); // Single random value -``` +// [1 => 'Very Easy', 2 => 'Easy', 3 => 'Medium', 4 => 'Strong', 5 => 'Very Strong'] +DifficultyEnum::optionsToArray(); -### Options and Selections +// Collection([1 => 'Very Easy', 2 => 'Easy', 3 => 'Medium', 4 => 'Strong', 5 => 'Very Strong']) +DifficultyEnum::options(); -Use these helpers when building form inputs. +// 'Very Strong' +DifficultyEnum::getOption(5); -```php -LevelTypes::options(); // Collection of [value => display] -LevelTypes::optionsToArray(); -LevelTypes::selections(); // Collection of [value => ..., display => ...] -LevelTypes::selectionsToArray(); +// ['Medium', 'Very Strong'] +DifficultyEnum::getOptions([3, 5]); + +// [['value' => 1, 'display' => 'Very Easy'], ['value' => 2, 'display' => 'Easy'], ...] +DifficultyEnum::selectionsToArray(); + +// Collection([['value' => 1, 'display' => 'Very Easy'], ['value' => 2, 'display' => 'Easy'], ...]) +DifficultyEnum::selections(); ``` -Example output of `options()`: +## Accessing Random Value ```php -Illuminate\Support\Collection { - #items: [ - 1 => "Very Easy", - 2 => "Easy", - 3 => "Medium", - 4 => "Strong", - 5 => "Very Strong", - ] -} +// [3, 1] (random values) +DifficultyEnum::randomArray(2); + +// 4 (single random value) +DifficultyEnum::randomFirst(); + +// Collection([2, 5, 1]) (random values) +DifficultyEnum::random(3); ``` ## Testing -Run the test suite with [Pest](https://pestphp.com/): - ```bash ./vendor/bin/pest ``` ## License -This package is open-sourced software licensed under the [MIT license](LICENSE) as specified in `composer.json`. +This package is open-sourced software licensed under the [MIT license](LICENSE). diff --git a/composer.json b/composer.json index eee3190..bf9eeee 100644 --- a/composer.json +++ b/composer.json @@ -1,30 +1,44 @@ { "name": "lazerg/laravel-enum-pro", - "description": "Laravel Enum Pro", + "description": "A powerful PHP enum extension with collection support, random selection, and magic static calls", "type": "library", "license": "MIT", + "keywords": ["laravel", "enum", "php", "collection", "helper"], + "homepage": "https://github.com/lazerg/laravel-enum-pro", "authors": [ { "name": "lazerg", "email": "lazerg2@gmail.com" } ], + "support": { + "issues": "https://github.com/lazerg/laravel-enum-pro/issues", + "source": "https://github.com/lazerg/laravel-enum-pro" + }, "minimum-stability": "stable", "require": { - "php": "^8.1|^8.2|^8.3|^8.4", - "illuminate/support": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0" + "php": "^8.1", + "illuminate/support": "^9.0|^10.0|^11.0|^12.0" }, "autoload": { "psr-4": { "Lazerg\\LaravelEnumPro\\": "src/" } }, + "autoload-dev": { + "psr-4": { + "Tests\\": "tests/" + } + }, "require-dev": { - "pestphp/pest": "^1.22|^2.0|^3.0" + "pestphp/pest": "^1.0|^2.0|^3.0" }, "config": { "allow-plugins": { "pestphp/pest-plugin": true } + }, + "scripts": { + "test": "pest" } } diff --git a/phpunit.xml b/phpunit.xml index 8f4b58c..f22a919 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -3,16 +3,18 @@ xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd" bootstrap="vendor/autoload.php" colors="true" + cacheDirectory=".phpunit.cache" + stopOnFailure="false" > ./tests - + + - ./app ./src - + diff --git a/src/EnumNames.php b/src/EnumNames.php index 46a72c2..adfcf9d 100644 --- a/src/EnumNames.php +++ b/src/EnumNames.php @@ -7,38 +7,62 @@ trait EnumNames { /** - * Return all names of enum as collection + * Get all enum case names as an array. + * + * @return array + * @example DifficultyEnum::namesToArray() + * // ['VERY_EASY', 'EASY', 'MEDIUM', 'STRONG', 'VERY_STRONG'] * - * @return Collection */ - public static function names(): Collection + public static function namesToArray(): array { - return collect(self::cases()) - ->map(fn($case) => $case->name); + return array_column(self::cases(), 'name'); } /** - * Return all names of enum as string separated by comma + * Get all enum case names as a string. * + * @param string $separator * @return string + * @example DifficultyEnum::namesToString() + * // 'VERY_EASY, EASY, MEDIUM, STRONG, VERY_STRONG' + * + * @example DifficultyEnum::namesToString(' | ') + * // 'VERY_EASY | EASY | MEDIUM | STRONG | VERY_STRONG' + * */ - public static function namesToString(): string + public static function namesToString(string $separator = ', '): string { - return self::names()->join(', '); + return implode($separator, self::namesToArray()); } /** - * Return all names of enum as array + * Get all enum case names as a Collection. + * + * @return Collection + * @example DifficultyEnum::names() + * // Collection(['VERY_EASY', 'EASY', 'MEDIUM', 'STRONG', 'VERY_STRONG']) * - * @return array */ - public static function namesToArray(): array + public static function names(): Collection { - return self::names()->toArray(); + return collect(self::namesToArray()); } - public static function nameOf(mixed $case): string + /** + * Get the enum case name by its value. + * + * @param mixed $value + * @return string|null + * @example DifficultyEnum::nameOf(3) + * // 'MEDIUM' + * + * @example DifficultyEnum::nameOf(99) + * // null + * + */ + public static function nameOf(mixed $value): ?string { - return array_column(self::cases(), 'name', 'value')[$case]; + return array_column(self::cases(), 'name', 'value')[$value] ?? null; } } diff --git a/src/EnumOptions.php b/src/EnumOptions.php index 4b3576e..dc9c3a2 100644 --- a/src/EnumOptions.php +++ b/src/EnumOptions.php @@ -3,103 +3,103 @@ namespace Lazerg\LaravelEnumPro; use Illuminate\Support\Collection; -use Illuminate\Support\Str; -use UnitEnum; trait EnumOptions { /** - * Convert cases of enum to collection of options + * Get all enum cases as key-value array with formatted labels. * - * @input - * case RENTAL_TRUCK = 1; - * case CONTAINER = 2; - * case FREIGHT_TRAILER = 3; + * @return array + * @example DifficultyEnum::optionsToArray() + * // [1 => 'Very Easy', 2 => 'Easy', 3 => 'Medium', 4 => 'Strong', 5 => 'Very Strong'] * - * @output - * [ - * 1 => "Rental Truck" - * 2 => "Container" - * 3 => "Freight Trailer" - * ] - * - * @return Collection */ - public static function options(): Collection + public static function optionsToArray(): array { - return collect(self::cases())->mapWithKeys(fn(UnitEnum $enum) => [ - $enum->value => Str::of($enum->name) - ->replace('_', ' ') - ->title() - ->value() - ]); + return array_combine( + array_column(self::cases(), 'value'), + array_map(fn($case) => ucwords(strtolower(str_replace('_', ' ', $case->name))), self::cases()) + ); } /** - * Get a value of an option + * Get all enum cases as a Collection with formatted labels. + * + * @return Collection + * @example DifficultyEnum::options() + * // Collection([1 => 'Very Easy', 2 => 'Easy', 3 => 'Medium', 4 => 'Strong', 5 => 'Very Strong']) * - * @param string $value - * @return string */ - public static function getOption(string $value): string + public static function options(): Collection { - return self::options()[$value]; + return collect(self::optionsToArray()); } /** - * Get values of options + * Get a single option label by its value. + * + * @param mixed $value + * @return string|null + * @example DifficultyEnum::getOption(5) + * // 'Very Strong' + * + * @example DifficultyEnum::getOption(99) + * // null * - * @param array $values - * @return Collection */ - public static function getOptions(array $values): Collection + public static function getOption(mixed $value): ?string { - return self::options() - ->filter(fn($value, $key) => in_array($key, $values)) - ->values(); + return self::optionsToArray()[$value] ?? null; } /** - * Convert cases of enum to collection of selections - * - * @input - * case RENTAL_TRUCK = 1; - * case CONTAINER = 2; - * case FREIGHT_TRAILER = 3; + * Get multiple option labels by their values. * - * @output - * [ - * 0 => ['value' => 1, 'display' => 'Rental Truck'], - * 1 => ['value' => 2, 'display' => 'Container'], - * 3 => ['value' => 3, 'display' => 'Freight Trailer'] - * ] + * @param array $values + * @return array + * @example DifficultyEnum::getOptions([3, 5]) + * // ['Medium', 'Very Strong'] * - * @return Collection */ - public static function selections(): Collection + public static function getOptions(array $values): array { - return self::options() - ->map(fn($display, $value) => compact('value', 'display')) - ->values(); + return array_values(array_intersect_key(self::optionsToArray(), array_flip($values))); } /** - * Convert cases of enum to array of options + * Get all enum cases as array of selections for form inputs. + * + * @return array + * @example DifficultyEnum::selectionsToArray() + * // [ + * // ['value' => 1, 'display' => 'Very Easy'], + * // ['value' => 2, 'display' => 'Easy'], + * // ['value' => 3, 'display' => 'Medium'], + * // ['value' => 4, 'display' => 'Strong'], + * // ['value' => 5, 'display' => 'Very Strong'], + * // ] * - * @return array */ - public static function optionsToArray(): array + public static function selectionsToArray(): array { - return self::options()->toArray(); + $options = self::optionsToArray(); + return array_map(fn($value) => ['value' => $value, 'display' => $options[$value]], array_keys($options)); } /** - * Convert cases of enum to array of selections + * Get all enum cases as Collection of selections for form inputs. + * + * @return Collection + * @example DifficultyEnum::selections() + * // Collection([ + * // ['value' => 1, 'display' => 'Very Easy'], + * // ['value' => 2, 'display' => 'Easy'], + * // ... + * // ]) * - * @return array */ - public static function selectionsToArray(): array + public static function selections(): Collection { - return self::selections()->toArray(); + return collect(self::selectionsToArray()); } } diff --git a/src/EnumPro.php b/src/EnumPro.php index f0feda0..e4ff2ee 100644 --- a/src/EnumPro.php +++ b/src/EnumPro.php @@ -2,6 +2,26 @@ namespace Lazerg\LaravelEnumPro; +/** + * Supercharge PHP 8.1+ enums with Laravel-friendly utilities. + * + * @example enum DifficultyEnum: int + * { + * use \Lazerg\LaravelEnumPro\EnumPro; + * + * case VERY_EASY = 1; + * case EASY = 2; + * case MEDIUM = 3; + * case STRONG = 4; + * case VERY_STRONG = 5; + * } + * + * @see EnumStaticCalls For accessing values: DifficultyEnum::MEDIUM() // 3 + * @see EnumNames For accessing names: DifficultyEnum::namesToArray() // ['VERY_EASY', ...] + * @see EnumValues For accessing values: DifficultyEnum::valuesToArray() // [1, 2, 3, 4, 5] + * @see EnumOptions For form options: DifficultyEnum::optionsToArray() // [1 => 'Very Easy', ...] + * @see EnumRandom For random values: DifficultyEnum::randomFirst() // 3 (random) + */ trait EnumPro { use EnumValues, diff --git a/src/EnumRandom.php b/src/EnumRandom.php index 0b910a9..bc32196 100644 --- a/src/EnumRandom.php +++ b/src/EnumRandom.php @@ -3,43 +3,57 @@ namespace Lazerg\LaravelEnumPro; use Illuminate\Support\Collection; -use InvalidArgumentException; +use Lazerg\LaravelEnumPro\Exceptions\TooManyRandomValuesException; trait EnumRandom { /** - * Get $count random values in collection + * Get random enum values as an array. * * @param int $count - * @return Collection + * @return array + * @throws TooManyRandomValuesException When requesting more values than available + * @example DifficultyEnum::randomArray(2) + * // [3, 1] (random) + * */ - public static function random(int $count = 1): Collection + public static function randomArray(int $count = 1): array { - if ($count > self::values()->count()) { - throw new InvalidArgumentException('Count of random values is greater than count of enum values'); + $values = self::valuesToArray(); + + if ($count > count($values)) { + throw new TooManyRandomValuesException($count, count($values)); } - return self::values()->shuffle()->take($count); + $keys = array_rand($values, $count); + return array_map(fn($key) => $values[$key], (array) $keys); } /** - * Get one random value + * Get a single random enum value. * * @return int|string + * @example DifficultyEnum::randomFirst() + * // 4 (random) + * */ public static function randomFirst(): int|string { - return self::random()->first(); + return self::randomArray()[0]; } /** - * Get $count random values in array + * Get random enum values as a Collection. * * @param int $count - * @return array + * @return Collection + * @throws TooManyRandomValuesException When requesting more values than available + * @example DifficultyEnum::random(3) + * // Collection([2, 5, 1]) (random) + * */ - public static function randomArray(int $count = 1): array + public static function random(int $count = 1): Collection { - return self::random($count)->toArray(); + return collect(self::randomArray($count)); } } diff --git a/src/EnumStaticCalls.php b/src/EnumStaticCalls.php index f379bd6..554f985 100644 --- a/src/EnumStaticCalls.php +++ b/src/EnumStaticCalls.php @@ -2,31 +2,44 @@ namespace Lazerg\LaravelEnumPro; -use Exception; -use UnitEnum; +use Lazerg\LaravelEnumPro\Exceptions\UndefinedCaseException; trait EnumStaticCalls { /** + * Get the enum value by invoking the instance. + * * @return int|string + * @example $enum = DifficultyEnum::MEDIUM; + * $enum(); + * // 3 + * */ public function __invoke(): int|string { - /** @type UnitEnum $this */ return $this->value ?? $this->name; } /** - * @throws Exception + * Get the enum value using static method call with case name. + * + * @param string $name + * @param array $arguments + * @return int|string + * @throws UndefinedCaseException When case name does not exist + * @example DifficultyEnum::VERY_EASY() + * // 1 + * + * @example DifficultyEnum::MEDIUM() + * // 3 + * + * @example DifficultyEnum::VERY_STRONG() + * // 5 + * */ public static function __callStatic(string $name, array $arguments): int|string { - foreach (self::cases() as $case) { - if ($case->name === $name) { - return $case->value; - } - } - - throw new Exception("Case with name $name does not exist"); + return array_column(self::cases(), 'value', 'name')[$name] + ?? throw new UndefinedCaseException($name); } } diff --git a/src/EnumValues.php b/src/EnumValues.php index 7149681..37b96ad 100644 --- a/src/EnumValues.php +++ b/src/EnumValues.php @@ -3,57 +3,73 @@ namespace Lazerg\LaravelEnumPro; use Illuminate\Support\Collection; -use Illuminate\Support\Str; trait EnumValues { /** - * Return all values of enum as collection + * Get all enum case values as an array. + * + * @return array + * @example DifficultyEnum::valuesToArray() + * // [1, 2, 3, 4, 5] * - * @return Collection */ - public static function values(): Collection + public static function valuesToArray(): array { - return collect(self::cases()) - ->map(fn($case) => $case->value ?? $case->name); + return array_column(self::cases(), 'value') ?: array_column(self::cases(), 'name'); } /** - * Return all values of enum as string separated by comma + * Get all enum case values as a string. * + * @param string $separator * @return string + * @example DifficultyEnum::valuesToString() + * // '1,2,3,4,5' + * + * @example DifficultyEnum::valuesToString(' | ') + * // '1 | 2 | 3 | 4 | 5' + * */ - public static function valuesToString(): string + public static function valuesToString(string $separator = ','): string { - return self::values()->join(','); + return implode($separator, self::valuesToArray()); } /** - * Return all values of enum as array + * Get all enum case values as a Collection. + * + * @return Collection + * @example DifficultyEnum::values() + * // Collection([1, 2, 3, 4, 5]) * - * @return array */ - public static function valuesToArray(): array + public static function values(): Collection { - return self::values()->toArray(); + return collect(self::valuesToArray()); } /** - * Return value of enum by name + * Get the enum case value by its name (case-insensitive, spaces become underscores). * * @param string $name * @return int|string|null + * @example DifficultyEnum::valueOf('Very Strong') + * // 5 + * + * @example DifficultyEnum::valueOf('invalid') + * // null + * + * @example DifficultyEnum::valueOf('VERY_EASY') + * // 1 + * + * @example DifficultyEnum::valueOf('medium') + * // 3 + * */ public static function valueOf(string $name): null|int|string { - $name = Str::replace(' ', '_', Str::upper($name)); - - foreach (self::cases() as $case) { - if ($case->name === $name) { - return $case->value; - } - } - - return null; + $name = strtoupper(str_replace(' ', '_', $name)); + return array_column(self::cases(), 'value', 'name')[$name] ?? null; } } diff --git a/src/Exceptions/TooManyRandomValuesException.php b/src/Exceptions/TooManyRandomValuesException.php new file mode 100644 index 0000000..01e5477 --- /dev/null +++ b/src/Exceptions/TooManyRandomValuesException.php @@ -0,0 +1,13 @@ +toBeInstanceOf(\Illuminate\Support\Collection::class); }); -test('Get name of enums', function () { - expect(LevelTypes::namesToArray()) - ->toBe([ - 0 => 'VERY_EASY', - 1 => 'EASY', - 2 => 'MEDIUM', - 3 => 'STRONG', - 4 => 'VERY_STRONG' - ]); +it('can get all enum names as an array', function () { + expect(DifficultyEnum::namesToArray()) + ->toBe(['VERY_EASY', 'EASY', 'MEDIUM', 'STRONG', 'VERY_STRONG']); }); -test('Get name of enums as string', function () { - expect(LevelTypes::names()->implode(', ')) +it('can get all enum names as a comma-separated string', function () { + expect(DifficultyEnum::namesToString()) ->toBe('VERY_EASY, EASY, MEDIUM, STRONG, VERY_STRONG'); }); -test('Get name of enum', function () { - expect(LevelTypes::nameOf(LevelTypes::MEDIUM())) +it('can get enum name by its value', function () { + expect(DifficultyEnum::nameOf(DifficultyEnum::MEDIUM())) ->toBe('MEDIUM'); -}); \ No newline at end of file +}); diff --git a/tests/EnumOptionsTest.php b/tests/EnumOptionsTest.php index 9ad8994..3f432ff 100644 --- a/tests/EnumOptionsTest.php +++ b/tests/EnumOptionsTest.php @@ -1,58 +1,43 @@ toBeInstanceOf(\Illuminate\Support\Collection::class); }); -test('Get options of enum as array', function () { - expect(LevelTypes::optionsToArray())->tobe([ - 1 => "Very Easy", - 2 => "Easy", - 3 => "Medium", - 4 => "Strong", - 5 => "Very Strong" +it('can get all enum options as key-value array with formatted labels', function () { + expect(DifficultyEnum::optionsToArray())->toBe([ + 1 => 'Very Easy', + 2 => 'Easy', + 3 => 'Medium', + 4 => 'Strong', + 5 => 'Very Strong', ]); }); -test('Get a single options of enum', function () { - expect(LevelTypes::getOption(LevelTypes::VERY_STRONG())) +it('can get a single option label by its value', function () { + expect(DifficultyEnum::getOption(DifficultyEnum::VERY_STRONG())) ->toBe('Very Strong'); }); -test('Get multiple options of enum', function () { - $options = LevelTypes::getOptions([ - LevelTypes::MEDIUM(), - LevelTypes::VERY_STRONG() - ]); - - expect($options->toArray()) - ->toBe([ - "Medium", - "Very Strong" - ]); +it('can get multiple option labels by their values', function () { + expect(DifficultyEnum::getOptions([DifficultyEnum::MEDIUM(), DifficultyEnum::VERY_STRONG()])) + ->toBe(['Medium', 'Very Strong']); }); -test('Get selection of enums as collection', function () { - expect(LevelTypes::selections()) +it('can get all enum selections as a collection for form inputs', function () { + expect(DifficultyEnum::selections()) ->toBeInstanceOf(\Illuminate\Support\Collection::class); }); -test('Get selection of enums as array', function () { - expect(LevelTypes::selectionsToArray())->tobe([[ - "value" => 1, - "display" => "Very Easy" - ], [ - "value" => 2, - "display" => "Easy" - ], [ - "value" => 3, - "display" => "Medium" - ], [ - "value" => 4, - "display" => "Strong" - ], [ - "value" => 5, - "display" => "Very Strong" - ]]); -}); \ No newline at end of file +it('can get all enum selections as array with value and display keys', function () { + expect(DifficultyEnum::selectionsToArray())->toBe([ + ['value' => 1, 'display' => 'Very Easy'], + ['value' => 2, 'display' => 'Easy'], + ['value' => 3, 'display' => 'Medium'], + ['value' => 4, 'display' => 'Strong'], + ['value' => 5, 'display' => 'Very Strong'], + ]); +}); diff --git a/tests/EnumRandomTest.php b/tests/EnumRandomTest.php new file mode 100644 index 0000000..8526bab --- /dev/null +++ b/tests/EnumRandomTest.php @@ -0,0 +1,28 @@ +toBeInstanceOf(\Illuminate\Support\Collection::class); +}); + +it('can get a specific count of random enum values', function () { + expect(DifficultyEnum::random(3)) + ->toHaveCount(3); +}); + +it('can get a single random enum value', function () { + expect(DifficultyEnum::randomFirst()) + ->toBeIn([1, 2, 3, 4, 5]); +}); + +it('can get random enum values as an array', function () { + expect(DifficultyEnum::randomArray(2)) + ->toBeArray() + ->toHaveCount(2); +}); + +it('throws exception when requesting more random values than available', function () { + DifficultyEnum::random(10); +})->throws(\Lazerg\LaravelEnumPro\Exceptions\TooManyRandomValuesException::class); diff --git a/tests/EnumStaticCallsTest.php b/tests/EnumStaticCallsTest.php new file mode 100644 index 0000000..ebf9cd7 --- /dev/null +++ b/tests/EnumStaticCallsTest.php @@ -0,0 +1,22 @@ +toBe(1) + ->and(DifficultyEnum::MEDIUM())->toBe(3) + ->and(DifficultyEnum::VERY_STRONG())->toBe(5); +}); + +it('throws exception when calling non-existent case as static method', function () { + DifficultyEnum::NON_EXISTENT(); +})->throws( + \Lazerg\LaravelEnumPro\Exceptions\UndefinedCaseException::class, + 'Case with name NON_EXISTENT does not exist' +); + +it('can get enum value by invoking the enum instance', function () { + $enum = DifficultyEnum::MEDIUM; + + expect($enum())->toBe(3); +}); diff --git a/tests/EnumTest.php b/tests/EnumTest.php deleted file mode 100644 index f8f36b5..0000000 --- a/tests/EnumTest.php +++ /dev/null @@ -1,21 +0,0 @@ -toBeInstanceOf(\Illuminate\Support\Collection::class); -}); +use Tests\DifficultyEnum; -test('Get values of enum as string', function () { - expect(LevelTypes::valuesToString()) - ->toBe('1,2,3,4,5'); +it('can get all enum values as a collection', function () { + expect(DifficultyEnum::values()) + ->toBeInstanceOf(\Illuminate\Support\Collection::class); }); -test('Get values of enum as array', function () { - expect(LevelTypes::valuesToArray()) +it('can get all enum values as an array', function () { + expect(DifficultyEnum::valuesToArray()) ->toBe([1, 2, 3, 4, 5]); }); -test('Get value of enum', function () { - expect(LevelTypes::valueOf('VERY_EASY')) - ->toBe(1); - - expect(LevelTypes::valueOf('medium')) - ->toBe(3); - - expect(LevelTypes::valueOf('Very strong')) - ->toBe(5); +it('can get all enum values as a comma-separated string', function () { + expect(DifficultyEnum::valuesToString()) + ->toBe('1,2,3,4,5'); +}); - expect(LevelTypes::valueOf('Not found')) - ->toBeNull(); -}); \ No newline at end of file +it('can get enum value by its name with case-insensitive lookup', function () { + expect(DifficultyEnum::valueOf('VERY_EASY'))->toBe(1) + ->and(DifficultyEnum::valueOf('medium'))->toBe(3) + ->and(DifficultyEnum::valueOf('Very strong'))->toBe(5) + ->and(DifficultyEnum::valueOf('Not found'))->toBeNull(); +});