Commit 3f0d7920 authored by Jan Kuchař's avatar Jan Kuchař

Merge branch 'docs-update' into 'master'

Docs update

See merge request !11
parents dbfe027d 0ec336a8
Pipeline #14392 passed with stages
in 40 seconds
# grifart/enum
repositories: [GRIFART GitLab](https://gitlab.grifart.cz/jkuchar1/grifart-enum), [GitHub](https://github.com/grifart/enum)
Enumeration value object. Enumerate values and behaviour with type-safety.
Repositories [gitlab.grifart.cz](https://gitlab.grifart.cz/jkuchar1/grifart-enum)
and [github.com](https://github.com/grifart/enum).
[![pipeline status](https://gitlab.grifart.cz/jkuchar1/grifart-enum/badges/master/pipeline.svg)](https://gitlab.grifart.cz/jkuchar1/grifart-enum/commits/master)
Sponsored by [grifart.com](https://grifart.com).
## Introduction
Enums represent predefined set of values. The available values are defined statically by each enum class. Each value is represented by an instance of this class in a flyweight manner.
- This enum allows you to add individal behaviour to every enum value (as in Java). This allows you to transform your `switch`es/`if`s into more readable composition. (see example bellow)
- Checks enum annotations if phpdoc-declared methods are properly declared (will generate docblock for you in exception)
- This enum allows you to add individual behaviour for every enum value (as in Java). This allows you to transform your `switch`es/`if`s into more readable composition. (see example bellow)
- Checks enum annotations if phpdoc-declared methods are properly declared (will generate docblock for you when not specified or incorrect)
- `===`, `==` and usage of `switch`es is supported
- string or integer scalar keys are supported
- Easily access scalar value of enum `DayOfWeek::MONDAY()->toScalar()` or `(string) DayOfWeek::MONDAY()`
Common with other enum implementations:
Also includes:
- You can type-hint: `function setCurrentDay(DayOfWeek $day) {`
- You can get a list of all the possible values
- It is type safe. By annotating your enumeration type, you are guaranteed that there will be no other values then you declared. `function translateTo(DayOfWeek $day) { ...`
- You can get a list of all the possible values `Enum::getAvailableValues()`
## Installation
......@@ -21,7 +32,64 @@ composer require grifart/enum
This library uses [**semantic versioning 2.0**](https://semver.org/spec/v2.0.0.html).
You can safely use `^` constrain in you `composer.json`.
## Let code speak: individual behaviour for each value
## Requirements
This library requires PHP 7.1 and later.
## Project status & release process
While this library is still under development, it is well tested and should be stable enough to use in production environments.
The current releases are numbered 0.x.y. When a non-breaking change is introduced (adding new methods, optimizing existing code, etc.), y is incremented.
When a breaking change is introduced, a new 0.x version cycle is always started.
It is therefore safe to lock your project to a given release cycle, such as 0.1.*.
If you need to upgrade to a newer release cycle, check the release history for a list of changes introduced by each further 0.x.0 version.
## Overview
### Static methods
- fromScalar() - returns enum instance (value) for given scalar
- getAvailableValues() - returns all values for given type
- provideInstances() - implement to return enum instances or automatically implemented by `Grifart\Enum\AutoInstances` trait.
### Instance methods
- toScalar() - return scalar value identifier
- equals() - returns true if the same enum value is passed
- scalarEquals() - returns true if passed scalar value is equal to current value
### Basic enumeration
```php
/**
* @method static DayOfWeek MONDAY()
* @method static DayOfWeek TUESDAY()
*/
final class DayOfWeek extends \Grifart\Enum\Enum
{
use Grifart\Enum\AutoInstances;
private const MONDAY = 'monday';
private const TUESDAY = 'tuesday';
// ...
public function process(self $value): void { /* ... */ }
}
$monday = DayOfWeek::MONDAY();
$monday->process(DayOfWeek::TUESDAY());
````
### Migrating from class constants
This guide show how to migrate from classes with constants to `\Grifart\Enum` in few simple steps. [Continue to example](tests/Example/MigratingLegacyCode/readme.md)
### Adding behaviour to values
Let's **refactor** following existing code:
......@@ -44,12 +112,14 @@ $monday = DayOfWeek::MONDAY();
function nextDay(DayOfWeek $dayOfWeek): DayOfWeek
{
if($dayOfWeek === DayOfWeek::MONDAY()) {
switch($dayOfWeek) {
case DayOfWeek::MONDAY():
return DayOfWeek::TUESDAY();
} else if (...) {
...
}
case DayOfWeek::TUESDAY():
// ...
}
throw new ShouldNotHappenException();
}
......@@ -73,12 +143,15 @@ final class DayOfWeek extends \Grifart\Enum\Enum
public function nextDay(): self
{
if($this === self::MONDAY()) {
switch($this) {
case self::MONDAY():
return self::TUESDAY();
} else if (...) {
...
}
case self::TUESDAY():
// ...
}
throw new ShouldNotHappenException();
}
......@@ -115,14 +188,14 @@ abstract class DayOfWeek extends \Grifart\Enum\Enum
protected const TUESDAY = 'tuesday';
// ...
public abstract function nextDay(): self;
abstract public function nextDay(): self;
/** @return static[] */
protected static function provideInstances(): array
{
return [
self::MONDAY => new class extends DayOfWeek
new class(self::MONDAY) extends DayOfWeek
{
public function nextDay(): DayOfWeek
{
......@@ -130,11 +203,11 @@ abstract class DayOfWeek extends \Grifart\Enum\Enum
}
},
self::TUESDAY => new class extends DayOfWeek
new class(self::TUESDAY) extends DayOfWeek
{
public function nextDay(): DayOfWeek
{
return return DayOfWeek::WEDNESDAY();
return DayOfWeek::WEDNESDAY();
}
},
];
......
# Migrating legacy code to `\Grifart\Enum`
This is step-by-step guide how to migrate you legacy code to `\Grifart\Enum`.
We will start with non-type safe enum represented by class with constants. [[full source code](step0.phpt)]
```php
class OrderState {
public const NEW = 'new';
public const PROCESSING = 'processing';
}
```
Our business logic is this:
```php
$result = '';
switch ($state) {
// your business logic
case OrderState::NEW:
$result = 'new';
break;
case OrderState::PROCESSING:
$result = 'processing';
break;
}
```
## Step 1: add new type-safe API [[source](step1.phpt)]
This is done by
- extending `\Grifart\Enum\Enum` class
- by automatically implementing enum values by including `use \Grifart\Enum\AutoInstances;` trait
- and by adding magic methods annotations
There is not backward incompatible change introduced. And now you can use new APIs!
```php
/**
* @method static OrderState NEW()
* @method static OrderState PROCESSING()
*/
class OrderState extends \Grifart\Enum\Enum {
use \Grifart\Enum\AutoInstances;
public const NEW = 'new';
public const PROCESSING = 'processing';
}
```
## Step 2: Migrating existing code to new API [[source](step2.phpt)]
Migrating old code to new API is usually easy, just add parenthesis `()` when you access value.
```php
$state = OrderState::NEW();
$result = '';
switch ($state) {
// your business logic
case OrderState::NEW():
$result = 'new';
break;
case OrderState::PROCESSING():
$result = 'processing';
break;
}
Assert::same('new', $result);
```
Please note, that you will need to handle some cases manually as `OrderState::NEW()` returns object, enum instance, not a string.
#### Removing old API
So when you are finally ready to remove old API, just change constant visibility to `private`.
```php
/**
* @method static OrderState NEW()
* @method static OrderState PROCESSING()
*/
class OrderState extends \Grifart\Enum\Enum {
use \Grifart\Enum\AutoInstances;
private const NEW = 'new';
private const PROCESSING = 'processing';
}
```
## Step 3: Enjoy new features [[source](step3.phpt)]
Now, when you decided that you what to move your business logic inside enum declaration. You are now free to do so. And there are many more options, see other examples.
<?php declare(strict_types=1);
namespace MigratingOldCode;
require __DIR__ . '/../../bootstrap.php';
use Tester\Assert;
class OrderState {
public const NEW = 'new';
public const PROCESSING = 'processing';
}
$state = OrderState::NEW;
$result = '';
switch ($state) {
// your business logic
case OrderState::NEW:
$result = 'new';
break;
case OrderState::PROCESSING:
$result = 'processing';
break;
}
Assert::same('new', $result);
<?php declare(strict_types=1);
namespace MigratingOldCode;
require __DIR__ . '/../../bootstrap.php';
use Tester\Assert;
/**
* @method static OrderState NEW()
* @method static OrderState PROCESSING()
*/
class OrderState extends \Grifart\Enum\Enum {
use \Grifart\Enum\AutoInstances;
public const NEW = 'new';
public const PROCESSING = 'processing';
}
// code bellow is untouched:
$state = OrderState::NEW;
$result = '';
switch ($state) {
// your business logic
case OrderState::NEW:
$result = 'new';
break;
case OrderState::PROCESSING:
$result = 'processing';
break;
}
Assert::same('new', $result);
<?php declare(strict_types=1);
namespace MigratingOldCode;
require __DIR__ . '/../../bootstrap.php';
use Tester\Assert;
/**
* @method static OrderState NEW()
* @method static OrderState PROCESSING()
*/
class OrderState extends \Grifart\Enum\Enum {
use \Grifart\Enum\AutoInstances;
private const NEW = 'new';
private const PROCESSING = 'processing';
}
$state = OrderState::NEW();
$result = '';
switch ($state) {
// your business logic
case OrderState::NEW():
$result = 'new';
break;
case OrderState::PROCESSING():
$result = 'processing';
break;
}
Assert::same('new', $result);
<?php declare(strict_types=1);
namespace MigratingOldCode;
require __DIR__ . '/../../bootstrap.php';
use Tester\Assert;
/**
* @method static OrderState NEW()
* @method static OrderState PROCESSING()
*/
class OrderState extends \Grifart\Enum\Enum {
use \Grifart\Enum\AutoInstances;
private const NEW = 'new';
private const PROCESSING = 'processing';
public function doBusinessLogic(): string
{
switch ($this) {
// your business logic
case self::NEW():
return 'new';
break;
case self::PROCESSING():
return 'processing';
break;
}
throw new \LogicException('should never happen');
}
}
$state = OrderState::NEW();
$result = $state->doBusinessLogic();
Assert::same('new', $result);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment