Skip to content

Commit 154d779

Browse files
committed
Expect::from() removed support for phpDoc annotations (BC break)
1 parent 1069c92 commit 154d779

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
@@ -486,12 +486,9 @@ You can generate structure schema from the class. Example:
486486
```php
487487
class Config
488488
{
489-
/** @var string */
490-
public $name;
491-
/** @var string|null */
492-
public $password;
493-
/** @var bool */
494-
public $admin = false;
489+
public string $name;
490+
public ?string $password;
491+
public bool $admin = false;
495492
}
496493

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

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

523507
```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)