Skip to content

Commit 0631c70

Browse files
authored
Add Rector rules for conversion of classes that extend BenSampo\Enum\Enum to native PHP enums
1 parent 0e48455 commit 0631c70

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+2205
-56
lines changed

.github/workflows/continuous-integration.yml

+3-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ jobs:
3232
with:
3333
dependency-versions: ${{ matrix.dependency-versions }}
3434

35-
- run: vendor/bin/phpunit
35+
- run: vendor/bin/phpunit --testsuite=Tests
36+
37+
- run: vendor/bin/phpunit --testsuite=Rector
3638

3739
static-analysis:
3840
runs-on: ubuntu-latest

.php-cs-fixer.php

+2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
->in(__DIR__)
77
->name('*.php')
88
->notPath('vendor')
9+
->notPath('tests/Enums/Annotate') // Generated
910
->notPath('tests/Enums/AnnotateFixtures') // Matches laminas/laminas-code
11+
->notPath('tests/Enums/ToNative') // Generated
1012
->notPath('tests/Enums/ToNativeFixtures') // Matches laminas/laminas-code
1113
->ignoreDotFiles(false)
1214
->ignoreVCS(true);

CHANGELOG.md

+10
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## Unreleased
99

10+
## 6.5.0
11+
12+
### Added
13+
14+
- Add Rector rules for conversion of classes that extend `BenSampo\Enum\Enum` to native PHP enums
15+
16+
### Deprecated
17+
18+
- Deprecate command `enum:to-native` in favor of Rector conversion
19+
1020
## 6.4.1
1121

1222
### Fixed

CONTRIBUTING.md

+5-6
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Hey, thank you for contributing. Here are some tips to make it easy for you.
1010
1. Think about how the changes you are about to make can be tested, write tests before coding
1111
1. Run tests, make sure they fail
1212
1. Write the actual code to make the tests pass
13-
1. Run checks with `composer all`
13+
1. Run checks with `make`
1414
1. Open a pull request detailing your changes. Make sure to follow the [template](.github/PULL_REQUEST_TEMPLATE.md)
1515

1616
## Testing
@@ -28,7 +28,7 @@ failing test.
2828
Run the testsuite:
2929

3030
```sh
31-
composer test
31+
make test
3232
```
3333

