Skip to content

Commit

Permalink
v1.20.0
Browse files Browse the repository at this point in the history
  • Loading branch information
henzeb committed Jan 4, 2023
1 parent 1b674d2 commit 5e8b151
Show file tree
Hide file tree
Showing 79 changed files with 3,391 additions and 641 deletions.
22 changes: 21 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,29 @@

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

## 1.20.0 - 2023-01-04

- bugfix in [Default](docs/defaults.md) where configured defaults would
not override the by const defined value
- bugfix in [Mappers](docs/mappers.md) where mapping to integers was
not allowed

### Extended features

- You can now set Mapper FQCN in constants starting with
`map` and `map_flip`
- [Mappers](docs/mappers.md) methods now are usable statically
- All Laravel rules have now macro's set on `Rule`

### New features

- added [Bitmask](docs/bitmasks.md)
- added [Macros](docs/macros.md)
- added `isEnum` and `enumBitmask` rules

## 1.19.0 - 2022-12-15

- You can now use constants for [Mappers](docs/mappers)
- You can now use constants for [Mappers](docs/mappers.md)
and [Defaults](docs/defaults.md)
- you can now flag a unit enum as `strict`, so you don't
have to worry about casing in [Values](docs/value.md).
Expand Down
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ implemented the methods of `Getters`, `Extractor` and `Reporters`.

### Features

- [Bitmasks](docs/bitmasks.md)
- [Constructor](docs/constructor.md)
- [Comparison](docs/comparison.md)
- [Configure](docs/configure.md)
Expand All @@ -67,6 +68,7 @@ implemented the methods of `Getters`, `Extractor` and `Reporters`.
- [Getters](docs/getters.md)
- [Labels](docs/labels.md)
- ~~[Makers](docs/makers.md)~~ (deprecated)
- [Macros](docs/macros.md)
- [Mappers](docs/mappers.md)
- [Properties](docs/properties.md)
- [Reporters](docs/reporters.md)
Expand All @@ -89,8 +91,9 @@ implemented the methods of `Getters`, `Extractor` and `Reporters`.
### Laravel's auto-discovery

When you are installing this package into a laravel project, Enumhancer will
automatically set the global `Reporter` for the `makeOrReport` methods, so that
it will use Laravel's `Log` facade.
automatically set macro's for the `validation rules` and sets the global
`Reporter` for the `makeOrReport` methods, so that it will use Laravel's
`Log` facade.

If you don't want that to happen, you can tell Laravel not to discover the
package.
Expand Down
309 changes: 309 additions & 0 deletions docs/bitmasks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,309 @@
# Bitmasks

````php
enum Permission {
use Henzeb\Enumhancer\Concerns\Bitmasks;

case Create;
case Read;
case Update;
case Delete;
}

Permission::Create->bit(); // returns 1
Permission::Read->bit(); // returns 2
Permission::Update->bit(); // returns 4
Permission::Delete->bit(); // returns 8
````

## Integer backed enums

Enumhancer allows you to use your own bit values by using an integer or
string backed enum. This is disabled by default. You can enable it by
adding a constant called `BIT_VALUES` that returns true.

````php
enum PermissionInt: int
{
use Henzeb\Enumhancer\Concerns\Bitmasks;

private const BIT_VALUES = true;

case Create = 8;
case Read = 16;
case Update = 32;
case Delete = 128;
}

PermissionInt::Create->bit(); // returns 8
PermissionInt::Read->bit(); // returns 16
PermissionInt::Update->bit(); // returns 32
PermissionInt::Delete->bit(); // returns 128
````

Note: when the flag `BIT_VALUES` is set, each case must have a valid bit set.
For example: `7` would throw a fatal error as this consists of the bits `1` `2`
and `4`.

## Bits

When you want to use the bits in a dropdown, you can easily use `bits`.

````php
// returns [1 => 'Create', 2 => 'Read', 4 => 'Update', 8 => 'Delete']
Permission::bits();

// returns [8 => 'Create', 16 => 'Read', 32 => 'Update', 128 => 'Delete']
PermissionInt::bits();

````

Note: Just like [Dropdown](dropdown.md), `bits` uses [Labels](labels.md) where applicable.

## Create bitmasks

