Skip to content

Commit 24c29e8

Browse files
committed
Rules: provide phpdoc-compatible type for rule input and output
1 parent 62b4cf1 commit 24c29e8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+1906
-20
lines changed

src/Bridge/NextrasOrm/EntityFromIdRule.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
use Orisai\ObjectMapper\Exception\InvalidData;
1414
use Orisai\ObjectMapper\Exception\ValueDoesNotMatch;
1515
use Orisai\ObjectMapper\Meta\Compile\RuleCompileMeta;
16+
use Orisai\ObjectMapper\PhpTypes\Node;
17+
use Orisai\ObjectMapper\PhpTypes\SimpleNode;
1618
use Orisai\ObjectMapper\Rules\Rule;
1719
use Orisai\ObjectMapper\Types\SimpleValueType;
1820
use Orisai\ObjectMapper\Types\Value;
@@ -129,4 +131,24 @@ public function createType(Args $args, TypeContext $context): SimpleValueType
129131
return new SimpleValueType($args->name);
130132
}
131133

134+
/**
135+
* @param EntityFromIdArgs $args
136+
*/
137+
public function getExpectedInputType(Args $args, TypeContext $context): Node
138+
{
139+
$ruleMeta = $args->idRule;
140+
$rule = $context->getRule($ruleMeta->getType());
141+
$ruleArgs = $ruleMeta->getArgs();
142+
143+
return $rule->getExpectedInputType($ruleArgs, $context);
144+
}
145+
146+
/**
147+
* @param EntityFromIdArgs $args
148+
*/
149+
public function getReturnType(Args $args, TypeContext $context): Node
150+
{
151+
return new SimpleNode($args->entity);
152+
}
153+
132154
}

src/PhpTypes/ClassReferenceNode.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Orisai\ObjectMapper\PhpTypes;
4+
5+
use function array_key_last;
6+
7+
final class ClassReferenceNode implements Node
8+
{
9+
10+
/** @var class-string */
11+
private string $class;
12+
13+
/** @var array<int|string, Node> */
14+
private array $structure;
15+
16+
/**
17+
* @param class-string $class
18+
* @param array<int|string, Node> $structure
19+
*/
20+
public function __construct(string $class, array $structure)
21+
{
22+
$this->class = $class;
23+
$this->structure = $structure;
24+
}
25+
26+
public function getArrayShape(): string
27+
{
28+
$inline = '';
29+
$lastKey = array_key_last($this->structure);
30+
foreach ($this->structure as $field => $node) {
31+
$inline .=
32+
$field
33+
. ': '
34+
. ((string) $node);
35+
36+
if ($field !== $lastKey) {
37+
$inline .= ', ';
38+
}
39+
}
40+
41+
return "array{{$inline}}";
42+
}
43+
44+
public function __toString(): string
45+
{
46+
return $this->class;
47+
}
48+
49+
}

src/PhpTypes/CompoundNode.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Orisai\ObjectMapper\PhpTypes;
4+
5+
use function array_key_last;
6+
7+
final class CompoundNode implements Node
8+
{
9+
10+
/** @var array<int, Node> */
11+
private array $nodes;
12+
13+
private string $operator;
14+
15+
/**
16+
* @param array<int, Node> $nodes
17+
*/
18+
private function __construct(array $nodes, string $operator)
19+
{
20+
$this->nodes = $nodes;
21+
$this->operator = $operator;
22+
}
23+
24+
/**
25+
* @param array<int, Node> $nodes
26+
*/
27+
public static function createAndType(array $nodes): self
28+
{
29+
return new self($nodes, '&');
30+
}
31+
32+
/**
33+
* @param array<int, Node> $nodes
34+
*/
35+
public static function createOrType(array $nodes): self
36+
{
37+
return new self($nodes, '|');
38+
}
39+
40+
public function __toString(): string
41+
{
42+
$string = '';
43+
$lastKey = array_key_last($this->nodes);
44+
foreach ($this->nodes as $key => $node) {
45+
$string .= $node;
46+
47+
if ($key !== $lastKey) {
48+
$string .= $this->operator;
49+
}
50+
}
51+
52+
return "($string)";
53+
}
54+
55+
}

src/PhpTypes/LiteralNode.php

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Orisai\ObjectMapper\PhpTypes;
4+
5+
use function is_bool;
6+
use function is_float;
7+
use function is_int;
8+
use function var_export;
9+
10+
final class LiteralNode implements Node
11+
{
12+
13+
/** @var int|float|string|bool|null */
14+
private $value;
15+
16+
/**
17+
* @param int|float|string|bool|null $value
18+
*/
19+
public function __construct($value)
20+
{
21+
$this->value = $value;
22+
}
23+
24+
public function __toString(): string
25+
{
26+
if (is_bool($this->value)) {
27+
return $this->value ? 'true' : 'false';
28+
}
29+
30+
if ($this->value === null) {
31+
return 'null';
32+
}
33+
34+
if (is_int($this->value) || is_float($this->value)) {
35+
return var_export($this->value, true);
36+
}
37+
38+
return "'{$this->value}'";
39+
}
40+
41+
}

