Skip to content

Commit 2514614

Browse files
committed
Refactor integer types and namespaces; migrate to custom Assert and TypeException classes
- Renamed and reorganized namespaces for consistency, removing redundant prefixes. - Replaced usage of `Webmozart\Assert` with a custom `Assert` class for tailored integer validations. - Introduced and standardized the `TypeException` class across all integer types. - Refactored `PositiveInt`, `NonNegativeInt`, and `WeekDayInt` to improve validation strictness and handling. - Enhanced test cases with additional scenarios and updated exception expectations. - Updated documentation (`README.md`, `INSTALL.md`, `USAGE.md`) to align with the new structure and behavior. - Adjusted `composer.json` and `composer.lock` to reflect dependency changes. - Improved autoloading and refined the `psalm.xml` configuration for better static analysis.
1 parent bc7fcff commit 2514614

24 files changed

+433
-167
lines changed

README.md

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Typed value objects for common PHP data types. Make primitives explicit, safe, a
99

1010
Quick links:
1111
- Install: docs/INSTALL.md
12+
- Usage: docs/USAGE.md
1213
- Development: docs/DEVELOP.md
1314

1415
Install
@@ -26,22 +27,32 @@ Usage
2627
Create and use typed integers with validation built in.
2728

2829
```php
29-
use GeorgiiWeb\\PhpTypedValues\\Types\\Integer\\PositiveInt;
30-
use GeorgiiWeb\\PhpTypedValues\\Types\\Integer\\NonNegativeInt;
31-
use GeorgiiWeb\\PhpTypedValues\\Types\\Integer\\Nullable\\PositiveIntOrNull;
30+
use PhpTypedValues\\Integer\\PositiveInt;
31+
use PhpTypedValues\\Integer\\NonNegativeInt;
32+
use PhpTypedValues\\Integer\\WeekDayInt;
33+
use PhpTypedValues\\Integer\\Integer;
3234

33-
$age = new PositiveInt(27); // ok
34-
$retries = new NonNegativeInt(0); // ok
35+
$age = new PositiveInt(27); // ok (positive-int)
36+
$retries = new NonNegativeInt(0); // ok (0 or positive)
37+
$weekday = new WeekDayInt(5); // ok (1..7)
38+
$any = new Integer(-42); // ok (any integer)
3539

36-
// Nullable wrapper: accepts PositiveInt or null semantics
37-
$maybeCount = new PositiveIntOrNull(null); // ok
38-
$maybeCount = new PositiveIntOrNull(5); // ok
40+
// Construct from string
41+
$fromString = PositiveInt::fromString('123');
3942

4043
// Access the underlying scalar value
4144
$ageValue = $age->value(); // 27
45+
echo $weekday->toString(); // "5"
4246
```
4347

44-
All value objects are immutable; invalid input throws an InvalidArgumentException.
48+
All value objects are immutable; invalid input throws an exception with a helpful message.
49+
50+
Provided integer types (so far):
51+
52+
- Integer — any PHP integer
53+
- PositiveInt — positive integer (> 0)
54+
- NonNegativeInt — zero or positive integer (>= 0)
55+
- WeekDayInt — integer in range 1..7
4556

4657
Why
4758
---

