Skip to content

Commit

Permalink
added features to State and Comparison
Browse files Browse the repository at this point in the history
  • Loading branch information
henzeb committed Dec 14, 2022
1 parent fc3fcd8 commit 2b00ac5
Show file tree
Hide file tree
Showing 19 changed files with 695 additions and 46 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

All notable changes to `Enumhancer` will be documented in this file

## 1.18.0 - 2022-12-14

- Added Magic method functionality to [State](docs/state.md)
- Added `to` and `tryTo` methods to `State`
- Added `is`, `isNot`, `isIn` and `isNotIn`
to [Comparison](docs/comparison.md)

## 1.17.0 - 2022-12-13

- Added [Flip](docs/mappers.md#flip), allowing to use
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ You can also just use one of the features by using the specific trait for that
feature.

Note: all traits can be used next to each other, except for `Mappers`, which has
implemented the methods of `Makers`, `Extractor` and `Reporters`.
implemented the methods of `Getters`, `Extractor` and `Reporters`.

### Features

Expand Down
28 changes: 28 additions & 0 deletions docs/comparison.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ YourThirdEnum::ENUM->equals('enum', 'enum2'); //returns true
Next to `equals`, you can also handle assertions with `is` and `isNot`.

```php
YourEnum::Enum->is('enum'); // returns true
YourEnum::Enum->isNot('enum'); // returns false

YourEnum::Enum->is('enum2'); // returns false
YourEnum::Enum->isNot('enum2'); // returns true

/** magical methods */
YourEnum::ENUM->isEnum(); // returns true
YourEnum::ENUM->isNotEnum(); // returns false
YourEnum::ENUM->isEnum2(); // returns false
Expand All @@ -86,6 +93,21 @@ contain that underscore. You also cannot use values with spaces.

Tip: Use the @method tag in your docblock to typehint the methods if you like.

### isIn and isNotIn

`Equals` already can do this, but this might be easier to the eye.

````php
YourEnum::ENUM->isIn(YourEnum::ENUM, 'your_other_value'); // returns true
YourEnum::ENUM->isIn('ENUM', YourEnum::ENUM2); // returns true
YourEnum::ENUM->isIn('your_value', 'your_other_value'); //returns true
YourEnum::ENUM->isIn('ENUM2', YourEnum::ENUM2); // returns false


YourEnum::ENUM->isNotIn('random', 'something_else'); //returns true
YourEnum::ENUM->isNotIn('enum', 'something_else'); //returns false
````

## Comparing and mapping

Comparison automatically uses [Mappers](mappers.md) whenever available.
Expand Down Expand Up @@ -126,6 +148,12 @@ object, but do match by name or are mapped using a mapper.
Animal::Dog->equals(LatinAnimalName::Canine); // returns true;
Animal::Dog->equals(LatinAnimalName::Feline); // returns false;

Animal::Dog->is(LatinAnimalName::Canine); // returns true;
Animal::Dog->is(LatinAnimalName::Feline); // returns false;

Animal::Dog->isNot(LatinAnimalName::Canine); // returns false;
Animal::Dog->isNot(LatinAnimalName::Feline); // returns true;

Animal::Dog->equals(SomeOtherEnum::Canine); // return true
Animal::Dog->equals(SomeOtherEnum::Dog); // return true
Animal::Dog->equals(SomeOtherEnum::Something); // throws error
Expand Down
3 changes: 0 additions & 3 deletions docs/constructor.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,4 @@ enum yourEnum {
YourEnum::CALLABLE(); // will return YourEnum::CALLABLE;
```

Note: Under the hood it is using `__callStatic`, so it may give some unpredicted
behavior when calling a method that doesn't exist.

Note: This trait is not enabled by default when using the `Enhancers` trait.
26 changes: 23 additions & 3 deletions docs/state.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,16 @@ elevator::Open->allowsTransition(elevator::Move); // returns false

elevator::Open->transitionTo('Close'); // returns elevator::Close
elevator::Move->transitionTo(elevator::Close); // throws exception
elevator::Close->transitionTo('Open'); // throws exception
elevator::Close->transitionTo('Open'); // throws IllegalEnumTransitionException

elevator::Open->to(elevator::Move) // throws IllegalEnumTransitionException
elevator::Open->tryTo(elevator::Move) // returns elevator::Open
elevator::Open->tryTo(elevator::Close) // returns elevator::Close

/** using magic */
elevator::Open->toMove() // throws IllegalEnumTransitionException
elevator::Open->tryToMove() // returns elevator::Open
elevator::Open->tryToClose() // returns elevator::Close
```

#### Complex Usage
Expand Down Expand Up @@ -69,7 +78,7 @@ elevator::Open->transitionTo(elevator::Close)
->transitionTo('Open')
->transitionTo('Close'); //eventually returns elevator::Close

elevator::Move->transitionTo('Open'); //throws exception
elevator::Move->transitionTo('Open'); //throws IllegalEnumTransitionException
```

The array returned by the `customTransitions` method can return an array containing
Expand Down Expand Up @@ -132,9 +141,20 @@ elevator::Move->allowedTransitions($hook); // returns []
elevator::Move->transitionTo('stop', $hook); // throws IllegalEnumTransitionException
elevator::Close->allowTransition('move', $hook); // returns true
elevator::Close->transitionTo('move', $hook); // returns increases $floor to 2

elevator::Move->tryTo('stop', $hook); // returns elevator::Move
elevator::Move->to('stop', $hook); // throws IllegalEnumTransitionException
elevator::Close->tryTo('move', $hook); // returns elevator::Close
elevator::Close->to('move', $hook); // returns increases $floor to 2

/** using magic calls */
elevator::Move->tryToStop($hook); // returns elevator::Move
elevator::Move->toStop($hook); // throws IllegalEnumTransitionException
elevator::Close->tryToMove($hook); // returns elevator::Close
elevator::Close->toMove($hook); // returns increases $floor to 2
```

You can also add a `TransitionHook` directly on to your enum class.
You can also add a `TransitionHook` directly on to your enum object.

```php
enum elevator {
Expand Down
36 changes: 16 additions & 20 deletions src/Concerns/Comparison.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,35 @@

namespace Henzeb\Enumhancer\Concerns;

use BadMethodCallException;
use Henzeb\Enumhancer\Helpers\EnumGetters;
use Henzeb\Enumhancer\Helpers\EnumCompare;
use UnitEnum;

trait Comparison
{
use MagicCalls;

public function equals(UnitEnum|string|int|null ...$equals): bool
{
return EnumCompare::equals($this, ...$equals);
}

public function __call(string $name, array $arguments): self|bool
public function is(UnitEnum|string|int|null $equals): bool
{
if (EnumCompare::isValidCall(self::class, $name, $arguments)) {
throw new BadMethodCallException(sprintf('Call to undefined method %s::%s(...)', $this::class, $name));
}

$nameIsEnum = !EnumGetters::tryGet(self::class, $name, true);

if (!$nameIsEnum && method_exists(self::class, '__callStatic')) {
return self::__callStatic($name, []);
}
return $this->equals($equals);
}

$value = substr($name, str_starts_with($name, 'isNot') ? 5 : 2);
public function isNot(UnitEnum|string|int|null $equals): bool
{
return !$this->is($equals);
}

if (!EnumGetters::tryGet(self::class, $value, true)) {
throw new BadMethodCallException(sprintf('Call to undefined method %s::%s(...)', $this::class, $name));
}
public function isIn(UnitEnum|string|int|null ...$equals): bool
{
return $this->equals(...$equals);
}

if (str_starts_with($name, 'isNot')) {
return !$this->equals($value);
}
return $this->equals($value);
public function isNotIn(UnitEnum|string|int|null ...$equals): bool
{
return !$this->equals(...$equals);
}
}
5 changes: 1 addition & 4 deletions src/Concerns/Constructor.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,5 @@

trait Constructor
{
public static function __callStatic(string $name, array $arguments)
{
return EnumGetters::get(self::class, $name, true);
}
use MagicCalls;
}
18 changes: 18 additions & 0 deletions src/Concerns/MagicCalls.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace Henzeb\Enumhancer\Concerns;

use Henzeb\Enumhancer\Helpers\EnumMagicCalls;

trait MagicCalls
{
public static function __callStatic(string $name, array $arguments = [])
{
return EnumMagicCalls::static(self::class, $name);
}

public function __call(string $name, array $arguments = [])
{
return EnumMagicCalls::call($this, $name, $arguments);
}
}
30 changes: 22 additions & 8 deletions src/Concerns/State.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,19 @@

namespace Henzeb\Enumhancer\Concerns;

use Henzeb\Enumhancer\Helpers\EnumProperties;
use UnitEnum;
use Henzeb\Enumhancer\Helpers\EnumState;
use Henzeb\Enumhancer\Helpers\EnumGetters;
use Henzeb\Enumhancer\Contracts\TransitionHook;
use Henzeb\Enumhancer\Exceptions\SyntaxException;
use Henzeb\Enumhancer\Exceptions\IllegalEnumTransitionException;
use Henzeb\Enumhancer\Exceptions\IllegalNextEnumTransitionException;
use Henzeb\Enumhancer\Exceptions\SyntaxException;
use Henzeb\Enumhancer\Helpers\EnumGetters;
use Henzeb\Enumhancer\Helpers\EnumProperties;
use Henzeb\Enumhancer\Helpers\EnumState;
use UnitEnum;

trait State
{
use MagicCalls;

/**
* @throws IllegalEnumTransitionException|SyntaxException
*/
Expand All @@ -30,20 +32,32 @@ public function transitionTo(self|string|int $state, TransitionHook $hook = null
throw new IllegalEnumTransitionException($this, $state);
}

public function to(self|string|int $state, TransitionHook $hook = null): self
{
return $this->transitionTo($state, $hook);
}

public function tryTo(self|string|int $state, TransitionHook $hook = null): self
{
if ($this->isTransitionAllowed($state, $hook)) {
return $this->transitionTo($state, $hook);
}
return $this;
}

/**
* @param self|string|int $state
* @param TransitionHook|null $hook
* @return bool
* @throws SyntaxException
*/
public function isTransitionAllowed(self|string|int $state, TransitionHook $hook = null): bool
{
/**
* @var $this UnitEnum
*/
$state = EnumGetters::cast(self::class, $state);
$state = EnumGetters::tryCast(self::class, $state);

return in_array($state, $this->allowedTransitions($hook));
return $state && in_array($state, $this->allowedTransitions($hook));
}

/**
Expand Down
23 changes: 19 additions & 4 deletions src/Helpers/EnumCompare.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,24 @@ public static function equals(UnitEnum $compare, UnitEnum|int|string|null ...$wi

public static function isValidCall(string $class, $name, array $arguments): bool
{
$nameIsEnum = !EnumGetters::tryGet($class, $name, true);
return ((!str_starts_with($name, 'is') && !str_starts_with($name, 'isNot'))
|| count($arguments))
&& $nameIsEnum;
EnumCheck::check($class);

return EnumImplements::comparison($class)
&& !count($arguments) && str_starts_with($name, 'is');
}

public static function call(UnitEnum $enum, string $name): bool
{
$value = EnumGetters::tryGet(
$enum::class,
substr($name, str_starts_with($name, 'isNot') ? 5 : 2),
true
);

if (!$value) {
EnumMagicCalls::throwException($enum::class, $name);
}

return str_starts_with($name, 'isNot') !== self::equals($enum, $value);
}
}
12 changes: 12 additions & 0 deletions src/Helpers/EnumImplements.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace Henzeb\Enumhancer\Helpers;

use Henzeb\Enumhancer\Concerns\Comparison;
use Henzeb\Enumhancer\Concerns\Constructor;
use Henzeb\Enumhancer\Concerns\Labels;
use Henzeb\Enumhancer\Concerns\State;
use Henzeb\Enumhancer\Concerns\Mappers;
Expand Down Expand Up @@ -36,6 +38,16 @@ public static function labels(string $class): bool
return self::traitOn($class, Labels::class);
}

public static function constructor(string $class): bool
{
return self::traitOn($class, Constructor::class);
}

public static function comparison(string $class): bool
{
return self::traitOn($class, Comparison::class);
}

private static function classUsesTrait(string $class): array
{
$results = [];
Expand Down
40 changes: 40 additions & 0 deletions src/Helpers/EnumMagicCalls.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

namespace Henzeb\Enumhancer\Helpers;

use BadMethodCallException;
use UnitEnum;

abstract class EnumMagicCalls
{
public static function call(UnitEnum $enum, string $name, array $arguments): mixed
{
EnumCheck::check($enum::class);

if (EnumCompare::isValidCall($enum::class, $name, $arguments)) {
return EnumCompare::call($enum, $name);
}

if (EnumState::isValidCall($enum::class, $name)) {
return EnumState::call($enum, $name, $arguments);
}

return self::static($enum::class, $name);
}

public static function static(string $class, string $name): mixed
{
EnumCheck::check($class);

if (EnumImplements::constructor($class)) {
return EnumGetters::tryGet($class, $name, true) ?? self::throwException($class, $name);
}

self::throwException($class, $name);
}

public static function throwException($class, $name): never
{
throw new BadMethodCallException(sprintf('Call to undefined method %s::%s(...)', $class, $name));
}
}
Loading

0 comments on commit 2b00ac5

Please sign in to comment.