Skip to content

Commit fff30af

Browse files
Initial commit for phpdevcommunity/php-options-resolver: a library for processing and validating option arrays in PHP
0 parents  commit fff30af

11 files changed

+696
-0
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/vendor/
2+
/.vscode/
3+
/.idea/

LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2021 F. Michel
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

+221
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
# Option Array Processing and Validation Library
2+
3+
This library provides a simple solution for processing and validating option arrays in PHP.
4+
5+
## Installation
6+
7+
To install this library, use [Composer](https://getcomposer.org/)
8+
9+
### Run the following Composer command:
10+
11+
```bash
12+
composer require phpdevcommunity/php-options-resolver
13+
```
14+
15+
## Requirements
16+
17+
* PHP version 7.4 or higher
18+
19+
### Defining Required Options
20+
21+
Define the required options for your class using `OptionsResolver` with the expected options:
22+
23+
```php
24+
<?php
25+
26+
use PhpDevCommunity\Resolver\Option;
27+
use PhpDevCommunity\Resolver\OptionsResolver;
28+
29+
class Database
30+
{
31+
public function __construct(array $options = [])
32+
{
33+
$resolver = new OptionsResolver([
34+
new Option('host'),
35+
new Option('username'),
36+
new Option('password'),
37+
new Option('dbname'),
38+
]);
39+
40+
try {
41+
$this->options = $resolver->resolve($options);
42+
} catch (InvalidArgumentException $e) {
43+
throw new InvalidArgumentException("Error: " . $e->getMessage());
44+
}
45+
}
46+
}
47+
48+
// Example usage:
49+
try {
50+
$database = new Database([
51+
'host' => 'localhost',
52+
'dbname' => 'app',
53+
]);
54+
} catch (InvalidArgumentException $e) {
55+
echo "Error: " . $e->getMessage(); // Displays: "Error: The required option 'username' is missing."
56+
}
57+
```
58+
59+
### Defining Default Options
60+
61+
You can also set default values for your options using `setDefaultValue` for each option:
62+
63+
```php
64+
<?php
65+
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+
]);
76+
77+
$this->options = $resolver->resolve($options);
78+
}
79+
}
80+
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+
// }
91+
```
92+
93+
### Handling Non-existent Options
94+
95+
If a provided option does not exist in the defined list of options, an `InvalidArgumentException` will be thrown:
96+
97+
```php
98+
<?php
99+
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+
]);
110+
111+
try {
112+
$this->options = $resolver->resolve($options);
113+
} catch (InvalidArgumentException $e) {
114+
throw new InvalidArgumentException("Error: " . $e->getMessage());
115+
}
116+
}
117+
}
118+
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+
}
127+
```
128+
129+
### Validating Option Values
130+
131+
You can add custom validators for each option to validate the provided values:
132+
133+
```php
134+
<?php
135+
136+
class Database
137+
{
138+
public function __construct(array $options = [])
139+
{
140+
$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'),
160+
]);
161+
162+
try {
163+
$this->options = $resolver->resolve($options);
164+
} catch (InvalidArgumentException $e) {
165+
throw new InvalidArgumentException("Error: " . $e->getMessage());
166+
}
167+
}
168+
}
169+
170+
// Example usage with an invalid driver value:
171+
try {
172+
$database = new Database([
173+
'host' => '192.168.1.200',
174+
'username' => 'root',
175+
'password' => 'root',
176+
'dbname' => 'my-app',
177+
'driver' => 'pdo_sqlite',
178+
]);
179+
} catch (InvalidArgumentException $e) {
180+
echo "Error: " . $e->getMessage(); // Displays: "Error: The option 'driver' with value 'pdo_sqlite' is invalid."
181+
}
182+
```
183+
184+
Certainly! Let's focus specifically on the use of `Option::new()` to instantiate options in a fluent manner:
185+
186+
---
187+
188+
## Instantiating Options with `Option::new()`
189+
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:
191+
192+
```php
193+
<?php
194+
195+
use PhpDevCommunity\Resolver\Option;
196+
use PhpDevCommunity\Resolver\OptionsResolver;
197+
198+
// Create an option instance using Option::new()
199+
$option1 = Option::new('option1');
200+
201+
// Create another option instance with a default value using Option::new()
202+
$option2 = Option::new('option2')->setDefaultValue('default');
203+
204+
// Create a resolver and add the configured options
205+
$resolver = new OptionsResolver([$option1, $option2]);
206+
207+
// Resolve the options with provided values
208+
$options = $resolver->resolve([
209+
'option1' => 'value1',
210+
]);
211+
212+
```
213+
214+
In this example:
215+
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'`).
220+
221+
Using `Option::new()` provides a concise and clear way to create and configure option instances before resolving them with specific values.

composer.json

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"name": "phpdevcommunity/php-options-resolver",
3+
"description": "This library provides a simple solution for processing and validating option arrays in PHP.",
4+
"type": "library",
5+
"license": "MIT",
6+
"authors": [
7+
{
8+
"name": "F. Michel",
9+
"homepage": "https://www.phpdevcommunity.com"
10+
}
11+
],
12+
"autoload": {
13+
"psr-4": {
14+
"PhpDevCommunity\\Resolver\\": "src",
15+
"Test\\PhpDevCommunity\\Resolver\\": "tests"
16+
17+
}
18+
},
19+
"minimum-stability": "alpha",
20+
"require": {
21+
"php": ">=7.4"
22+
},
23+
"require-dev": {
24+
"phpdevcommunity/unitester": "^0.1.0@alpha"
25+
}
26+
}