3434
## Codestyle
@@ -37,17 +37,16 @@ Formatting is automated through [php-cs-fixer](https://github.com/friendsofphp/p
3737

3838
Apply automated fixes:
3939

40-
```bash
41-
composer fix
40+
```sh
41+
make fix
4242
```
4343

44-
4544
## Static Analysis
4645

4746
We use [PHPStan](https://phpstan.org) for static analysis.
4847

4948
Run static analysis:
5049

5150
```sh
52-
composer stan
51+
make stan
5352
```

Makefile

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
.PHONY: it
2+
it: fix stan test docs ## Run the commonly used targets
3+
4+
.PHONY: help
5+
help: ## Displays this list of targets with descriptions
6+
@grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(firstword $(MAKEFILE_LIST)) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[32m%-30s\033[0m %s\n", $$1, $$2}'
7+
8+
.PHONY: fix
9+
fix: vendor ## Apply automatic code fixes
10+
vendor/bin/php-cs-fixer fix
11+
12+
.PHONY: stan
13+
stan: vendor ## Runs a static analysis with phpstan
14+
vendor/bin/phpstan
15+
16+
.PHONY: test
17+
test: vendor ## Runs tests with phpunit
18+
vendor/bin/phpunit --testsuite=Tests
19+
vendor/bin/phpunit --testsuite=Rector
20+
21+
docs: ## Generate documentation
22+
vendor/bin/rule-doc-generator generate src/Rector --output-file=rector-rules.md
23+
24+
vendor: composer.json
25+
composer validate --strict
26+
composer install
27+
composer normalize

README.md

+40-18
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,10 @@ Created by [Ben Sampson](https://sampo.co.uk)
2626

2727
- [Guide](#guide)
2828
- [Installation](#installation)
29+
- [Migrate to Native PHP Enums](#migrate-to-native-PHP-enums)
2930
- [Enum Library](enum-library.md)
3031
- [Basic Usage](#basic-usage)
31-
- [Enum definition](#enum-definition)
32+
- [Enum Definition](#enum-definition)
3233
- [Instantiation](#instantiation)
3334
- [Instance Properties](#instance-properties)
3435
- [Instance Equality](#instance-equality)
@@ -38,7 +39,9 @@ Created by [Ben Sampson](https://sampo.co.uk)
3839
- [Migrations](#migrations)
3940
- [Validation](#validation)
4041
- [Localization](#localization)
41-
- [Customizing descriptions](#customizing-descriptions)
42+
- [Customizing Descriptions](#customizing-descriptions)
43+
- [Customizing Class Description](#customizing-class-description)
44+
- [Customizing Value Descriptions](#customizing-value-descriptions)
4245
- [Extending the Enum Base Class](#extending-the-enum-base-class)
4346
- [Laravel Nova Integration](#laravel-nova-integration)
4447
- [PHPStan Integration](#phpstan-integration)
@@ -54,25 +57,42 @@ You are reading the documentation for `6.x`.
5457
- If you're using **Laravel 7** please see the [docs for `2.x`](https://github.com/BenSampo/laravel-enum/blob/v2.2.0/README.md).
5558
- If you're using **Laravel 6** or below, please see the [docs for `1.x`](https://github.com/BenSampo/laravel-enum/blob/v1.38.0/README.md).
5659

57-
Please see the [upgrade guide](./UPGRADE.md) for information on how to upgrade to the latest version.
60+
Please see the [upgrade guide](UPGRADE.md) for information on how to upgrade to the latest version.
5861

5962
## Guide
6063

6164
I wrote a blog post about using laravel-enum: https://sampo.co.uk/blog/using-enums-in-laravel
6265

6366
## Installation
6467

65-
### Requirements
68+
Requires PHP 8, and Laravel 9 or 10.
6669

67-
- Laravel `9` or higher
68-
- PHP `8.0` or higher
69-
70-
Via Composer
71-
72-
```bash
70+
```sh
7371
composer require bensampo/laravel-enum
7472
```
7573

74+
## Migrate to Native PHP Enums
75+
76+
PHP 8.1 supports enums natively.
77+
You can migrate your usages of `BenSampo\Enum\Enum` to native PHP enums using the following steps.
78+
79+
For large projects, it is recommended to migrate one enum at a time.
80+
Conversion of enums and their usages can not be done in a single run of rector,
81+
that would leave the project partially converted.
82+
Usages seen after the enum classes have been converted will no longer be transformed.
83+
84+
1. Configure the enum class you want to convert in [`ToNativeUsagesRector`](rector-rules.md#tonativeusagesrector)
85+
and run `vendor/bin/rector process --clear-cache` once.
86+
Running repeatedly messes up the conversion.
87+
1. Switch the rector to [`ToNativeImplementationRector`](rector-rules.md#tonativeimplementationrector)
88+
and run `vendor/bin/rector process --clear-cache` once again.
89+
If you have just one or a few classes, you may pass their paths to speed this up.
90+
1. Review and validate the code changes for missed edge cases
91+
- See [Unimplemented](tests/Rector/Unimplemented)
92+
- `Enum::coerce()`: If only values were passed, you can replace it with `tryFrom()`.
93+
If keys or instances could also be passed, you might need additional logic to cover this.
94+
- `Enum::getDescription()`: Implement an alternative.
95+
7696
## Enum Library
7797

7898
Browse and download from a list of commonly used, community contributed enums.
@@ -144,15 +164,15 @@ $enumInstance = UserType::coerce($someValue);
144164
If you want your IDE to autocomplete the static instantiation helpers, you can
145165
generate PHPDoc annotations through an artisan command.
146166

147-
By default all Enums in `app/Enums` will be annotated (you can change the folder by passing a path to `--folder`)
167+
By default, all Enums in `app/Enums` will be annotated (you can change the folder by passing a path to `--folder`).
148168

149-
```bash
169+
```sh
150170
php artisan enum:annotate
151171
```
152172

153-
You can annotate a single class by specifying the class name
173+
You can annotate a single class by specifying the class name.
154174

155-
```bash
175+
```sh
156176
php artisan enum:annotate "App\Enums\UserType"
157177
```
158178

@@ -768,7 +788,9 @@ final class UserType extends Enum implements LocalizedEnum
768788

769789
The `getDescription` method will now look for the value in your localization files. If a value doesn't exist for a given key, the default description is returned instead.
770790

771-
## Customizing enum class description
791+
## Customizing descriptions
792+
793+
### Customizing class description
772794

773795
If you'd like to return a custom description for your enum class, add a `Description` attribute to your Enum class:
774796

@@ -787,7 +809,7 @@ Calling `UserType::getClassDescription()` now returns `List of available User ty
787809

788810
You may also override the `getClassDescription` method on the base Enum class if you wish to have more control of the description.
789811

790-
## Customizing value descriptions
812+
### Customizing value descriptions
791813

792814
If you'd like to return a custom description for your enum values, add a `Description` attribute to your Enum constants:
793815

@@ -828,7 +850,7 @@ It's best to register the macro inside a service providers' boot method.
828850

829851
Use the [nova-enum-field](https://github.com/simplesquid/nova-enum-field) package by Simple Squid to easily create fields for your Enums in Nova. See their readme for usage.
830852

831-
## PHPStan integration
853+
## PHPStan Integration
832854

833855
If you are using [PHPStan](https://github.com/phpstan/phpstan) for static
834856
analysis, you can enable the extension for proper recognition of the
@@ -855,7 +877,7 @@ Generate DocBlock annotations for enum classes.
855877

856878
### `php artisan enum:to-native`
857879

858-
Convert a class that extends `BenSampo\Enum\Enum` to a native PHP enum.
880+
Deprecated, see [migrate to native PHP enums](#migrate-to-native-php-enums).
859881

860882
## Enum Class Reference
861883

composer.json

+5-12
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,14 @@
3636
"ergebnis/composer-normalize": "^2.28.3",
3737
"mll-lab/php-cs-fixer-config": "^5.4",
3838
"mockery/mockery": "^1.5",
39-
"nunomaduro/larastan": "^2.1.12",
39+
"nunomaduro/larastan": "^2.6.3",
4040
"orchestra/testbench": "^7.6.1 || ^8",
4141
"phpstan/phpstan": "^1.8.2",
4242
"phpstan/phpstan-mockery": "^1.1",
4343
"phpstan/phpstan-phpunit": "^1.1.1",
44-
"phpunit/phpunit": "^9.5.21"
44+
"phpunit/phpunit": "^9.5.21 || ^10",
45+
"rector/rector": "^0.17.6",
46+
"symplify/rule-doc-generator": "^11"
4547
},
4648
"minimum-stability": "dev",
4749
"prefer-stable": true,
@@ -76,15 +78,6 @@
7678
"scripts": {
7779
"post-autoload-dump": [
7880
"@php vendor/bin/testbench package:discover"
79-
],
80-
"all": [
81-
"composer normalize",
82-
"@fix",
83-
"@test",
84-
"@stan"
85-
],
86-
"fix": "php-cs-fixer fix",
87-
"stan": "phpstan",
88-
"test": "phpunit"
81+
]
8982
}
9083
}

phpunit.xml

+17-18
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,20 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<phpunit backupGlobals="false"
3-
backupStaticAttributes="false"
2+
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
44
bootstrap="vendor/autoload.php"
5-
colors="true"
6-
convertErrorsToExceptions="true"
7-
convertNoticesToExceptions="true"
8-
convertWarningsToExceptions="true"
9-
processIsolation="false"
10-
stopOnFailure="false"
11-
>
12-
<testsuites>
13-
<testsuite name="Laravel Enum Test Suite">
14-
<directory suffix="Test.php">./tests/</directory>
15-
</testsuite>
16-
</testsuites>
17-
<php>
18-
<env name="DB_CONNECTION" value="sqlite"/>
19-
<env name="DB_DATABASE" value=":memory:"/>
20-
</php>
5+
colors="true">
6+
<testsuites>
7+
<!-- We have to separate those testsuites due to a conflict when requiring PhpParser, see https://github.com/rectorphp/rector/issues/6709 -->
8+
<testsuite name="Tests">
9+
<directory>tests</directory>
10+
<exclude>tests/Rector</exclude>
11+
</testsuite>
12+
<testsuite name="Rector">
13+
<directory>tests/Rector</directory>
14+
</testsuite>
15+
</testsuites>
16+
<php>
17+
<env name="DB_CONNECTION" value="sqlite"/>
18+
<env name="DB_DATABASE" value=":memory:"/>
19+
</php>
2120
</phpunit>

rector-rules.md

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# 2 Rules Overview
2+
3+
## ToNativeImplementationRector
4+
5+
Convert usages of `BenSampo\Enum\Enum` to native PHP enums
6+
7+
:wrench: **configure it!**
8+
9+
- class: [`BenSampo\Enum\Rector\ToNativeImplementationRector`](src/Rector/ToNativeImplementationRector.php)
10+
11+
```php
12+
<?php
13+
14+
declare(strict_types=1);
15+
16+
use BenSampo\Enum\Rector\ToNativeImplementationRector;
17+
use BenSampo\Enum\Tests\Enums\UserType;
18+
use Rector\Config\RectorConfig;
19+
20+
return static function (RectorConfig $rectorConfig): void {
21+
$rectorConfig->ruleWithConfiguration(ToNativeImplementationRector::class, [
22+
UserType::class,
23+
]);
24+
};
25+
```
26+
27+
28+
29+
```diff
30+
-/**
31+
- * @method static static ADMIN()
32+
- * @method static static MEMBER()
33+
- *
34+
- * @extends Enum<int>
35+
- */
36+
-class UserType extends Enum
37+
+enum UserType : int
38+
{
39+
- const ADMIN = 1;
40+
- const MEMBER = 2;
41+
+ case ADMIN = 1;
42+
+ case MEMBER = 2;
43+
}
44+
```
45+
46+
<br>
47+
48+
## ToNativeUsagesRector
49+
50+
Convert usages of `BenSampo\Enum\Enum` to native PHP enums
51+
52+
:wrench: **configure it!**
53+
54+
- class: [`BenSampo\Enum\Rector\ToNativeUsagesRector`](src/Rector/ToNativeUsagesRector.php)
55+
56+
```php
57+
<?php
58+
59+
declare(strict_types=1);
60+
61+
use BenSampo\Enum\Rector\ToNativeUsagesRector;
62+
use BenSampo\Enum\Tests\Enums\UserType;
63+
use Rector\Config\RectorConfig;
64+
65+
return static function (RectorConfig $rectorConfig): void {
66+
$rectorConfig->ruleWithConfiguration(ToNativeUsagesRector::class, [
67+
UserType::class,
68+
]);
69+
};
70+
```
71+
72+
73+
74+
```diff
75+
-$user = UserType::ADMIN();
76+
-$user->is(UserType::ADMIN);
77+
+$user = UserType::ADMIN;
78+
+$user === UserType::ADMIN;
79+
```
80+
81+
<br>

0 commit comments

Comments
 (0)