Skip to content

Commit 08558e5

Browse files
committed
Merge branch 'develop'
* develop: specify next release update action version update actions version add Validation fix doc error
2 parents 9ba8332 + 94442fc commit 08558e5

File tree

10 files changed

+991
-8
lines changed

10 files changed

+991
-8
lines changed

.github/workflows/ci.yml

+5-5
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
name: 'BlackBox'
1414
steps:
1515
- name: Checkout
16-
uses: actions/checkout@v2
16+
uses: actions/checkout@v4
1717
- name: Setup PHP
1818
uses: shivammathur/setup-php@v2
1919
with:
@@ -38,7 +38,7 @@ jobs:
3838
name: 'Coverage'
3939
steps:
4040
- name: Checkout
41-
uses: actions/checkout@v2
41+
uses: actions/checkout@v4
4242
- name: Setup PHP
4343
uses: shivammathur/setup-php@v2
4444
with:
@@ -54,7 +54,7 @@ jobs:
5454
env:
5555
ENABLE_COVERAGE: 'true'
5656
BLACKBOX_SET_SIZE: 1
57-
- uses: codecov/codecov-action@v1
57+
- uses: codecov/codecov-action@v3
5858
with:
5959
token: ${{ secrets.CODECOV_TOKEN }}
6060
psalm:
@@ -65,7 +65,7 @@ jobs:
6565
name: 'Psalm'
6666
steps:
6767
- name: Checkout
68-
uses: actions/checkout@v2
68+
uses: actions/checkout@v4
6969
- name: Setup PHP
7070
uses: shivammathur/setup-php@v2
7171
with:
@@ -83,7 +83,7 @@ jobs:
8383
name: 'CS'
8484
steps:
8585
- name: Checkout
86-
uses: actions/checkout@v2
86+
uses: actions/checkout@v4
8787
- name: Setup PHP
8888
uses: shivammathur/setup-php@v2
8989
with:

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## 5.3.0 - 2023-11-06
4+
5+
### Added
6+
7+
- `Innmind\Immutable\Validation`
8+
39
## 5.2.0 - 2023-11-05
410

511
### Added

docs/EITHER.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ function identify(ServerRequest $request): Either {
1717
return Either::right($theUser);
1818
}
1919

20-
Either::left(new Error('User not found'));
20+
return Either::left(new Error('User not found'));
2121
}
2222