Enumhancer gives you easy tools to work with bitmasks. Just like everywhere else,
if [Mappers](mappers.md) are being used, any value will be mapped.

### mask

To get a mask, simply call the static method on your enum. just like with
[Comparison](comparison.md), you can add as many enum or values that represent enums
as you need.

````php
Permission::mask(); // returns a Bitmask object with value 0
Permission::mask(Permission::Create); // returns Bitmask with value 1
Permission::mask(Permission::Create, 'update'); // returns Bitmask with value 5
Permission::mask(Permission::Create, 'modify'); // throws error
````

### fromMask

To transform a numeric bitmask, retreived from for example a database,
into a `Bitmask` object, you can use `fromMask`.

````php
Permission::fromMask(0); // returns a Bitmask object with value 0
Permission::fromMask(1); // returns Bitmask with value 1
Permission::fromMask(5); // returns Bitmask with value 5
Permission::fromMask(16); // throws error

PermissionInt::fromMask(32); // returns a Bitmask object with value 32
PermissionInt::fromMask(64); // throws error
````

numeric bitmasks are validated and can only represent any existing combination
of bits corresponding to existing cases.

### tryMask

This method works the same as `fromMask`, but will return a `Bitmask`
with a value of 0 or a specified bitmask instead if an invalid
bitmask is given.

````php
Permission::tryMask(null); // returns a Bitmask object with value 0
Permission::tryMask(
null,
Permission::Read
); // returns a Bitmask object with value 1
Permission::tryMask(0); // returns a Bitmask object with value 0
Permission::tryMask(
0,
Permission::Read
); // returns a Bitmask object with value 0

Permission::tryMask(1); // returns Bitmask with value 1
Permission::tryMask(5); // returns Bitmask with value 5
Permission::tryMask(16); // returns a Bitmask object with value 0
Permission::tryMask(16, 'read'); // returns a Bitmask object with value 1

Permission::tryMask(
16,
Permission::Read
); // returns a Bitmask object with value 1
Permission::tryMask(
16,
Permission::mask('Read', 'Update')
); // returns a Bitmask object with value 3

PermissionInt::tryMask(32); // returns a Bitmask object with value 32
PermissionInt::tryMask(64); // returns a Bitmask object with value 0
PermissionInt::tryMask(
64,
'Read', 'Update'
); // returns a Bitmask object with value 3
````

Note: If [Defaults](defaults.md) is configured, tryMask will use that default.
You can counteract by passing a null as the second value.

## Bitmask operations

The `Bitmask` object operates a similar to a `Flag Bag` you see in other libraries.
You can easily modify and validate. It is however tied to the enum that created it.

The `Bitmask` object is also implementing a fluent interface for all methods, unless
specified otherwise.

All the methods accept either enums or strings or integers representing
the enums either mapped or directly. You can also insert Bitmask instances
as (one of) it's argument, as long as the Bitmask belongs to the same enum.

### Value

````php
Permission::mask()->value(); // returns 0
Permission::mask('Read')->value(); // returns 2
Permission::mask('Create', 'Read')->value(); // returns 3
````

#### Stringable

Bitmask objects are stringable. It will return the value as a string

````php
(string)Permission::mask(); // returns "0"
(string)Permission::mask('Read'); // returns "2"
(string)Permission::mask('Create', 'Read'); // returns "3"
````

### Cases

Returns an array of cases corresponding to the bits set.

````php
Permission::mask()->cases(); // returns []
Permission::mask('Read')->cases(); // returns [Permission::Read]
Permission::mask('Create', 'Read')->cases(); // returns [Permission::Create, Permission::Read]
````

### Set

````php
Permission::mask()->set(Permission::Read); // sets value to 2
Permission::mask('Read')->set(Permission::Create); // sets value to 3
Permission::mask('Read')
->set(Permission::mask(Permission::Create)); // sets value to 3
Permission::mask('Read')->set(Permission::Create, 'Update'); // sets value to 7
Permission::mask('Read')->set(Permission::Read); // keeps value as 2
````

### Unset

