Skip to content

Commit 7ccabab

Browse files
Release version 2.0.0
1 parent fff30af commit 7ccabab

File tree

10 files changed

+301
-179
lines changed

10 files changed

+301
-179
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
/vendor/
22
/.vscode/
3-
/.idea/
3+
/.idea/
4+
composer.lock

README.md

Lines changed: 161 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
# Option Array Processing and Validation Library
1+
# PHP Options Resolver
22

3-
This library provides a simple solution for processing and validating option arrays in PHP.
3+
**Strict, Fluent, and Type-Safe Option Validation for PHP.**
4+
5+
Stop guessing what's in your `$options` array. This library provides a robust, fluent API to define, validate, and resolve options with strict type enforcement and custom validation logic. Designed for developers who value clarity and code quality.
46

57
## Installation
68

79
To install this library, use [Composer](https://getcomposer.org/)
810

9-
### Run the following Composer command:
10-
1111
```bash
1212
composer require phpdevcommunity/php-options-resolver
1313
```
@@ -16,9 +16,13 @@ composer require phpdevcommunity/php-options-resolver
1616

1717
* PHP version 7.4 or higher
1818

19-
### Defining Required Options
19+
---
20+
21+
## Documentation (English)
22+
23+
### Basic Usage
2024

21-
Define the required options for your class using `OptionsResolver` with the expected options:
25+
Define the options for your class using `OptionsResolver` with the expected options. You can use static factory methods on the `Option` class to define types easily.
2226

2327
```php
2428
<?php
@@ -28,194 +32,224 @@ use PhpDevCommunity\Resolver\OptionsResolver;
2832

2933
class Database
3034
{
35+
private array $options;
36+
3137
public function __construct(array $options = [])
3238
{
3339
$resolver = new OptionsResolver([
34-
new Option('host'),
35-
new Option('username'),
36-
new Option('password'),
37-
new Option('dbname'),
40+
Option::string('host')->setOptional('localhost'),
41+
Option::string('username')->required(),
42+
Option::string('password')->required(),
43+
Option::string('dbname')->required(),
44+
Option::int('port')->setOptional(3306),
3845
]);
3946

40-
try {
41-
$this->options = $resolver->resolve($options);
42-
} catch (InvalidArgumentException $e) {
43-
throw new InvalidArgumentException("Error: " . $e->getMessage());
44-
}
47+
$this->options = $resolver->resolve($options);
4548
}
4649
}
4750

4851
// Example usage:
4952
try {
5053
$database = new Database([
51-
'host' => 'localhost',
52-
'dbname' => 'app',
54+
'username' => 'root',
55+
'password' => 'secret',
56+
'dbname' => 'app_db',
5357
]);
58+
// 'host' will be 'localhost' and 'port' will be 3306
5459
} catch (InvalidArgumentException $e) {
55-
echo "Error: " . $e->getMessage(); // Displays: "Error: The required option 'username' is missing."
60+
echo "Error: " . $e->getMessage();
5661
}
5762
```
5863

59-
### Defining Default Options
64+
### Available Types
65+
6066

61-
You can also set default values for your options using `setDefaultValue` for each option:
6267

68+
The `Option` class provides several static factory methods to enforce types automatically. Here are examples for each type:
69+
70+
#### String
6371
```php
64-
<?php
72+
Option::string('host')->setOptional('localhost');
73+
```
6574

66-
class Database
67-
{
68-
public function __construct(array $options = [])
69-
{
70-
$resolver = new OptionsResolver([
71-
(new Option('host'))->setDefaultValue('localhost'),
72-
(new Option('username'))->setDefaultValue('root'),
73-
(new Option('password'))->setDefaultValue('root'),
74-
(new Option('dbname'))->setDefaultValue('app'),
75-
]);
75+
#### Integer
76+
```php
77+
Option::int('port')->setOptional(3306);
78+
```
7679

77-
$this->options = $resolver->resolve($options);
78-
}
79-
}
80+
#### Float
81+
```php
82+
Option::float('timeout')->setOptional(2.5);
83+
```
8084

81-
// Example usage:
82-
$database = new Database([]);
83-
var_dump($database->getOptions());
84-
// Expected output:
85-
// array(4) {
86-
// ["host"]=> string(9) "localhost"
87-
// ["username"]=> string(4) "root"
88-
// ["password"]=> string(4) "root"
89-
// ["dbname"]=> string(3) "app"
90-
// }
85+
#### Boolean
86+
```php
87+
Option::bool('active')->setOptional(true);
9188
```
9289

93-
### Handling Non-existent Options
90+
#### Array
91+
```php
92+
Option::array('tags')->setOptional(['php', 'library']);
93+
```
9494

95-
If a provided option does not exist in the defined list of options, an `InvalidArgumentException` will be thrown:
95+
#### Iterable
96+
```php
97+
Option::iterable('items')->required();
98+
```
9699

100+
#### Mixed (No type enforcement)
97101
```php
98-
<?php
102+
Option::mixed('metadata')->setOptional(null);
103+
```
99104

100-
class Database
101-
{
102-
public function __construct(array $options = [])
103-
{
104-
$resolver = new OptionsResolver([
105-
(new Option('host'))->setDefaultValue('localhost'),
106-
(new Option('username'))->setDefaultValue('root'),
107-
(new Option('password'))->setDefaultValue('root'),
108-
(new Option('dbname'))->setDefaultValue('app'),
109-
]);
105+
### Required vs Optional
110106

111-
try {
112-
$this->options = $resolver->resolve($options);
113-
} catch (InvalidArgumentException $e) {
114-
throw new InvalidArgumentException("Error: " . $e->getMessage());
115-
}
116-
}
117-
}
107+
* **Required**: Use `required()` to enforce that an option must be passed. If missing, an exception is thrown.
108+
* **Optional**: Use `setOptional($defaultValue)` to define a default value if the option is not provided.
118109

119-
// Example usage:
120-
try {
121-
$database = new Database([
122-
'url' => 'mysql://root:root@localhost/app',
123-
]);
124-
} catch (InvalidArgumentException $e) {
125-
echo "Error: " . $e->getMessage(); // Displays: "Error: The option(s) 'url' do(es) not exist. Defined options are: 'host', 'username', 'password', 'dbname'."
126-
}
110+
```php
111+
Option::string('apiKey')->required(); // Must be provided
112+
Option::bool('debug')->setOptional(false); // Defaults to false if missing
127113
```
128114

129-
### Validating Option Values
115+
### Custom Validation
130116

131-
You can add custom validators for each option to validate the provided values:
117+
You can add custom validation logic using the `validator()` method. The closure must return a `bool`.
118+
119+
```php
120+
Option::string('driver')
121+
->setOptional('mysql')
122+
->validator(function ($value) {
123+
return in_array($value, ['mysql', 'pgsql', 'sqlite']);
124+
});
125+
```
126+
127+
### Handling Errors
128+
129+
The `resolve()` method throws an `InvalidArgumentException` if:
130+
* A required option is missing.
131+
* An undefined option is provided.
132+
* An option value is invalid (wrong type or failed custom validation).
133+
134+
### License
135+
136+
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
137+
138+
---
139+
140+
## Documentation (Français)
141+
142+
### Usage de base
143+
144+
Définissez les options attendues pour votre classe en utilisant `OptionsResolver`. Vous pouvez utiliser les méthodes statiques de la classe `Option` pour définir les types facilement.
132145

133146
```php
134147
<?php
135148

149+
use PhpDevCommunity\Resolver\Option;
150+
use PhpDevCommunity\Resolver\OptionsResolver;
151+
136152
class Database
137153
{
154+
private array $options;
155+
138156
public function __construct(array $options = [])
139157
{
140158
$resolver = new OptionsResolver([
141-
(new Option('host'))->validator(static function($value) {
142-
return is_string($value);
143-
})->setDefaultValue('localhost'),
144-
145-
(new Option('username'))->validator(static function($value) {
146-
return is_string($value);
147-
})->setDefaultValue('root'),
148-
149-
(new Option('password'))->validator(static function($value) {
150-
return is_string($value);
151-
})->setDefaultValue('root'),
152-
153-
(new Option('dbname'))->validator(static function($value) {
154-
return is_string($value);
155-
})->setDefaultValue('app'),
156-
157-
(new Option('driver'))->validator(static function($value) {
158-
return in_array($value, ['pdo_mysql', 'pdo_pgsql']);
159-
})->setDefaultValue('pdo_mysql'),
159+
Option::string('host')->setOptional('localhost'),
160+
Option::string('username')->required(),
161+
Option::string('password')->required(),
162+
Option::string('dbname')->required(),
163+
Option::int('port')->setOptional(3306),
160164
]);
161165

162-
try {
163-
$this->options = $resolver->resolve($options);
164-
} catch (InvalidArgumentException $e) {
165-
throw new InvalidArgumentException("Error: " . $e->getMessage());
166-
}
166+
$this->options = $resolver->resolve($options);
167167
}
168168
}
169169

170-
// Example usage with an invalid driver value:
170+
// Exemple d'utilisation :
171171
try {
172172
$database = new Database([
173-
'host' => '192.168.1.200',
174173
'username' => 'root',
175-
'password' => 'root',
176-
'dbname' => 'my-app',
177-
'driver' => 'pdo_sqlite',
174+
'password' => 'secret',
175+
'dbname' => 'app_db',
178176
]);
177+
// 'host' vaudra 'localhost' et 'port' vaudra 3306
179178
} catch (InvalidArgumentException $e) {
180-
echo "Error: " . $e->getMessage(); // Displays: "Error: The option 'driver' with value 'pdo_sqlite' is invalid."
179+
echo "Erreur : " . $e->getMessage();
181180
}
182181
```
183182

184-
Certainly! Let's focus specifically on the use of `Option::new()` to instantiate options in a fluent manner:
183+
### Types Disponibles
185184

186-
---
187185

188-
## Instantiating Options with `Option::new()`
189186

190-
You can use `Option::new()` to create and configure option instances in a fluent style before adding them to the `OptionsResolver`. Here's an example that demonstrates this approach:
187+
La classe `Option` fournit plusieurs méthodes statiques pour forcer les types automatiquement. Voici des exemples pour chaque type :
191188

189+
#### Chaîne de caractères (String)
192190
```php
193-
<?php
191+
Option::string('host')->setOptional('localhost');
192+
```
194193

195-
use PhpDevCommunity\Resolver\Option;
196-
use PhpDevCommunity\Resolver\OptionsResolver;
194+
#### Entier (Integer)
195+
```php
196+
Option::int('port')->setOptional(3306);
197+
```
198+
199+
#### Flottant (Float)
200+
```php
201+
Option::float('timeout')->setOptional(2.5);
202+
```
203+
204+
#### Booléen (Boolean)
205+
```php
206+
Option::bool('active')->setOptional(true);
207+
```
208+
209+
#### Tableau (Array)
210+
```php
211+
Option::array('tags')->setOptional(['php', 'library']);
212+
```
213+
214+
#### Itérable (Iterable)
215+
```php
216+
Option::iterable('items')->required();
217+
```
218+
219+
#### Mixte (Mixed - Pas de vérification de type)
220+
```php
221+
Option::mixed('metadata')->setOptional(null);
222+
```
223+
224+
### Requis vs Optionnel
197225

198-
// Create an option instance using Option::new()
199-
$option1 = Option::new('option1');
226+
* **Requis** : Utilisez `required()` pour obliger l'utilisateur à fournir une option. Si elle est manquante, une exception est levée.
227+
* **Optionnel** : Utilisez `setOptional($defaultValue)` pour définir une valeur par défaut si l'option n'est pas fournie.
200228

201-
// Create another option instance with a default value using Option::new()
202-
$option2 = Option::new('option2')->setDefaultValue('default');
229+
```php
230+
Option::string('apiKey')->required(); // Doit être fourni
231+
Option::bool('debug')->setOptional(false); // Vaut false par défaut si absent
232+
```
203233

204-
// Create a resolver and add the configured options
205-
$resolver = new OptionsResolver([$option1, $option2]);
234+
### Validation Personnalisée
206235

207-
// Resolve the options with provided values
208-
$options = $resolver->resolve([
209-
'option1' => 'value1',
210-
]);
236+
Vous pouvez ajouter une logique de validation personnalisée via la méthode `validator()`. La closure doit retourner un `bool`.
211237

238+
```php
239+
Option::string('driver')
240+
->setOptional('mysql')
241+
->validator(function ($value) {
242+
return in_array($value, ['mysql', 'pgsql', 'sqlite']);
243+
});
212244
```
213245

214-
In this example:
246+
### Gestion des Erreurs
247+
248+
La méthode `resolve()` lance une `InvalidArgumentException` si :
249+
* Une option requise est manquante.
250+
* Une option non définie est fournie.
251+
* Une valeur d'option est invalide (mauvais type ou échec de validation personnalisée).
215252

216-
- We use `Option::new('option1')` to create an `Option` instance named `'option1'`.
217-
- Similarly, we use `Option::new('option2')->setDefaultValue('default')` to create an `Option` instance named `'option2'` with a default value of `'default'`.
218-
- Both options are then added to the `OptionsResolver` when it's instantiated.
219-
- Finally, we resolve the options by passing an array of values, and only `'option1'` is provided with a value (`'value1'`).
253+
### Licence
220254

221-
Using `Option::new()` provides a concise and clear way to create and configure option instances before resolving them with specific values.
255+
Ce projet est sous licence MIT. Voir le fichier [LICENSE](LICENSE) pour plus de détails.

0 commit comments

Comments
 (0)