Skip to content

Commit 56139a0

Browse files
committed
Merge branch 'release/0.7.9'
2 parents 3bc1198 + 812d021 commit 56139a0

7 files changed

Lines changed: 268 additions & 21 deletions

File tree

.github/workflows/ci.yml

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,30 +5,29 @@ on: [push]
55
jobs:
66
build-test:
77
runs-on: ubuntu-latest
8-
container:
9-
image: php:8.4 # This forces the job to run in a Docker container
108

119
steps:
1210
- name: Checkout
1311
uses: actions/checkout@v3
1412

15-
- name: Install System Dependencies (Git, Zip, Unzip)
16-
run: |
17-
apt-get update
18-
apt-get install -y unzip git zip
19-
20-
- name: Install and Enable extensions
21-
run: |
22-
docker-php-ext-install sockets calendar
23-
docker-php-ext-enable sockets calendar
24-
25-
- name: Install Composer
26-
run: |
27-
curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
28-
composer --version
13+
- name: Setup PHP
14+
uses: shivammathur/setup-php@v2
15+
with:
16+
php-version: 8.4
17+
extensions: sockets, calendar, pcov
18+
coverage: pcov
2919

3020
- name: Install Dependencies
31-
run: composer install --prefer-dist --no-progress
32-
33-
- name: Run PHPUnit
34-
run: vendor/bin/phpunit tests
21+
run: composer install --prefer-dist --no-progress --no-interaction --optimize-autoloader
22+
23+
- name: Run PHPUnit with Coverage
24+
run: vendor/bin/phpunit tests --coverage-clover coverage.xml --coverage-filter src
25+
26+
- name: Upload coverage to Codecov
27+
uses: codecov/codecov-action@v5
28+
with:
29+
token: ${{ secrets.CODECOV_TOKEN }}
30+
files: ./coverage.xml
31+
flags: validation
32+
slug: Neuron-PHP/validation
33+
fail_ci_if_error: true

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,5 @@ node_modules
77
.DS_STORE
88
public_html/
99
.phpunit.result.cache
10+
11+
coverage.xml