````php
Permission::mask()->unset(Permission::Read); // keeps value as 0
Permission::mask('Read')->unset(Permission::Read); // sets value to 0
Permission::mask('Read')
->unset(Permission::mask(Permission::Read)); // sets value to 0
Permission::mask('Read', 'Update')
->unset(Permission::Create, 'Update'); // sets value to 2
Permission::mask('Read')->unset(Permission::Read); // keeps value as 2
````

### Toggle

Toggle toggles between 0 and 1. If a bit is set, it wil unset it and vice versa.
You can mix up as many as you like, it will toggle each value individually.

````php
Permission::mask()->toggle(Permission::Read); // sets value to 1
Permission::mask('Read')->toggle(Permission::Read); // sets value to 0
Permission::mask()
->toggle(Permission::mask(Permission::Read)); // sets value to 1
Permission::mask('Read', 'Update')
->toggle(Permission::Create, 'Update'); // sets value to 3
Permission::mask('Update')->toggle(Permission::Read); // sets value to 6
````

### Clear

Resets the value to 0. This means no bits are set after calling it.

````php
Permission::mask()->clear(); // sets value to 0
Permission::mask('Read')->clear(); // sets value to 0
Permission::mask('Read', 'Update')->clear(); // sets value to 0
````

### Copy

Copy allows you to duplicate the `Bitmask`. It creates a whole new instance,
with the current value, you can modify, without modifying the original one.

````php
Permission::mask()->copy(); // returns new Bitmask instance.
````

### Has

````php
Permission::mask()->has('Read'); // returns false
Permission::mask('Read')->has(Permission::Read); // returns true
Permission::mask('Create')->has('Read'); // returns false
````

### All

````php
Permission::mask()->all(); // returns true
Permission::mask()->all('Read', 'Create'); // returns false
Permission::mask('Read')->all('Read', 'Create'); // returns false
Permission::mask('Read', 'Update', 'Delete')->all('Read', 'Update'); // returns true
````

### Any

````php
Permission::mask()->all(); // returns true
Permission::mask()->all('Read', 'Create'); // returns false
Permission::mask('Read')->all('Read', 'Create'); // returns false
Permission::mask('Read', 'Update', 'Delete')->all('Read', 'Update'); // returns true
````

### Xor

````php
Permission::mask()->xor(); // returns false
Permission::mask()->xor('Read', 'Create'); // returns false
Permission::mask('Read')->xor('Read', 'Create'); // returns true
Permission::mask('Read', 'Update')->xor('Read', 'Update'); // returns false
````

### None

````php
Permission::mask()->none(); // returns true
Permission::mask()->none('Read', 'Create'); // returns true
Permission::mask('Read')->none('Read', 'Create'); // returns false
Permission::mask('Read', 'Update')->none('Delete', 'Create'); // returns true
````

### for

Bitmask does it for you, but if you want to check up front, you can check if
the Bitmask belongs to a certain enum.

````php
Permission::mask()->for(Permission::class); // returns true
Permission::mask()->for(PermissionInt::class); // returns false
````

### forOrFail

Does the same as `for`, but instead throws an exception when it does not match.

````php
Permission::mask()->for(Permission::class); // returns true
Permission::mask()->for(PermissionInt::class); // throws exception
````

### ForEnum

Returns the class name of the enum the Bitmask belongs to.

````php
Permission::mask()->forEnum(); // returns Permission::class
PermissionInt::mask()->forEnum(); // returns PermissionInt::class
````
9 changes: 7 additions & 2 deletions docs/configure.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,19 @@ use Henzeb\Enumhancer\Concerns\ConfigureMapper;

use Henzeb\Enumhancer\Concerns\Enhancers;

enum YourEnum {
enum Suit {
use Enhancers, ConfigureMapper;

// ...
}

yourEnum::setMapper(new YourMapper());
yourEnum::setMapper(new SuitMapper());
yourEnum::setMapper(['H'=>'Hearts']);
yourEnum::setMapper(SuitMapper::class, ['H'=>'Hearts']);

yourEnum::setMapperOnce(new YourMapper());
yourEnum::setMapperOnce(['H'=>'Hearts']);
yourEnum::setMapperOnce(SuitMapper::class, ['H'=>'Hearts']);
```

### ConfigureState
Expand Down
Loading

0 comments on commit 5e8b151

Please sign in to comment.