Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co

`bitapps/wp-validator` — a Composer library (PSR-4: `BitApps\WPValidator\` → [src/](src/)) providing Laravel-style validation and sanitization for WordPress. Public API and the full rule list are documented in [README.md](README.md); update it when adding a rule or sanitizer.

**PHP 7.2 is the floor.** No typed properties, no arrow functions, no null coalescing assignment, no union types. Return types on methods are used and fine. [rector.php](rector.php) pins `PhpVersion::PHP_72` and skips the typed-property rectors for this reason.
**PHP 7.4 is the floor.** No union types or other PHP 8+ syntax. Return types on methods are used and fine. [rector.php](rector.php) pins `PhpVersion::PHP_74` and skips the typed-property rectors.

## Commands

```bash
composer test:unit # full suite (Pest, --testdox, excludes group 'db')
./vendor/bin/pest tests/Rules/BetweenTest.php # single file
./vendor/bin/pest --filter='between accepts a length of zero' # single test by name
composer compat # PHPCompatibility check against PHP 7.2
composer compat # PHPCompatibility check against PHP 7.4
composer rector # Rector dry-run (never auto-applies)
```

Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
},

"require": {
"php": ">=7.2"
"php": ">=7.4"
},
"require-dev": {
"pestphp/pest": "^2.18",
Expand Down
4 changes: 2 additions & 2 deletions rector.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
->withPaths([
__DIR__ . '/src',
])
->withPhpVersion(PhpVersion::PHP_72)
->withPhpVersion(PhpVersion::PHP_74)
->withSkip([
UnwrapFutureCompatibleIfPhpVersionRector::class,
TypedPropertyFromStrictConstructorRector::class,
Expand All @@ -29,4 +29,4 @@
// strictBooleans: true,
// naming: true,
)
->withSets([SetList::PHP_72]);
->withSets([SetList::PHP_74]);
23 changes: 9 additions & 14 deletions src/InputDataContainer.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class InputDataContainer

private $data = [];

private $attributeKey;
private $attributeKey = '';

private $attributeLabel;

Expand All @@ -18,7 +18,7 @@ public function __construct($data = [])

public function setAttributeKey($key): void
{
$this->attributeKey = $key;
$this->attributeKey = $key ?? '';
}

public function getAttributeKey()
Expand All @@ -28,22 +28,17 @@ public function getAttributeKey()

public function getAttributeValue($key = null)
{
$keys = explode('.', trim($this->attributeKey ?? '', '[]'));

$data = $this->data;
$keys = explode('.', trim($this->attributeKey, '[]'));

if (count($keys) > 1) {
$data = $this->getValueFromPath($keys, $data);
} elseif ($key && isset($data[$key])) {
return $data[$key];
} elseif (isset($data[$this->attributeKey])) {
return $data[$this->attributeKey];
} else {
return null;
return $this->getValueFromPath($keys, $this->data);
}

return $data;
if ($key !== null && isset($this->data[$key])) {
return $this->data[$key];
}

return $this->data[$this->attributeKey] ?? null;
}

public function setAttributeLabel($value): void
Expand All @@ -63,7 +58,7 @@ public function getData()

public function setAttributeValue($value): void
{
$keys = explode('.', trim($this->attributeKey ?? '', '[]'));
$keys = explode('.', trim($this->attributeKey, '[]'));

if (\count($keys) > 1) {
$this->setNestedElement($this->data, $keys, $value);
Expand Down
104 changes: 104 additions & 0 deletions tests/InputDataContainerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<?php

use BitApps\WPValidator\InputDataContainer;
use BitApps\WPValidator\Rules\PresentRule;
use BitApps\WPValidator\Validator;

function collectDeprecations(callable $callback): array
{
$deprecations = [];

set_error_handler(function ($level, $message) use (&$deprecations) {
$deprecations[] = $message;

return true;
}, E_DEPRECATED);

try {
$callback();
} finally {
restore_error_handler();
}

return $deprecations;
}

test('getAttributeValue without a key does not use null as an array offset', function () {
$container = new InputDataContainer(['name' => 'John']);
$container->setAttributeKey('name');

$deprecations = collectDeprecations(function () use ($container) {
$container->getAttributeValue();
});

expect($deprecations)->toBe([]);
expect($container->getAttributeValue())->toBe('John');
});

test('getAttributeValue before an attribute key is set does not use null as an array offset', function () {
$container = new InputDataContainer(['name' => 'John']);

$deprecations = collectDeprecations(function () use ($container) {
$container->getAttributeValue();
});

expect($deprecations)->toBe([]);
expect($container->getAttributeValue())->toBeNull();
});

test('setAttributeValue before an attribute key is set does not use null as an array offset', function () {
$container = new InputDataContainer(['name' => 'John']);

$deprecations = collectDeprecations(function () use ($container) {
$container->setAttributeValue('Doe');
});

expect($deprecations)->toBe([]);
expect($container->getData())->toBe(['name' => 'John', '' => 'Doe']);
expect($container->getAttributeValue())->toBe('Doe');
});

test('a null attribute key does not use null as an array offset', function () {
$container = new InputDataContainer(['name' => 'John']);
$container->setAttributeKey(null);

$deprecations = collectDeprecations(function () use ($container) {
$container->getAttributeValue();
$container->setAttributeValue('Doe');
});

expect($deprecations)->toBe([]);
});

test('present rule before an attribute key is set does not use null as an array offset', function () {
$rule = new PresentRule();
$rule->setInputDataContainer(new InputDataContainer(['name' => 'John']));

$deprecations = collectDeprecations(function () use ($rule) {
$rule->validate('John');
});

expect($deprecations)->toBe([]);
});

test('getAttributeValue does not read an empty string key when called without a key', function () {
$container = new InputDataContainer(['' => 'wrong', 'name' => 'John']);
$container->setAttributeKey('name');

expect($container->getAttributeValue())->toBe('John');
});

test('getAttributeValue reads falsy explicit keys', function () {
$container = new InputDataContainer(['first', 'second']);
$container->setAttributeKey(1);

expect($container->getAttributeValue(0))->toBe('first');
expect($container->getAttributeValue('0'))->toBe('first');
});

test('same rule compares against a field named 0', function () {
$validator = new Validator();

expect($validator->make(['0' => 'secret', 'confirm' => 'wrong'], ['confirm' => ['same:0']])->fails())->toBeTrue();
expect($validator->make(['0' => 'secret', 'confirm' => 'secret'], ['confirm' => ['same:0']])->fails())->toBeFalse();
});
Loading