.version.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22
"strategy": "semver",
33
"major": 0,
44
"minor": 7,
5-
"patch": 8,
5+
"patch": 9,
66
"build": 0
77
}

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
[![CI](https://github.com/Neuron-PHP/validation/actions/workflows/ci.yml/badge.svg)](https://github.com/Neuron-PHP/validation/actions)
2+
[![codecov](https://codecov.io/gh/Neuron-PHP/validation/branch/develop/graph/badge.svg)](https://codecov.io/gh/Neuron-PHP/validation)
23
# Neuron-PHP Validation
34

45
## Overview

VERSIONLOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
## 0.7.9 2025-12-27
2+
* Added IsInSet.
3+
14
## 0.7.8 2025-11-28
25

36
## 0.7.7 2025-11-18

src/Validation/IsInSet.php

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
<?php
2+
3+
namespace Neuron\Validation;
4+
5+
/**
6+
* Validates that a value is within a predefined set of allowed values.
7+
*
8+
* This validator is commonly used for enum-like validations where a value
9+
* must be one of a specific set of allowed options. It supports both strict
10+
* and loose comparison modes.
11+
*
12+
* @package Neuron\Validation
13+
*
14+
* @example
15+
* ```php
16+
* // Validate user role
17+
* $roleValidator = new IsInSet(['admin', 'editor', 'author', 'subscriber']);
18+
* $roleValidator->isValid('admin'); // true
19+
* $roleValidator->isValid('moderator'); // false
20+
*
21+
* // Validate with loose comparison
22+
* $statusValidator = new IsInSet([1, 2, 3], false);
23+
* $statusValidator->isValid('2'); // true (loose comparison)
24+
* ```
25+
*/
26+
class IsInSet extends Base
27+
{
28+
private array $_allowedValues;
29+
private bool $_strict;
30+
31+
/**
32+
* @param array $allowedValues Array of allowed values
33+
* @param bool $strict Whether to use strict comparison (default: true)
34+
*/
35+
public function __construct( array $allowedValues, bool $strict = true )
36+
{
37+
$this->_allowedValues = $allowedValues;
38+
$this->_strict = $strict;
39+
parent::__construct();
40+
}
41+
42+
/**
43+
* Get the array of allowed values.
44+
*
45+
* @return array
46+
*/
47+
public function getAllowedValues(): array
48+
{
49+
return $this->_allowedValues;
50+
}
51+
52+
/**
53+
* Set the array of allowed values.
54+
*
55+
* @param array $allowedValues
56+
* @return void
57+
*/
58+
public function setAllowedValues( array $allowedValues ): void
59+
{
60+
$this->_allowedValues = $allowedValues;
61+
}
62+
63+
/**
64+
* Check if strict comparison is enabled.
65+
*
66+
* @return bool
67+
*/
68+
public function isStrict(): bool
69+
{
70+
return $this->_strict;
71+
}
72+
73+
/**
74+
* Set whether to use strict comparison.
75+
*
76+
* @param bool $strict
77+
* @return void
78+
*/
79+
public function setStrict( bool $strict ): void
80+
{
81+
$this->_strict = $strict;
82+
}
83+
84+
/**
85+
* Validates that the value is in the allowed set.
86+
*
87+
* @param mixed $value
88+
* @return bool
89+
*/
90+
protected function validate( mixed $value ): bool
91+
{
92+
return in_array( $value, $this->_allowedValues, $this->_strict );
93+
}
94+
}
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
<?php
2+
namespace Tests\Data\Validation;
3+
4+
use Neuron\Validation\IsInSet;
5+
use PHPUnit\Framework\TestCase;
6+
7+
class InSetTest extends TestCase
8+
{
9+
public function testPassWithStringInSet()
10+
{
11+
$validator = new IsInSet( ['admin', 'editor', 'author', 'subscriber'] );
12+
13+
$this->assertTrue( $validator->isValid( 'admin' ) );
14+
$this->assertTrue( $validator->isValid( 'editor' ) );
15+
$this->assertTrue( $validator->isValid( 'author' ) );
16+
$this->assertTrue( $validator->isValid( 'subscriber' ) );
17+
}
18+
19+
public function testFailWithStringNotInSet()
20+
{
21+
$validator = new IsInSet( ['admin', 'editor', 'author'] );
22+
23+
$this->assertFalse( $validator->isValid( 'moderator' ) );
24+
$this->assertFalse( $validator->isValid( 'superadmin' ) );
25+
$this->assertFalse( $validator->isValid( '' ) );
26+
}
27+
28+
public function testStrictComparisonCaseSensitive()
29+
{
30+
$validator = new IsInSet( ['admin', 'editor'] );
31+
32+
$this->assertTrue( $validator->isValid( 'admin' ) );
33+
$this->assertFalse( $validator->isValid( 'ADMIN' ) );
34+
$this->assertFalse( $validator->isValid( 'Admin' ) );
35+
}
36+
37+
public function testStrictComparisonTypeCheck()
38+
{
39+
$validator = new IsInSet( [1, 2, 3], true );
40+
41+
$this->assertTrue( $validator->isValid( 1 ) );
42+
$this->assertTrue( $validator->isValid( 2 ) );
43+
$this->assertFalse( $validator->isValid( '1' ) ); // String vs int
44+
$this->assertFalse( $validator->isValid( '2' ) );
45+
}
46+
47+
public function testLooseComparison()
48+
{
49+
$validator = new IsInSet( [1, 2, 3], false );
50+
51+
$this->assertTrue( $validator->isValid( 1 ) );
52+
$this->assertTrue( $validator->isValid( '1' ) ); // Loose comparison allows this
53+
$this->assertTrue( $validator->isValid( '2' ) );
54+
$this->assertTrue( $validator->isValid( 3 ) );
55+
$this->assertFalse( $validator->isValid( 4 ) );
56+
$this->assertFalse( $validator->isValid( '5' ) );
57+
}
58+
59+
public function testEmptySet()
60+
{
61+
$validator = new IsInSet( [] );
62+
63+
$this->assertFalse( $validator->isValid( 'anything' ) );
64+
$this->assertFalse( $validator->isValid( 1 ) );
65+
$this->assertFalse( $validator->isValid( null ) );
66+
}
67+
68+
public function testMixedTypes()
69+
{
70+
$validator = new IsInSet( ['active', 1, true, null], true );
71+
72+
$this->assertTrue( $validator->isValid( 'active' ) );
73+
$this->assertTrue( $validator->isValid( 1 ) );
74+
$this->assertTrue( $validator->isValid( true ) );
75+
$this->assertTrue( $validator->isValid( null ) );
76+
77+
$this->assertFalse( $validator->isValid( 'inactive' ) );
78+
$this->assertFalse( $validator->isValid( 2 ) );
79+
$this->assertFalse( $validator->isValid( false ) );
80+
}
81+
82+
public function testGetAllowedValues()
83+
{
84+
$allowedValues = ['red', 'green', 'blue'];
85+
$validator = new IsInSet( $allowedValues );
86+
87+
$this->assertEquals( $allowedValues, $validator->getAllowedValues() );
88+
}
89+
90+
public function testSetAllowedValues()
91+
{
92+
$validator = new IsInSet( ['old'] );
93+
94+
$newValues = ['new1', 'new2', 'new3'];
95+
$validator->setAllowedValues( $newValues );
96+
97+
$this->assertEquals( $newValues, $validator->getAllowedValues() );
98+
$this->assertTrue( $validator->isValid( 'new1' ) );
99+
$this->assertFalse( $validator->isValid( 'old' ) );
100+
}
101+
102+
public function testIsStrict()
103+
{
104+
$strictValidator = new IsInSet( [1, 2, 3], true );
105+
$looseValidator = new IsInSet( [1, 2, 3], false );
106+
107+
$this->assertTrue( $strictValidator->isStrict() );
108+
$this->assertFalse( $looseValidator->isStrict() );
109+
}
110+
111+
public function testSetStrict()
112+
{
113+
$validator = new IsInSet( [1, 2, 3], true );
114+
115+
$this->assertTrue( $validator->isStrict() );
116+
$this->assertFalse( $validator->isValid( '1' ) );
117+
118+
$validator->setStrict( false );
119+
120+
$this->assertFalse( $validator->isStrict() );
121+
$this->assertTrue( $validator->isValid( '1' ) );
122+
}
123+
124+
public function testNullValue()
125+
{
126+
$validator = new IsInSet( ['a', 'b', null] );
127+
128+
$this->assertTrue( $validator->isValid( null ) );
129+
}
130+
131+
public function testBooleanValues()
132+
{
133+
$validator = new IsInSet( [true, false] );
134+
135+
$this->assertTrue( $validator->isValid( true ) );
136+
$this->assertTrue( $validator->isValid( false ) );
137+
$this->assertFalse( $validator->isValid( 1 ) ); // Strict: 1 !== true
138+
$this->assertFalse( $validator->isValid( 0 ) ); // Strict: 0 !== false
139+
}
140+
141+
public function testNumericStrings()
142+
{
143+
$validator = new IsInSet( ['1', '2', '3'], true );
144+
145+
$this->assertTrue( $validator->isValid( '1' ) );
146+
$this->assertFalse( $validator->isValid( 1 ) ); // Strict comparison
147+
}
148+
}

0 commit comments

Comments
 (0)