src/Option.php

+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpDevCommunity\Resolver;
6+
7+
final class Option
8+
{
9+
/**
10+
* @var string
11+
*/
12+
private string $name;
13+
14+
/**
15+
* @var mixed
16+
*/
17+
private $defaultValue;
18+
19+
/**
20+
* @var bool
21+
*/
22+
private bool $hasDefaultValue = false;
23+
24+
/**
25+
* @var \Closure|null
26+
*/
27+
private ?\Closure $validator = null;
28+
29+
/**
30+
* Option constructor.
31+
* @param string $name
32+
*/
33+
public function __construct(string $name)
34+
{
35+
$this->name = $name;
36+
}
37+
38+
public function getName(): string
39+
{
40+
return $this->name;
41+
}
42+
43+
/**
44+
* @return mixed
45+
*/
46+
public function getDefaultValue()
47+
{
48+
return $this->defaultValue;
49+
}
50+
51+
/**
52+
* Set the default value of the option.
53+
*
54+
* @param mixed $value The default value to set.
55+
* @return Option
56+
*/
57+
public function setDefaultValue($value): self
58+
{
59+
$this->hasDefaultValue = true;
60+
$this->defaultValue = $value;
61+
return $this;
62+
}
63+
64+
65+
/**
66+
* Check if the option has a default value.
67+
*
68+
* @return bool True if the option has a default value, false otherwise.
69+
*/
70+
public function hasDefaultValue(): bool
71+
{
72+
return $this->hasDefaultValue;
73+
}
74+
75+
/**
76+
* Set a validator function for the option.
77+
*
78+
* @param \Closure $closure The closure to use as a validator.
79+
* @return Option
80+
*/
81+
public function validator(\Closure $closure): self
82+
{
83+
$this->validator = $closure;
84+
return $this;
85+
}
86+
87+
/**
88+
* Check if a value is valid based on the validator function.
89+
*
90+
* @param mixed $value The value to validate.
91+
* @return bool True if the value is valid, false otherwise.
92+
*/
93+
public function isValid($value): bool
94+
{
95+
if ($this->validator instanceof \Closure) {
96+
$validator = $this->validator;
97+
return $validator($value);
98+
}
99+
return true;
100+
}
101+
102+
public static function new(string $name) : self
103+
{
104+
return new self($name);
105+
}
106+
}

0 commit comments

Comments
 (0)