├── docs └── screenshot.png ├── LICENSE.md ├── src ├── FlaggedEnum.php ├── Enum.php ├── EnumFilter.php └── EnumBooleanFilter.php ├── CHANGELOG.md ├── composer.json └── README.md /docs/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simplesquid/nova-enum-field/HEAD/docs/screenshot.png -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Simple Squid (Pty) Ltd 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/FlaggedEnum.php: -------------------------------------------------------------------------------- 1 | resolveUsing( 16 | function ($value) use ($class) { 17 | if (! $value instanceof \BenSampo\Enum\FlaggedEnum) { 18 | return $value; 19 | } 20 | 21 | return collect($value->getValues())->mapWithKeys(function ($flag) use ($value) { 22 | return [$flag => $value->hasFlag($flag)]; 23 | })->except($class::None)->all(); 24 | } 25 | ); 26 | 27 | $this->fillUsing( 28 | function (NovaRequest $request, $model, $attribute, $requestAttribute) use ($class) { 29 | if ($request->exists($requestAttribute)) { 30 | $value = json_decode($request[$requestAttribute], true); 31 | 32 | $model->{$attribute} = $class::flags(array_keys(array_filter($value))); 33 | } 34 | } 35 | ); 36 | 37 | return $this->options(Arr::except($class::asSelectArray(), $class::None)); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Enum.php: -------------------------------------------------------------------------------- 1 | resolveUsing( 16 | function ($value) { 17 | return $value instanceof \BenSampo\Enum\Enum ? $value->value : $value; 18 | } 19 | ); 20 | 21 | $this->displayUsing( 22 | function ($value) { 23 | return $value instanceof \BenSampo\Enum\Enum ? $value->description : $value; 24 | } 25 | ); 26 | 27 | $this->fillUsing( 28 | function (NovaRequest $request, $model, $attribute, $requestAttribute) { 29 | if ($request->exists($requestAttribute)) { 30 | $model->{$attribute} = $request[$requestAttribute]; 31 | } 32 | } 33 | ); 34 | } 35 | 36 | public function attach($class) 37 | { 38 | return $this->options($class::asSelectArray()) 39 | ->rules($this->nullable ? 'nullable' : 'required', new EnumValue($class, false)); 40 | } 41 | 42 | public function nullable($nullable = true, $values = null) 43 | { 44 | $this->rules = str_replace('required', 'nullable', $this->rules); 45 | 46 | return parent::nullable($nullable, $values); 47 | } 48 | 49 | /** 50 | * @deprecated deprecated since version 2.3 51 | */ 52 | public function attachEnum($class) 53 | { 54 | return $this->attach($class); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/EnumFilter.php: -------------------------------------------------------------------------------- 1 | column = $column; 25 | $this->class = $class; 26 | 27 | $this->flagged = is_subclass_of($this->class, \BenSampo\Enum\FlaggedEnum::class); 28 | } 29 | 30 | public function name($name = null) 31 | { 32 | if (is_null($name)) { 33 | return $this->name ?: Nova::humanize($this->column); 34 | } 35 | 36 | $this->name = $name; 37 | 38 | return $this; 39 | } 40 | 41 | public function apply(Request $request, $query, $value) 42 | { 43 | if ($this->flagged && $value != $this->class::None) { 44 | return $this->scopeHasFlag($query, $this->column, $value); 45 | } 46 | 47 | return $query->where($this->column, $value); 48 | } 49 | 50 | public function key() 51 | { 52 | return 'enum_filter_'.$this->column; 53 | } 54 | 55 | public function options(Request $request) 56 | { 57 | return array_flip($this->class::asSelectArray()); 58 | } 59 | 60 | public function default() 61 | { 62 | if (isset(func_get_args()[0])) { 63 | $this->default = is_subclass_of(func_get_args()[0], \BenSampo\Enum\Enum::class) ? func_get_args()[0]->value : func_get_args()[0]; 64 | 65 | return $this; 66 | } 67 | 68 | if (is_null($this->default)) { 69 | return parent::default(); 70 | } 71 | 72 | return $this->default; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `nova-enum-field` will be documented in this file. 4 | 5 | ## 3.0.1 - 2022-11-29 6 | - Laravel Nova v4 is now required 7 | 8 | ## 3.0.0 - 2022-11-29 9 | - Add support for BenSampo/laravel-enum v6 10 | - Laravel v9 is now required 11 | - PHP 8.0 or higher is now required 12 | - BenSampo/laravel-enum v5 or higher is now required 13 | 14 | ## 2.7.0 - 2022-04-27 15 | - Support Laravel Nova v4 16 | 17 | ## 2.6.0 - 2022-02-22 18 | - Support Laravel v9 19 | - Support BenSampo/laravel-enum v5 20 | 21 | ## 2.5.0 - 2021-12-20 22 | - Upgrade to v4 of BenSampo/laravel-enum 23 | 24 | ## 2.4.0 - 2021-10-24 25 | - Allow nullable Enum fields. 26 | - Fix filter issue when multiple enum filters are used. 27 | - Fix and improve GitHub actions. 28 | 29 | ## 2.3.1 - 2021-04-06 30 | - Add ability to specify default value/s for `EnumFilter` and `EnumBooleanFilter`. 31 | 32 | ## 2.3.0 - 2021-01-25 33 | 34 | - Drop support for Laravel `7.x` 35 | - Drop support for `laravel-enum < 3.1`. 36 | - Add a customisable select filter. 37 | - Add a customisable boolean filter. 38 | - Add a flagged enum field. 39 | - Refactor and simplify tests. 40 | 41 | ## 2.2.0 - 2020-09-25 42 | 43 | - Add support for Laravel `8.x`. 44 | - Add support for PHP `8.0`. 45 | - Allow editing enums without casts. 46 | 47 | ## 2.1.0 - 2020-09-01 48 | 49 | - Add support for `laravel-enum 2.2.0`. 50 | 51 | ## 2.0.0 - 2020-07-08 52 | 53 | - Add support for `laravel-enum 2.x`. 54 | - Drop support for Laravel `< 7.x`. 55 | 56 | ## 1.1.0 - 2019-09-30 57 | 58 | - Update from package template. 59 | - Refactor and remove unnecessary code. 60 | - Add tests. 61 | 62 | ## 1.0.4 - 2019-09-27 63 | 64 | - Add documentation. 65 | - Refactor `Enum` field code. 66 | 67 | ## 1.0.3 - 2019-09-27 68 | 69 | - Cleanup codebase. 70 | - Fix casting. 71 | 72 | ## 1.0.2 - 2019-09-07 73 | 74 | - Fix version number. 75 | 76 | ## 1.0.1 - 2019-09-07 77 | 78 | - Push to packagist. 79 | 80 | ## 1.0.0 - 2019-09-07 81 | 82 | - Initial release. 83 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simplesquid/nova-enum-field", 3 | "description": "A Laravel Nova field to add enums to resources.", 4 | "license": "MIT", 5 | "keywords": [ 6 | "simplesquid", 7 | "laravel", 8 | "nova", 9 | "field", 10 | "enum", 11 | "nova-enum-field" 12 | ], 13 | "authors": [ 14 | { 15 | "name": "Matthew Poulter", 16 | "email": "matthew.poulter@simplesquid.co.za", 17 | "homepage": "https://simplesquid.co.za/", 18 | "role": "Developer" 19 | } 20 | ], 21 | "homepage": "https://github.com/simplesquid/nova-enum-field", 22 | "require": { 23 | "php": "^8.2", 24 | "bensampo/laravel-enum": "^5.0 || ^6.0", 25 | "illuminate/support": "^11.0 || ^12.0", 26 | "laravel/nova": "^4.0 || ^5.0" 27 | }, 28 | "require-dev": { 29 | "ergebnis/composer-normalize": "^2.0", 30 | "laravel/pint": "^1.13", 31 | "mockery/mockery": "^1.6", 32 | "nunomaduro/collision": "^8.6", 33 | "orchestra/testbench": "^9.0 || ^10.0", 34 | "phpunit/phpunit": "^11.5.3", 35 | "quotevelocity/novaunit": "^4.0 || ^5.0", 36 | "symfony/var-dumper": "^7.0" 37 | }, 38 | "repositories": [ 39 | { 40 | "type": "composer", 41 | "url": "https://nova.laravel.com" 42 | } 43 | ], 44 | "minimum-stability": "stable", 45 | "autoload": { 46 | "psr-4": { 47 | "SimpleSquid\\Nova\\Fields\\Enum\\": "src" 48 | } 49 | }, 50 | "autoload-dev": { 51 | "psr-4": { 52 | "SimpleSquid\\Nova\\Fields\\Enum\\Tests\\": "tests" 53 | } 54 | }, 55 | "config": { 56 | "allow-plugins": { 57 | "ergebnis/composer-normalize": true 58 | }, 59 | "sort-packages": true 60 | }, 61 | "extra": { 62 | "laravel": { 63 | "providers": [] 64 | } 65 | }, 66 | "scripts": { 67 | "test": "vendor/bin/phpunit --colors=always" 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/EnumBooleanFilter.php: -------------------------------------------------------------------------------- 1 | column = $column; 28 | $this->class = $class; 29 | 30 | $this->flagged = is_subclass_of($this->class, \BenSampo\Enum\FlaggedEnum::class); 31 | } 32 | 33 | public function filterAnyFlags() 34 | { 35 | $this->scope = 'any'; 36 | 37 | return $this; 38 | } 39 | 40 | public function filterAllFlags() 41 | { 42 | $this->scope = 'all'; 43 | 44 | return $this; 45 | } 46 | 47 | public function name($name = null) 48 | { 49 | if (is_null($name)) { 50 | return $this->name ?: Nova::humanize($this->column); 51 | } 52 | 53 | $this->name = $name; 54 | 55 | return $this; 56 | } 57 | 58 | public function apply(Request $request, $query, $value) 59 | { 60 | $enums = array_keys(array_filter($value)); 61 | 62 | if (empty($enums)) { 63 | return $query; 64 | } 65 | 66 | if ($this->flagged && $this->scope === 'all') { 67 | return $this->scopeHasAllFlags($query, $this->column, $enums); 68 | } 69 | 70 | return $query->where( 71 | function ($query) use ($enums) { 72 | if ($this->flagged) { 73 | $query = $this->scopeHasAnyFlags($query, $this->column, $enums); 74 | 75 | $enums = in_array($this->class::None, $enums) ? [$this->class::None] : []; 76 | } else { 77 | $query->where($this->column, array_shift($enums)); 78 | } 79 | 80 | foreach ($enums as $enum) { 81 | $query->orWhere($this->column, $enum); 82 | } 83 | } 84 | ); 85 | } 86 | 87 | public function key() 88 | { 89 | return 'enum_boolean_filter_'.$this->column; 90 | } 91 | 92 | public function options(Request $request) 93 | { 94 | if ($this->flagged && $this->scope === 'all') { 95 | return array_flip(Arr::except($this->class::asSelectArray(), $this->class::None)); 96 | } 97 | 98 | return array_flip($this->class::asSelectArray()); 99 | } 100 | 101 | public function default() 102 | { 103 | if (isset(func_get_args()[0])) { 104 | $this->default = collect(is_array(func_get_args()[0]) ? func_get_args()[0] : [func_get_args()[0]]) 105 | ->map(function ($value, $key) { 106 | return is_subclass_of($value, \BenSampo\Enum\Enum::class) ? $value->value : $value; 107 | })->all(); 108 | 109 | return $this; 110 | } 111 | 112 | if (is_null($this->default)) { 113 | return parent::default(); 114 | } 115 | 116 | return collect($this->default)->mapWithKeys(function ($option) { 117 | return [$option => true]; 118 | })->all() + parent::default(); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # An enum field for Laravel Nova 2 | 3 | [![Latest Version on Packagist](https://img.shields.io/packagist/v/simplesquid/nova-enum-field.svg?style=flat-square)](https://packagist.org/packages/simplesquid/nova-enum-field) 4 | [![Tests](https://github.com/simplesquid/nova-enum-field/actions/workflows/run-tests.yml/badge.svg)](https://github.com/simplesquid/nova-enum-field/actions/workflows/run-tests.yml) 5 | [![Code styling](https://github.com/simplesquid/nova-enum-field/actions/workflows/code-style.yml/badge.svg)](https://github.com/simplesquid/nova-enum-field/actions/workflows/code-style.yml) 6 | [![MIT License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md) 7 | [![Total Downloads](https://img.shields.io/packagist/dt/simplesquid/nova-enum-field.svg?style=flat-square)](https://packagist.org/packages/simplesquid/nova-enum-field) 8 | 9 | Laravel Nova field to add enums to resources. This field uses the [BenSampo/laravel-enum](https://github.com/BenSampo/laravel-enum) package, so make sure to check out the installation instructions there first. 10 | 11 | ![Screenshot of the enum field](https://github.com/simplesquid/nova-enum-field/raw/main/docs/screenshot.png) 12 | 13 | ## Installation 14 | 15 | You can install this package in a Laravel app that uses [Nova](https://nova.laravel.com) via composer: 16 | 17 | ```bash 18 | composer require simplesquid/nova-enum-field 19 | ``` 20 | 21 | ## Setup 22 | 23 | It is strongly recommended that you use Attribute Casting in your models. From the docs at [BenSampo/laravel-enum](https://github.com/BenSampo/laravel-enum#attribute-casting), this can be done like this: 24 | 25 | ```php 26 | use App\Enums\UserType; 27 | use Illuminate\Database\Eloquent\Model; 28 | 29 | class Example extends Model 30 | { 31 | protected $casts = [ 32 | 'user_type' => UserType::class, 33 | ]; 34 | } 35 | ``` 36 | 37 | ## Usage 38 | 39 | You can use the `Enum` field in your Nova resource like this: 40 | 41 | ```php 42 | namespace App\Nova; 43 | 44 | use App\Enums\UserType; 45 | use SimpleSquid\Nova\Fields\Enum\Enum; 46 | 47 | class Example extends Resource 48 | { 49 | // ... 50 | 51 | public function fields(Request $request) 52 | { 53 | return [ 54 | // ... 55 | 56 | Enum::make('User Type')->attach(UserType::class), 57 | 58 | // ... 59 | ]; 60 | } 61 | } 62 | ``` 63 | 64 | ### Flagged Enums 65 | 66 | You can use the `FlaggedEnum` field in your Nova resource like this (see [Flagged/Bitwise Enum](https://github.com/BenSampo/laravel-enum#flaggedbitwise-enum) setup): 67 | 68 | ```php 69 | namespace App\Nova; 70 | 71 | use App\Enums\UserPermissions; 72 | use SimpleSquid\Nova\Fields\Enum\FlaggedEnum; 73 | 74 | class Example extends Resource 75 | { 76 | // ... 77 | 78 | public function fields(Request $request) 79 | { 80 | return [ 81 | // ... 82 | 83 | FlaggedEnum::make('User Permissions')->attach(UserPermissions::class), 84 | 85 | // ... 86 | ]; 87 | } 88 | } 89 | ``` 90 | 91 | ### Filters 92 | 93 | If you would like to use the provided Nova Select filter (which is compatible with both the `Enum` and `FlaggedEnum` fields), you can include it like this: 94 | 95 | ```php 96 | namespace App\Nova; 97 | 98 | use App\Enums\UserPermissions; 99 | use App\Enums\UserType; 100 | use SimpleSquid\Nova\Fields\Enum\EnumFilter; 101 | 102 | class Example extends Resource 103 | { 104 | // ... 105 | 106 | public function filters(Request $request) 107 | { 108 | return [ 109 | new EnumFilter('user_type', UserType::class), 110 | 111 | new EnumFilter('user_permissions', UserPermissions::class), 112 | 113 | // With optional filter name: 114 | (new EnumFilter('user_type', UserType::class)) 115 | ->name('Type of user'), 116 | 117 | // With optional default value: 118 | (new EnumFilter('user_type', UserType::class)) 119 | ->default(UserType::Administrator), 120 | ]; 121 | } 122 | } 123 | ``` 124 | 125 | Alternatively, you may wish to use the provided Nova Boolean filter (which is also compatible with both the `Enum` and `FlaggedEnum` fields): 126 | 127 | ```php 128 | namespace App\Nova; 129 | 130 | use App\Enums\UserPermissions; 131 | use App\Enums\UserType; 132 | use SimpleSquid\Nova\Fields\Enum\EnumBooleanFilter; 133 | 134 | class Example extends Resource 135 | { 136 | // ... 137 | 138 | public function filters(Request $request) 139 | { 140 | return [ 141 | new EnumBooleanFilter('user_type', UserType::class), 142 | 143 | new EnumBooleanFilter('user_permissions', UserPermissions::class), 144 | 145 | // With optional filter name: 146 | (new EnumBooleanFilter('user_type', UserType::class)) 147 | ->name('Type of user'), 148 | 149 | // With optional default values: 150 | (new EnumBooleanFilter('user_type', UserType::class)) 151 | ->default([ 152 | UserType::Administrator, 153 | UserType::Moderator, 154 | ]), 155 | 156 | // When filtering a FlaggedEnum, it will default to filtering 157 | // by ANY flags, however you may wish to filter by ALL flags: 158 | (new EnumBooleanFilter('user_permissions', UserPermissions::class)) 159 | ->filterAllFlags(), 160 | ]; 161 | } 162 | } 163 | ``` 164 | 165 | ## Testing 166 | 167 | ``` bash 168 | composer test 169 | ``` 170 | 171 | ## Changelog 172 | 173 | Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently. 174 | 175 | ## Contributing 176 | 177 | Please see [CONTRIBUTING](.github/CONTRIBUTING.md) for details. 178 | 179 | ## Security Vulnerabilities 180 | 181 | Please review [our security policy](../../security/policy) on how to report security vulnerabilities. 182 | 183 | ## Credits 184 | 185 | - [Matthew Poulter](https://github.com/mdpoulter) 186 | - [Ben Sampson](https://github.com/BenSampo) 187 | - [atymic](https://github.com/atymic) 188 | - [Robin D'Arcy](https://github.com/rdarcy1) 189 | - [Antoni Siek](https://github.com/ImJustToNy) 190 | - [All Contributors](../../contributors) 191 | 192 | Package skeleton based on [spatie/skeleton-php](https://github.com/spatie/skeleton-php). 193 | 194 | ## About us 195 | 196 | SimpleSquid is a small web development and design company based in Valkenburg, Netherlands. 197 | 198 | ## License 199 | 200 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 201 | --------------------------------------------------------------------------------