2323
/**
@@ -83,7 +83,7 @@ This will apply the map transformation on the right value if there is one, other
8383

8484
```php
8585
/** @var Either<Error, User> */
86-
$either = identify($serverRequest)
86+
$either = identify($serverRequest);
8787
/** @var Either<Error, Impersonated> */
8888
$impersonated = $either->map(fn(User $user): Impersonated => $user->impersonateAdmin());
8989
```

docs/README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ composer require innmind/immutable
1212

1313
## Structures
1414

15-
This library provides the 7 following structures:
15+
This library provides the 10 following structures:
1616

1717
- [`Sequence`](SEQUENCE.md)
1818
- [`Set`](SET.md)
@@ -21,6 +21,7 @@ This library provides the 7 following structures:
2121
- [`RegExp`](REGEXP.md)
2222
- [`Maybe`](MAYBE.md)
2323
- [`Either`](EITHER.md)
24+
- [`Validation`](VALIDATION.md)
2425
- [`State`](STATE.md)
2526
- [`Fold`](FOLD.md)
2627

docs/VALIDATION.md

+176
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
# `Validation`
2+
3+
This structure is similar to [`Either`](EITHER.md) except that the right side is called success and left fail. The difference is that `Validation` allows to accumulate failures.
4+
5+
For the examples below we will use the given imaginary functions:
6+
7+
```php
8+
use Innmind\Immutable\Validation;
9+
10+
/**
11+
* @return Validation<Error, string>
12+
*/
13+
function isEmail(string $value): Validation {
14+
if (\filter_var($value, \FILTER_VALIDATE_EMAIL)) {
15+
return Validation::success($value);
16+
}
17+
18+
return Validation::fail(new Error("$value is not an email"));
19+
}
20+
21+
/**
22+
* @return Validation<Error, string>
23+
*/
24+
function isLocal(string $value): Validation {
25+
if (\str_ends_with($value, '.local')) {
26+
return Validation::success($value);
27+
}
28+
29+
return Validation::fail(new Error('Not a local email'));
30+
}
31+
```
32+
33+
> **Note**
34+
> `Error` is imaginary class.
35+
36+
## `::fail()`
37+
38+
This builds a `Validation` instance with the given value in the fail side.
39+
40+
```php
41+
$validation = Validation::fail($anyValue);
42+
```
43+
44+
## `::success()`
45+
46+
This builds a `Validation` instance with the given value in the success side.
47+
48+
```php
49+
$validation = Validation::success($anyValue);
50+
```
51+
52+
## `->map()`
53+
54+
This will apply the map transformation on the success value if there is one, otherwise it's only a type change.
55+
56+
```php
57+
/** @var Validation<Error, string> */
58+
$validation = isEmail('[email protected]');
59+
/** @var Either<Error, Email> */
60+
$email = $validation->map(fn(string $email): Email => new Email($email));
61+
```
62+
63+
## `->flatMap()`
64+
65+
This is similar to `->map()` but instead of returning the new success value you return a new `Validation` object.
66+
67+
```php
68+
/** @var Validation<Error, string> */
69+
$validation = isEmail('[email protected]');
70+
/** @var Validation<Error, string> */
71+
$localEmail = $either->flatMap(fn(string $email): Validation => isLocal($email));
72+
```
73+
74+
## `->match()`
75+
76+
This is the only way to extract the wrapped value.
77+
78+
```php
79+
/** @var Email */
80+
$localEmail = isEmail($serverRequest)
81+
->flatMap(fn(string $email): Validation => isLocal($email))
82+
->map(static fn(string $email) => new Email($email))
83+
->match(
84+
fn(Email $email) => $email,
85+
fn(Sequence $failures) => throw new \Exception(\implode(', ', $failure->toList())),
86+
);
87+
```
88+
89+
## `->otherwise()`
90+
91+
This is like `->flatMap()` but is called when the instance contains failures. The callable must return a new `Validation` object.
92+
93+
```php
94+
/** @var Validation<Error, string> */
95+
$email = isEmail('invalid value')
96+
->otherwise(fn() => isEmail('[email protected]'));
97+
```
98+
99+
## `->mapFailures()`
100+
101+
This is similar to the `->map()` function but will be applied on each failure.
102+
103+
```php
104+
/** @var Either<Exception, string> */
105+
$email = isEmail('[email protected]')
106+
->mapFailures(fn(Error $error) => new \Exception($error->toString()));
107+
```
108+
109+
## `->and()`
110+
111+
This method allows to aggregate the success values of 2 `Validation` objects or aggregates the failures if at least one of them is a failure.
112+
113+
```php
114+
$foo = isEmail('[email protected]');
115+
$bar = isEmail('[email protected]');
116+
$baz = isEmail('invalid value');
117+
$foobar = isEmail('another value');
118+
119+
$foo
120+
->and(
121+
$bar,
122+
static fn($a, $b) => [$a, $b],
123+
)
124+
->match(
125+
static fn($value) => $value,
126+
static fn() => null,
127+
128+
$foo
129+
->and(
130+
$baz,
131+
static fn($a, $b) => [$a, $b],
132+
)
133+
->match(
134+
static fn() => null,
135+
static fn($failures) => $failures->toList(),
136+
); // returns [new Error('invalid value is not an email')]
137+
$foobar
138+
->and(
139+
$baz,
140+
static fn($a, $b) => [$a, $b],
141+
)
142+
->match(
143+
static fn() => null,
144+
static fn($failures) => $failures->toList(),
145+
); // returns [new Error('another value is not an email'), new Error('invalid value is not an email')]
146+
```
147+
148+
## `->maybe()`
149+
150+
This returns a [`Maybe`](MAYBE.md) containing the success value, in case of failures it returns a `Maybe` with nothing inside.
151+
152+
```php
153+
Validation::success('something')->maybe()->match(
154+
static fn($value) => $value,
155+
static fn() => null,
156+
); // returns 'something'
157+
Validation::fail('something')->maybe()->match(
158+
static fn($value) => $value,
159+
static fn() => null,
160+
); // returns null
161+
```
162+
163+
## `->either()`
164+
165+
This returns an [`Either`](EITHER.md) containing the success value as the right side, in case of failures it returns an `Either` with failures as the left side.
166+
167+
```php
168+
Validation::success('something')->either()->match(
169+
static fn($value) => $value,
170+
static fn() => null,
171+
); // returns 'something'
172+
Validation::fail('something')->either()->match(
173+
static fn() => null,
174+
static fn($value) => $value,
175+
); // returns Sequence<string>
176+
```

0 commit comments

Comments
 (0)