Skip to content

Commit bf25d42

Browse files
committed
Expect::from() removed support for phpDoc annotations (BC break)
1 parent bb7e301 commit bf25d42

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
@@ -73,14 +73,11 @@ public static function from(object $object, array $items = []): Structure
7373
foreach ($props as $prop) {
7474
$item = &$items[$prop->getName()];
7575
if (!$item) {
76-
$type = Helpers::getPropertyType($prop) ?? 'mixed';
77-
$item = new Type($type);
76+
$item = new Type((string) (Nette\Utils\Type::fromReflection($prop) ?? 'mixed'));
7877
if ($prop instanceof \ReflectionProperty ? $prop->isInitialized($object) : $prop->isOptional()) {
7978
$def = ($prop instanceof \ReflectionProperty ? $prop->getValue($object) : $prop->getDefaultValue());
8079
if (is_object($def)) {
8180
$item = static::from($def);
82-
} elseif ($def === null && !Nette\Utils\Validators::is(null, $type)) {
83-
$item->required();
8481
} else {
8582
$item->default($def);
8683
}

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

1514

1615
/**
@@ -55,41 +54,6 @@ public static function merge(mixed $value, mixed $base): mixed
5554
}
5655

5756

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