Skip to content

Commit 4352e84

Browse files
committed
Expect::from() removed support for phpDoc annotations (BC break)
1 parent 6b3f9e1 commit 4352e84

File tree

7 files changed

+39
-254
lines changed

7 files changed

+39
-254
lines changed

readme.md

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -485,12 +485,9 @@ You can generate structure schema from the class. Example:
485485
```php
486486
class Config
487487
{
488-
/** @var string */
489-
public $name;
490-
/** @var string|null */
491-
public $password;
492-
/** @var bool */
493-
public $admin = false;
488+
public string $name;
489+
public ?string $password;
490+
public bool $admin = false;
494491
}
495492

496493
$schema = Expect::from(new Config);
@@ -504,19 +501,6 @@ $normalized = $processor->process($schema, $data);
504501
// $normalized = {'name' => 'jeff', 'password' => null, 'admin' => false}
505502
```
506503

507-
If you are using PHP 7.4 or higher, you can use native types:
508-
509-
```php
510-
class Config
511-
{
512-
public string $name;
513-
public ?string $password;
514-
public bool $admin = false;
515-
}
516-
517-
$schema = Expect::from(new Config);
518-
```
519-
520504
Anonymous classes are also supported:
521505

522506
```php

src/Schema/Expect.php

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,11 @@ public static function from(object $object, array $items = []): Structure
7474
foreach ($props as $prop) {
7575
$item = &$items[$prop->getName()];
7676
if (!$item) {
77-
$type = Helpers::getPropertyType($prop) ?? 'mixed';
78-
$item = new Type($type);
77+
$item = new Type((string) (Nette\Utils\Type::fromReflection($prop) ?? 'mixed'));
7978
if ($prop instanceof \ReflectionProperty ? $prop->isInitialized($object) : $prop->isOptional()) {
8079
$def = ($prop instanceof \ReflectionProperty ? $prop->getValue($object) : $prop->getDefaultValue());
8180
if (is_object($def)) {
8281
$item = static::from($def);
83-
} elseif ($def === null && !Nette\Utils\Validators::is(null, $type)) {
84-
$item->required();
8582
} else {
8683
$item->default($def);
8784
}

src/Schema/Helpers.php

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
namespace Nette\Schema;
1111

1212
use Nette;
13-
use Nette\Utils\Reflection;
1413
use function count, explode, get_debug_type, implode, in_array, is_array, is_float, is_int, is_object, is_scalar, is_string, method_exists, preg_match, preg_quote, preg_replace, preg_replace_callback, settype, str_replace, strlen, trim, var_export;
1514

1615

@@ -56,41 +55,6 @@ public static function merge(mixed $value, mixed $base): mixed
5655
}
5756

5857

59-
public static function getPropertyType(\ReflectionProperty|\ReflectionParameter $prop): ?string
60-
{
61-
if ($type = Nette\Utils\Type::fromReflection($prop)) {
62-
return (string) $type;
63-
} elseif (
64-
($prop instanceof \ReflectionProperty)
65-
&& ($type = preg_replace('#\s.*#', '', (string) self::parseAnnotation($prop, 'var')))
66-
) {
67-
$class = Reflection::getPropertyDeclaringClass($prop);
68-
return preg_replace_callback('#[\w\\\]+#', fn($m) => Reflection::expandClassName($m[0], $class), $type);
69-
}
70-
71-
return null;
72-
}
73-
74-
75-
/**
76-
* Returns an annotation value.
77-
* @param \ReflectionProperty $ref
78-
*/
79-
public static function parseAnnotation(\Reflector $ref, string $name): ?string
80-
{
81-
if (!Reflection::areCommentsAvailable()) {
82-
throw new Nette\InvalidStateException('You have to enable phpDoc comments in opcode cache.');
83-
}
84-
85-
$re = '#[\s*]@' . preg_quote($name, '#') . '(?=\s|$)(?:[ \t]+([^@\s]\S*))?#';
86-
if ($ref->getDocComment() && preg_match($re, trim($ref->getDocComment(), '/*'), $m)) {
87-
return $m[1] ?? '';
88-
}
89-
90-
return null;
91-
}
92-
93-
9458
public static function formatValue(mixed $value): string
9559
{
9660
if ($value instanceof DynamicParameter) {

tests/Schema/Expect.from.php80.phpt

Lines changed: 0 additions & 57 deletions
This file was deleted.

tests/Schema/Expect.from.phpt

Lines changed: 35 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -22,76 +22,70 @@ Assert::with(Structure::class, function () {
2222

2323
Assert::with(Structure::class, function () {
2424
$schema = Expect::from($obj = new class {
25-
/** @var string */
26-
public $dsn = 'mysql';
27-
28-
/** @var string|null */
29-
public $user;
30-
31-
/** @var ?string */
32-
public $password;
33-
34-
/** @var string[] */
35-
public $options = [1];
36-
37-
/** @var bool */
38-
public $debugger = true;
39-
public $mixed;
40-
41-
/** @var array|null */
42-
public $arr;
43-
44-
/** @var string */
45-
public $required;
25+
public string $dsn = 'mysql';
26+
public ?string $user;
27+
public ?string $password = null;
28+
public array|int $options = [];
29+
public bool $debugger = true;
30+
public mixed $mixed;
31+
public array $arr = [1];
4632
});
4733

4834
Assert::type(Structure::class, $schema);
4935
Assert::equal([
5036
'dsn' => Expect::string('mysql'),
51-
'user' => Expect::type('string|null'),
37+
'user' => Expect::type('?string')->required(),
5238
'password' => Expect::type('?string'),
53-
'options' => Expect::type('string[]')->default([1]),
39+
'options' => Expect::type('array|int')->default([]),
5440
'debugger' => Expect::bool(true),
55-
'mixed' => Expect::mixed(),
56-
'arr' => Expect::type('array|null')->default(null),
57-
'required' => Expect::type('string')->required(),
41+
'mixed' => Expect::mixed()->required(),
42+
'arr' => Expect::type('array')->default([1]),
5843
], $schema->items);
59-
Assert::type($obj, (new Processor)->process($schema, ['required' => '']));
44+
Assert::type($obj, (new Processor)->process($schema, ['user' => '', 'mixed' => '']));
6045
});
6146

6247

63-
Assert::exception(function () {
64-
Expect::from(new class {
65-
/** @var Unknown */
66-
public $unknown;
48+
Assert::with(Structure::class, function () { // constructor injection
49+
$schema = Expect::from($obj = new class ('') {
50+
public function __construct(
51+
public ?string $user,
52+
public ?string $password = null,
53+
) {
54+
}
6755
});
68-
}, Nette\NotImplementedException::class, 'Anonymous classes are not supported.');
56+
57+
Assert::type(Structure::class, $schema);
58+
Assert::equal([
59+
'user' => Expect::type('?string')->required(),
60+
'password' => Expect::type('?string'),
61+
], $schema->items);
62+
Assert::equal(
63+
new $obj('foo', 'bar'),
64+
(new Processor)->process($schema, ['user' => 'foo', 'password' => 'bar']),
65+
);
66+
});
6967

7068

7169
Assert::with(Structure::class, function () { // overwritten item
7270
$schema = Expect::from(new class {
73-
/** @var string */
74-
public $dsn = 'mysql';
71+
public string $dsn = 'mysql';
7572

76-
/** @var string|null */
77-
public $user;
73+
public ?string $user;
7874
}, ['dsn' => Expect::int(123)]);
7975

8076
Assert::equal([
8177
'dsn' => Expect::int(123),
82-
'user' => Expect::type('string|null'),
78+
'user' => Expect::type('?string')->required(),
8379
], $schema->items);
8480
});
8581

8682

8783
Assert::with(Structure::class, function () { // nested object
8884
$obj = new class {
89-
/** @var object */
90-
public $inner;
85+
public object $inner;
9186
};
9287
$obj->inner = new class {
93-
/** @var string */
94-
public $name;
88+
public string $name;
9589
};
9690

9791
$schema = Expect::from($obj);

tests/Schema/Helpers.getPropertyType.phpt

Lines changed: 0 additions & 37 deletions
This file was deleted.

tests/Schema/Helpers.parseAnnotation().phpt

Lines changed: 0 additions & 60 deletions
This file was deleted.

0 commit comments

Comments
 (0)