src/PhpTypes/MultiValueNode.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Orisai\ObjectMapper\PhpTypes;
4+
5+
final class MultiValueNode implements Node
6+
{
7+
8+
private string $name;
9+
10+
private ?Node $key;
11+
12+
private Node $item;
13+
14+
public function __construct(string $name, ?Node $key, Node $item)
15+
{
16+
$this->name = $name;
17+
$this->key = $key;
18+
$this->item = $item;
19+
}
20+
21+
public function __toString(): string
22+
{
23+
return $this->name
24+
. '<'
25+
. ($this->key !== null ? "$this->key, " : '')
26+
. ((string) $this->item)
27+
. '>';
28+
}
29+
30+
}

src/PhpTypes/Node.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Orisai\ObjectMapper\PhpTypes;
4+
5+
interface Node
6+
{
7+
8+
public function __toString(): string;
9+
10+
}

src/PhpTypes/SimpleNode.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Orisai\ObjectMapper\PhpTypes;
4+
5+
final class SimpleNode implements Node
6+
{
7+
8+
/** @var non-empty-string */
9+
private string $value;
10+
11+
/**
12+
* @param non-empty-string $value
13+
*/
14+
public function __construct(string $value)
15+
{
16+
$this->value = $value;
17+
}
18+
19+
public function __toString(): string
20+
{
21+
return $this->value;
22+
}
23+
24+
}

src/Rules/AllOfRule.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@
44

55
use Orisai\ObjectMapper\Args\Args;
66
use Orisai\ObjectMapper\Context\FieldContext;
7+
use Orisai\ObjectMapper\Context\TypeContext;
78
use Orisai\ObjectMapper\Exception\InvalidData;
89
use Orisai\ObjectMapper\Exception\ValueDoesNotMatch;
10+
use Orisai\ObjectMapper\PhpTypes\CompoundNode;
11+
use Orisai\ObjectMapper\PhpTypes\Node;
912
use Orisai\ObjectMapper\Types\CompoundType;
1013
use Orisai\ObjectMapper\Types\Value;
1114

@@ -59,4 +62,24 @@ protected function createCompoundType(): CompoundType
5962
return CompoundType::createAndType();
6063
}
6164

65+
/**
66+
* @param CompoundRuleArgs $args
67+
*/
68+
public function getExpectedInputType(Args $args, TypeContext $context): Node
69+
{
70+
return CompoundNode::createAndType(
71+
$this->getExpectedInputTypeNodes($args, $context),
72+
);
73+
}
74+
75+
/**
76+
* @param CompoundRuleArgs $args
77+
*/
78+
public function getReturnType(Args $args, TypeContext $context): Node
79+
{
80+
return CompoundNode::createAndType(
81+
$this->getReturnTypeNodes($args, $context),
82+
);
83+
}
84+
6285
}

src/Rules/AnyOfRule.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@
44

55
use Orisai\ObjectMapper\Args\Args;
66
use Orisai\ObjectMapper\Context\FieldContext;
7+
use Orisai\ObjectMapper\Context\TypeContext;
78
use Orisai\ObjectMapper\Exception\InvalidData;
89
use Orisai\ObjectMapper\Exception\ValueDoesNotMatch;
10+
use Orisai\ObjectMapper\PhpTypes\CompoundNode;
11+
use Orisai\ObjectMapper\PhpTypes\Node;
912
use Orisai\ObjectMapper\Types\CompoundType;
1013
use Orisai\ObjectMapper\Types\Value;
1114

@@ -58,4 +61,24 @@ protected function createCompoundType(): CompoundType
5861
return CompoundType::createOrType();
5962
}
6063

64+
/**
65+
* @param CompoundRuleArgs $args
66+
*/
67+
public function getExpectedInputType(Args $args, TypeContext $context): Node
68+
{
69+
return CompoundNode::createOrType(
70+
$this->getExpectedInputTypeNodes($args, $context),
71+
);
72+
}
73+
74+
/**
75+
* @param CompoundRuleArgs $args
76+
*/
77+
public function getReturnType(Args $args, TypeContext $context): Node
78+
{
79+
return CompoundNode::createOrType(
80+
$this->getReturnTypeNodes($args, $context),
81+
);
82+
}
83+
6184
}

src/Rules/ArrayEnumRule.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
use Orisai\ObjectMapper\Context\RuleArgsContext;
1010
use Orisai\ObjectMapper\Context\TypeContext;
1111
use Orisai\ObjectMapper\Exception\ValueDoesNotMatch;
12+
use Orisai\ObjectMapper\PhpTypes\CompoundNode;
13+
use Orisai\ObjectMapper\PhpTypes\LiteralNode;
14+
use Orisai\ObjectMapper\PhpTypes\Node;
1215
use Orisai\ObjectMapper\Types\EnumType;
1316
use Orisai\ObjectMapper\Types\Value;
1417
use function array_keys;
@@ -95,4 +98,25 @@ private function getEnumValues(ArrayEnumArgs $args): array
9598
: array_values($args->values);
9699
}
97100

101+
/**
102+
* @param ArrayEnumArgs $args
103+
*/
104+
public function getExpectedInputType(Args $args, TypeContext $context): Node
105+
{
106+
$types = [];
107+
foreach ($this->getEnumValues($args) as $value) {
108+
$types[] = new LiteralNode($value);
109+
}
110+
111+
return CompoundNode::createOrType($types);
112+
}
113+
114+
/**
115+
* @param ArrayEnumArgs $args
116+
*/
117+
public function getReturnType(Args $args, TypeContext $context): Node
118+
{
119+
return $this->getExpectedInputType($args, $context);
120+
}
121+
98122
}

0 commit comments

Comments
 (0)