Skip to content

Commit

Permalink
Rules: provide phpdoc-compatible type for rule input and output
Browse files Browse the repository at this point in the history
  • Loading branch information
mabar committed Aug 14, 2022
1 parent 62b4cf1 commit f0d6564
Show file tree
Hide file tree
Showing 53 changed files with 1,906 additions and 20 deletions.
22 changes: 22 additions & 0 deletions src/Bridge/NextrasOrm/EntityFromIdRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
use Orisai\ObjectMapper\Exception\InvalidData;
use Orisai\ObjectMapper\Exception\ValueDoesNotMatch;
use Orisai\ObjectMapper\Meta\Compile\RuleCompileMeta;
use Orisai\ObjectMapper\PhpTypes\Node;
use Orisai\ObjectMapper\PhpTypes\SimpleNode;
use Orisai\ObjectMapper\Rules\Rule;
use Orisai\ObjectMapper\Types\SimpleValueType;
use Orisai\ObjectMapper\Types\Value;
Expand Down Expand Up @@ -129,4 +131,24 @@ public function createType(Args $args, TypeContext $context): SimpleValueType
return new SimpleValueType($args->name);
}

/**
* @param EntityFromIdArgs $args
*/
public function getExpectedInputType(Args $args, TypeContext $context): Node
{
$ruleMeta = $args->idRule;
$rule = $context->getRule($ruleMeta->getType());
$ruleArgs = $ruleMeta->getArgs();

return $rule->getExpectedInputType($ruleArgs, $context);
}

/**
* @param EntityFromIdArgs $args
*/
public function getReturnType(Args $args, TypeContext $context): Node
{
return new SimpleNode($args->entity);
}

}
49 changes: 49 additions & 0 deletions src/PhpTypes/ClassReferenceNode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php declare(strict_types = 1);

namespace Orisai\ObjectMapper\PhpTypes;

use function array_key_last;

final class ClassReferenceNode implements Node
{

/** @var class-string */
private string $class;

/** @var array<int|string, Node> */
private array $structure;

/**
* @param class-string $class
* @param array<int|string, Node> $structure
*/
public function __construct(string $class, array $structure)
{
$this->class = $class;
$this->structure = $structure;
}

public function getArrayShape(): string
{
$inline = '';
$lastKey = array_key_last($this->structure);
foreach ($this->structure as $field => $node) {
$inline .=
$field
. ': '
. ((string) $node);

if ($field !== $lastKey) {
$inline .= ', ';
}
}

return "array{{$inline}}";
}

public function __toString(): string
{
return $this->class;
}

}
55 changes: 55 additions & 0 deletions src/PhpTypes/CompoundNode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php declare(strict_types = 1);

namespace Orisai\ObjectMapper\PhpTypes;

use function array_key_last;

final class CompoundNode implements Node
{

/** @var array<int, Node> */
private array $nodes;

private string $operator;

/**
* @param array<int, Node> $nodes
*/
private function __construct(array $nodes, string $operator)
{
$this->nodes = $nodes;
$this->operator = $operator;
}

/**
* @param array<int, Node> $nodes
*/
public static function createAndType(array $nodes): self
{
return new self($nodes, '&');
}

/**
* @param array<int, Node> $nodes
*/
public static function createOrType(array $nodes): self
{
return new self($nodes, '|');
}

public function __toString(): string
{
$string = '';
$lastKey = array_key_last($this->nodes);
foreach ($this->nodes as $key => $node) {
$string .= $node;

if ($key !== $lastKey) {
$string .= $this->operator;
}
}

return "($string)";
}

}
41 changes: 41 additions & 0 deletions src/PhpTypes/LiteralNode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php declare(strict_types = 1);

namespace Orisai\ObjectMapper\PhpTypes;

use function is_bool;
use function is_float;
use function is_int;
use function var_export;

final class LiteralNode implements Node
{

/** @var int|float|string|bool|null */
private $value;

/**
* @param int|float|string|bool|null $value
*/
public function __construct($value)
{
$this->value = $value;
}

public function __toString(): string
{
if (is_bool($this->value)) {
return $this->value ? 'true' : 'false';
}

if ($this->value === null) {
return 'null';
}

if (is_int($this->value) || is_float($this->value)) {
return var_export($this->value, true);
}

return "'{$this->value}'";
}

}
30 changes: 30 additions & 0 deletions src/PhpTypes/MultiValueNode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php declare(strict_types = 1);

namespace Orisai\ObjectMapper\PhpTypes;

