Skip to content

Commit a0d761c

Browse files
committed
uses nette/phpstan-rules
1 parent 63179c5 commit a0d761c

6 files changed

Lines changed: 78 additions & 11 deletions

File tree

composer.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@
2121
"require-dev": {
2222
"nette/tester": "^2.6",
2323
"tracy/tracy": "^2.8",
24-
"phpstan/phpstan-nette": "^2.0@stable"
24+
"phpstan/phpstan": "^2.1@stable",
25+
"phpstan/extension-installer": "^1.4@stable",
26+
"nette/phpstan-rules": "^1.0"
2527
},
2628
"autoload": {
2729
"classmap": ["src/"],
@@ -38,5 +40,10 @@
3840
"branch-alias": {
3941
"dev-master": "1.3-dev"
4042
}
43+
},
44+
"config": {
45+
"allow-plugins": {
46+
"phpstan/extension-installer": true
47+
}
4148
}
4249
}

phpstan.neon

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
parameters:
22
level: 8
3-
checkMissingIterableValueType: false
4-
errorFormat: raw
53

64
paths:
75
- src
8-
9-
includes:
10-
- vendor/phpstan/phpstan-nette/extension.neon

src/Schema/Expect.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,8 @@ public static function from(object $object, array $items = []): Structure
7070
: $ro->getProperties();
7171

7272
foreach ($props as $prop) {
73-
$item = &$items[$prop->getName()];
74-
if (!$item) {
73+
$name = $prop->getName();
74+
if (!isset($items[$name])) {
7575
$type = Helpers::getPropertyType($prop) ?? 'mixed';
7676
$item = new Type($type);
7777
if ($prop instanceof \ReflectionProperty ? $prop->isInitialized($object) : $prop->isOptional()) {
@@ -86,6 +86,7 @@ public static function from(object $object, array $items = []): Structure
8686
} else {
8787
$item->required();
8888
}
89+
$items[$name] = $item;
8990
}
9091
}
9192

@@ -98,7 +99,8 @@ public static function from(object $object, array $items = []): Structure
9899
*/
99100
public static function array(?array $shape = []): Structure|Type
100101
{
101-
return Nette\Utils\Arrays::first($shape ?? []) instanceof Schema
102+
$shape ??= [];
103+
return Nette\Utils\Arrays::first($shape) instanceof Schema
102104
? (new Structure($shape))->castTo('array')
103105
: (new Type('array'))->default($shape);
104106
}

src/Schema/Message.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
namespace Nette\Schema;
99

10-
use Nette;
1110
use function implode, preg_replace_callback;
1211

1312

@@ -85,6 +84,6 @@ public function toString(): string
8584
return preg_replace_callback('~( ?)%(\w+)%~', function ($m) use ($vars) {
8685
[, $space, $key] = $m;
8786
return $vars[$key] === null ? '' : $space . $vars[$key];
88-
}, $this->message) ?? throw new Nette\InvalidStateException(preg_last_error_msg());
87+
}, $this->message);
8988
}
9089
}

tests/types/schema-types.php

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php declare(strict_types=1);
2+
3+
/**
4+
* PHPStan type tests.
5+
*/
6+
7+
use Nette\Schema\Elements\AnyOf;
8+
use Nette\Schema\Elements\Structure;
9+
use Nette\Schema\Elements\Type;
10+
use Nette\Schema\Expect;
11+
use function PHPStan\Testing\assertType;
12+
13+
14+
// Magic methods return Type
15+
assertType(Type::class, Expect::string());
16+
assertType(Type::class, Expect::int());
17+
assertType(Type::class, Expect::bool());
18+
assertType(Type::class, Expect::float());
19+
assertType(Type::class, Expect::scalar());
20+
assertType(Type::class, Expect::null());
21+
assertType(Type::class, Expect::mixed());
22+
assertType(Type::class, Expect::list());
23+
assertType(Type::class, Expect::email());
24+
assertType(Type::class, Expect::unicode());
25+
26+
// Explicit type creation
27+
assertType(Type::class, Expect::type('string'));
28+
assertType(Type::class, Expect::arrayOf('string'));
29+
assertType(Type::class, Expect::listOf('string'));
30+
31+
// Structure creation
32+
assertType(Structure::class, Expect::structure(['a' => Expect::string()]));
33+
assertType(Structure::class, Expect::from(new stdClass));
34+
35+
// AnyOf creation
36+
assertType(AnyOf::class, Expect::anyOf('a', 'b'));
37+
38+
// Expect::array() conditional return (via PHPStan extension)
39+
assertType(Type::class, Expect::array());
40+
assertType(Type::class, Expect::array([]));
41+
assertType(Structure::class, Expect::array(['a' => Expect::string()]));
42+
43+
// Fluent methods preserve concrete type
44+
assertType(Type::class, Expect::string()->required());
45+
assertType(Type::class, Expect::string()->nullable());
46+
assertType(Type::class, Expect::string()->default('foo'));
47+
assertType(Type::class, Expect::int()->min(0)->max(100));
48+
49+
assertType(Structure::class, Expect::structure([])->required());
50+
assertType(Structure::class, Expect::structure([])->otherItems('string'));
51+
assertType(Structure::class, Expect::structure([])->skipDefaults());
52+
53+
assertType(AnyOf::class, Expect::anyOf('a', 'b')->required());
54+
assertType(AnyOf::class, Expect::anyOf('a', 'b')->firstIsDefault());
55+
56+
// Structure::extend() returns Structure
57+
assertType(Structure::class, Expect::structure([])->extend(['b' => Expect::int()]));

tests/types/types.phpt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php declare(strict_types=1);
2+
3+
require __DIR__ . '/../bootstrap.php';
4+
5+
use Nette\PHPStan\Tester\TypeAssert;
6+
7+
TypeAssert::assertTypes(__DIR__ . '/schema-types.php');

0 commit comments

Comments
 (0)