composer.json

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,14 @@
44
"type": "library",
55
"license": "MIT",
66
"require": {
7-
"php": ">=8.2",
8-
"webmozart/assert": "^1.12"
7+
"php": ">=8.2"
8+
},
9+
"require-dev": {
10+
"friendsofphp/php-cs-fixer": "^v3.89",
11+
"pestphp/pest": "^v3.8.4",
12+
"pestphp/pest-plugin-type-coverage": "^v3.6",
13+
"phpunit/phpunit": "^11.5",
14+
"vimeo/psalm": "^6.13.1"
915
},
1016
"autoload": {
1117
"psr-4": {
@@ -17,13 +23,6 @@
1723
"PhpTypedValues\\Tests\\": "tests/"
1824
}
1925
},
20-
"require-dev": {
21-
"friendsofphp/php-cs-fixer": "^v3.89",
22-
"pestphp/pest": "^v3.8.4",
23-
"pestphp/pest-plugin-type-coverage": "^v3.6",
24-
"phpunit/phpunit": "^11.5",
25-
"vimeo/psalm": "^6.13.1"
26-
},
2726
"scripts": {
2827
"sca": [
2928
"vendor/bin/psalm --no-cache --config=psalm.xml --diff --show-info=false --threads=2 --no-cache"

composer.lock

Lines changed: 60 additions & 61 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/INSTALL.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ composer require georgii-web/php-typed-values
1919
That’s it. Composer will autoload classes under the namespace:
2020

2121
```
22-
GeorgiiWeb\PhpTypedValues
22+
PhpTypedValues
2323
```
2424

2525
Quick verification
@@ -31,7 +31,7 @@ Create a quick test script (e.g., demo.php):
3131
<?php
3232
require __DIR__ . '/vendor/autoload.php';
3333

34-
use GeorgiiWeb\PhpTypedValues\Types\Integer\PositiveInt;
34+
use PhpTypedValues\Integer\PositiveInt;
3535

3636
$age = new PositiveInt(21);
3737
echo $age->value(); // 21

docs/USAGE.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
Usage
2+
=====
3+
4+
This page shows concise, up-to-date examples for the available integer value objects.
5+
6+
Namespaces
7+
----------
8+
9+
All classes live under the base namespace:
10+
11+
```
12+
PhpTypedValues
13+
```
14+
15+
Available integer types
16+
-----------------------
17+
18+
- PhpTypedValues\Integer\Integer — any PHP integer
19+
- PhpTypedValues\Integer\PositiveInt — positive integer (> 0)
20+
- PhpTypedValues\Integer\NonNegativeInt — zero or positive integer (>= 0)
21+
- PhpTypedValues\Integer\WeekDayInt — integer in range 1..7
22+
23+
Quick start
24+
-----------
25+
26+
```php
27+
use PhpTypedValues\Integer\Integer;
28+
use PhpTypedValues\Integer\NonNegativeInt;
29+
use PhpTypedValues\Integer\PositiveInt;
30+
use PhpTypedValues\Integer\WeekDayInt;
31+
32+
$any = new Integer(-10); // ok
33+
$pos = new PositiveInt(1); // ok
34+
$nn = new NonNegativeInt(0); // ok
35+
$wd = new WeekDayInt(7); // ok (1..7)
36+
37+
// From string
38+
$posFromString = PositiveInt::fromString('123');
39+
40+
// Accessing the raw value and string form
41+
echo $pos->value(); // 1
42+
echo $wd->toString(); // "7"
43+
```
44+
45+
Validation errors
46+
-----------------
47+
48+
Invalid input throws an exception with a helpful message.
49+
50+
```php
51+
use PhpTypedValues\Integer\PositiveInt;
52+
53+
new PositiveInt(0); // throws: Value must be a positive integer
54+
PositiveInt::fromString('12.3'); // throws: String has no valid integer
55+
```
56+
57+
Notes
58+
-----
59+
60+
- All value objects are immutable (readonly) and type-safe.
61+
- Utility constructors: fromInt(int) and fromString(string) are provided where applicable.

phpunit.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,8 @@
1919
<include>
2020
<directory>src</directory>
2121
</include>
22+
<exclude>
23+
<file>src/psalmTest.php</file>
24+
</exclude>
2225
</source>
2326
</phpunit>

src/Code/Assert/Assert.php

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpTypedValues\Code\Assert;
6+
7+
use PhpTypedValues\Code\Exception\TypeException;
8+
9+
use function is_numeric;
10+
11+
final class Assert
12+
{
13+
/**
14+
* @throws TypeException
15+
*/
16+
public static function greaterThanEq(int|float $value, int|float $min, string $message = ''): void
17+
{
18+
if ($value < $min) {
19+
throw new TypeException($message !== '' ? $message : 'Expected a value greater than or equal to the minimum');
20+
}
21+
}
22+
23+
/**
24+
* @throws TypeException
25+
*/
26+
public static function lessThanEq(int|float $value, int|float $max, string $message = ''): void
27+
{
28+
if ($value > $max) {
29+
throw new TypeException($message !== '' ? $message : 'Expected a value less than or equal to the maximum');
30+
}
31+
}
32+
33+
// /**
34+
// * @throws TypeException
35+
// */
36+
// public static function greaterThan(int|float $value, int|float $min, string $message = ''): void
37+
// {
38+
// if ($value <= $min) {
39+
// throw new TypeException($message !== '' ? $message : 'Expected a value greater than the minimum');
40+
// }
41+
// }
42+
//
43+
// /**
44+
// * @throws TypeException
45+
// */
46+
// public static function lessThan(int|float $value, int|float $max, string $message = ''): void
47+
// {
48+
// if ($value >= $max) {
49+
// throw new TypeException($message !== '' ? $message : 'Expected a value less than the maximum');
50+
// }
51+
// }
52+
53+
/**
54+
* Assert that the given value looks like an integer ("integerish").
55+
* Accepts numeric strings that represent an integer value (e.g., '5', '5.0'),
56+
* but rejects non-numeric strings and floats with a fractional part (e.g., '5.5').
57+
*
58+
* @throws TypeException
59+
*/
60+
public static function integerish(mixed $value, string $message = ''): void
61+
{
62+
if (!is_numeric($value) || $value != (int) $value) {
63+
throw new TypeException($message !== '' ? $message : 'Expected an "integerish" value');
64+
}
65+
}
66+
}
Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,22 @@
22

33
declare(strict_types=1);
44

5-
namespace PhpTypedValues\BaseType;
5+
namespace PhpTypedValues\Code\BaseType;
66

7-
use PhpTypedValues\Contract\IntTypeInterface;
8-
use Webmozart\Assert\Assert;
7+
use PhpTypedValues\Code\Assert\Assert;
8+
use PhpTypedValues\Code\Contract\IntTypeInterface;
9+
use PhpTypedValues\Code\Exception\TypeException;
910

1011
/**
1112
* @psalm-immutable
1213
*/
1314
abstract readonly class BaseIntType implements IntTypeInterface
1415
{
16+
/**
17+
* @throws TypeException
18+
*/
1519
protected static function assertNumericString(string $value): void
1620
{
17-
// Assert::numeric($value, 'String has no valid integer');
1821
Assert::integerish($value, 'String has no valid integer');
1922
}
2023

0 commit comments

Comments
 (0)