final class MultiValueNode implements Node
{

private string $name;

private ?Node $key;

private Node $item;

public function __construct(string $name, ?Node $key, Node $item)
{
$this->name = $name;
$this->key = $key;
$this->item = $item;
}

public function __toString(): string
{
return $this->name
. '<'
. ($this->key !== null ? "$this->key, " : '')
. ((string) $this->item)
. '>';
}

}
10 changes: 10 additions & 0 deletions src/PhpTypes/Node.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php declare(strict_types = 1);

namespace Orisai\ObjectMapper\PhpTypes;

interface Node
{

public function __toString(): string;

}
24 changes: 24 additions & 0 deletions src/PhpTypes/SimpleNode.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php declare(strict_types = 1);

namespace Orisai\ObjectMapper\PhpTypes;

final class SimpleNode implements Node
{

/** @var non-empty-string */
private string $value;

/**
* @param non-empty-string $value
*/
public function __construct(string $value)
{
$this->value = $value;
}

public function __toString(): string
{
return $this->value;
}

}
23 changes: 23 additions & 0 deletions src/Rules/AllOfRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@

use Orisai\ObjectMapper\Args\Args;
use Orisai\ObjectMapper\Context\FieldContext;
use Orisai\ObjectMapper\Context\TypeContext;
use Orisai\ObjectMapper\Exception\InvalidData;
use Orisai\ObjectMapper\Exception\ValueDoesNotMatch;
use Orisai\ObjectMapper\PhpTypes\CompoundNode;
use Orisai\ObjectMapper\PhpTypes\Node;
use Orisai\ObjectMapper\Types\CompoundType;
use Orisai\ObjectMapper\Types\Value;

Expand Down Expand Up @@ -59,4 +62,24 @@ protected function createCompoundType(): CompoundType
return CompoundType::createAndType();
}

/**
* @param CompoundRuleArgs $args
*/
public function getExpectedInputType(Args $args, TypeContext $context): Node
{
return CompoundNode::createAndType(
$this->getExpectedInputTypeNodes($args, $context),
);
}

/**
* @param CompoundRuleArgs $args
*/
public function getReturnType(Args $args, TypeContext $context): Node
{
return CompoundNode::createAndType(
$this->getReturnTypeNodes($args, $context),
);
}

}
23 changes: 23 additions & 0 deletions src/Rules/AnyOfRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@

use Orisai\ObjectMapper\Args\Args;
use Orisai\ObjectMapper\Context\FieldContext;
use Orisai\ObjectMapper\Context\TypeContext;
use Orisai\ObjectMapper\Exception\InvalidData;
use Orisai\ObjectMapper\Exception\ValueDoesNotMatch;
use Orisai\ObjectMapper\PhpTypes\CompoundNode;
use Orisai\ObjectMapper\PhpTypes\Node;
use Orisai\ObjectMapper\Types\CompoundType;
use Orisai\ObjectMapper\Types\Value;

Expand Down Expand Up @@ -58,4 +61,24 @@ protected function createCompoundType(): CompoundType
return CompoundType::createOrType();
}

/**
* @param CompoundRuleArgs $args
*/
public function getExpectedInputType(Args $args, TypeContext $context): Node
{
return CompoundNode::createOrType(
$this->getExpectedInputTypeNodes($args, $context),
);
}

/**
* @param CompoundRuleArgs $args
*/
public function getReturnType(Args $args, TypeContext $context): Node
{
return CompoundNode::createOrType(
$this->getReturnTypeNodes($args, $context),
);
}

}
24 changes: 24 additions & 0 deletions src/Rules/ArrayEnumRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
use Orisai\ObjectMapper\Context\RuleArgsContext;
use Orisai\ObjectMapper\Context\TypeContext;
use Orisai\ObjectMapper\Exception\ValueDoesNotMatch;
use Orisai\ObjectMapper\PhpTypes\CompoundNode;
use Orisai\ObjectMapper\PhpTypes\LiteralNode;
use Orisai\ObjectMapper\PhpTypes\Node;
use Orisai\ObjectMapper\Types\EnumType;
use Orisai\ObjectMapper\Types\Value;
use function array_keys;
Expand Down Expand Up @@ -95,4 +98,25 @@ private function getEnumValues(ArrayEnumArgs $args): array
: array_values($args->values);
}

/**
* @param ArrayEnumArgs $args
*/
public function getExpectedInputType(Args $args, TypeContext $context): Node
{
$types = [];
foreach ($this->getEnumValues($args) as $value) {
$types[] = new LiteralNode($value);
}

return CompoundNode::createOrType($types);
}

/**
* @param ArrayEnumArgs $args
*/
public function getReturnType(Args $args, TypeContext $context): Node
{
return $this->getExpectedInputType($args, $context);
}

}
Loading

0 comments on commit f0d6564

Please sign in to comment.