Skip to content

Commit 87d1573

Browse files
committed
Support nullable properties and parameters - Close #7
1 parent 8ac1384 commit 87d1573

File tree

7 files changed

+353
-32
lines changed

7 files changed

+353
-32
lines changed

src/Code/ParameterGenerator.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,14 @@ final class ParameterGenerator
4848
private $variadic = false;
4949

5050
/**
51-
* @param string $name
52-
* @param string $type
53-
* @param mixed $defaultValue
54-
* @param bool $passByReference
51+
* @param string $name
52+
* @param string|null $type
53+
* @param mixed $defaultValue
54+
* @param bool $passByReference
5555
*/
5656
public function __construct(
57-
$name,
58-
$type = null,
57+
string $name,
58+
string $type = null,
5959
$defaultValue = null,
6060
bool $passByReference = false
6161
) {

src/Code/PropertyGenerator.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,13 @@ public function getDefaultValue(): ValueGenerator
106106

107107
public function generate(): Property
108108
{
109+
$docBlockType = $this->type->isNullable()
110+
? $this->type->type()
111+
: $this->type->type() . '|null';
112+
109113
$propComment = <<<EOF
110114
/**
111-
* @var {$this->type->type()}
115+
* @var {$docBlockType}
112116
*/
113117
EOF;
114118
$attributes = [];
@@ -126,7 +130,7 @@ public function generate(): Property
126130
),
127131
],
128132
$attributes,
129-
$this->typed ? $this->type->type() : null
133+
$this->typed ? $this->type->generate() : null
130134
);
131135
}
132136
}

src/Code/TypeGenerator.php

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ final class TypeGenerator
6969
*
7070
* @throws InvalidArgumentException
7171
*/
72-
public static function fromTypeString($type): TypeGenerator
72+
public static function fromTypeString(string $type): TypeGenerator
7373
{
7474
[$nullable, $trimmedNullable] = self::trimNullable($type);
7575
[$wasTrimmed, $trimmedType] = self::trimType($trimmedNullable);
@@ -97,7 +97,7 @@ public static function fromTypeString($type): TypeGenerator
9797

9898
$instance = new self();
9999

100-
$instance->type = $trimmedType;
100+
$instance->type = $isInternalPhpType ? $trimmedType : $trimmedNullable;
101101
$instance->nullable = $nullable;
102102
$instance->isInternalPhpType = $isInternalPhpType;
103103

@@ -113,27 +113,18 @@ public function type(): string
113113
return $this->type;
114114
}
115115

116-
public function generate(): NodeAbstract
116+
public function isNullable(): bool
117117
{
118-
$nullable = $this->nullable ? '?' : '';
119-
120-
// TODO nullable
121-
122-
if ($this->isInternalPhpType) {
123-
return new Node\Identifier(\strtolower($this->type));
124-
// return $nullable . strtolower($this->type);
125-
}
126-
127-
return new Node\Name($this->type);
128-
// return $nullable . '\\' . $this->type;
118+
return $this->nullable;
129119
}
130120

131-
/**
132-
* @return string the cleaned type string
133-
*/
134-
public function __toString(): string
121+
public function generate(): NodeAbstract
135122
{
136-
return \ltrim($this->generate(), '?\\');
123+
$type = $this->isInternalPhpType
124+
? new Node\Identifier(\strtolower($this->type))
125+
: new Node\Name($this->type);
126+
127+
return $this->nullable ? new Node\NullableType($type) : $type;
137128
}
138129

139130
/**
@@ -142,7 +133,7 @@ public function __toString(): string
142133
* @return bool[]|string[] ordered tuple, first key represents whether the type is nullable, second is the
143134
* trimmed string
144135
*/
145-
private static function trimNullable($type): array
136+
private static function trimNullable(string $type): array
146137
{
147138
if (0 === \strpos($type, '?')) {
148139
return [true, \substr($type, 1)];
@@ -157,7 +148,7 @@ private static function trimNullable($type): array
157148
* @return bool[]|string[] ordered tuple, first key represents whether the values was trimmed, second is the
158149
* trimmed string
159150
*/
160-
private static function trimType($type): array
151+
private static function trimType(string $type): array
161152
{
162153
if (0 === \strpos($type, '\\')) {
163154
return [true, \substr($type, 1)];
@@ -171,7 +162,7 @@ private static function trimType($type): array
171162
*
172163
* @return bool
173164
*/
174-
private static function isInternalPhpType($type): bool
165+
private static function isInternalPhpType(string $type): bool
175166
{
176167
return \in_array(\strtolower($type), self::$internalPhpTypes, true);
177168
}

tests/Code/ParameterGeneratorTest.php

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace OpenCodeModelingTest\CodeAst\Code;
6+
7+
use Generator;
8+
use OpenCodeModeling\CodeAst\Code\ParameterGenerator;
9+
use PhpParser\Parser;
10+
use PhpParser\ParserFactory;
11+
use PhpParser\PrettyPrinter\Standard;
12+
use PHPUnit\Framework\TestCase;
13+
14+
final class ParameterGeneratorTest extends TestCase
15+
{
16+
/**
17+
* @var Parser
18+
*/
19+
private $parser;
20+
21+
/**
22+
* @var Standard
23+
*/
24+
private $printer;
25+
26+
public function setUp(): void
27+
{
28+
$this->parser = (new ParserFactory())->create(ParserFactory::ONLY_PHP7);
29+
$this->printer = new Standard(['shortArraySyntax' => true]);
30+
}
31+
32+
/**
33+
* Values are: type
34+
*
35+
* @return Generator
36+
*/
37+
public function provideTypes(): Generator
38+
{
39+
yield 'string' => ['string'];
40+
yield 'bool' => ['bool'];
41+
yield 'int' => ['int'];
42+
yield 'float' => ['float'];
43+
yield '\\Awesome\\AcmeClass' => ['\\Awesome\\AcmeClass'];
44+
yield '\\Foo' => ['\\Foo'];
45+
46+
yield 'nullable string' => ['?string'];
47+
yield 'nullable bool' => ['?bool'];
48+
yield 'nullable int' => ['?int'];
49+
yield 'nullable float' => ['?float'];
50+
yield 'nullable \\Awesome\\AcmeClass' => ['?\\Awesome\\AcmeClass'];
51+
yield 'nullable \\Foo' => ['?\\Foo'];
52+
}
53+
54+
/**
55+
* @test
56+
* @dataProvider provideTypes
57+
* @param string $type
58+
*/
59+
public function it_generates_type(string $type): void
60+
{
61+
$parameter = new ParameterGenerator('myParameter', $type);
62+
63+
$expectedOutput = <<<PHP
64+
<?php
65+
66+
$type \$myParameter
67+
PHP;
68+
69+
$this->assertSame($expectedOutput, $this->printer->prettyPrintFile([$parameter->generate()]));
70+
}
71+
}

tests/Code/TypeGeneratorTest.php

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace OpenCodeModelingTest\CodeAst\Code;
6+
7+
use Generator;
8+
use OpenCodeModeling\CodeAst\Code\TypeGenerator;
9+
use PhpParser\Parser;
10+
use PhpParser\ParserFactory;
11+
use PhpParser\PrettyPrinter\Standard;
12+
use PHPUnit\Framework\TestCase;
13+
14+
final class TypeGeneratorTest extends TestCase
15+
{
16+
/**
17+
* @var Parser
18+
*/
19+
private $parser;
20+
21+
/**
22+
* @var Standard
23+
*/
24+
private $printer;
25+
26+
public function setUp(): void
27+
{
28+
$this->parser = (new ParserFactory())->create(ParserFactory::ONLY_PHP7);
29+
$this->printer = new Standard(['shortArraySyntax' => true]);
30+
}
31+
32+
/**
33+
* Values are: type, expected output
34+
*
35+
* @return Generator
36+
*/
37+
public function provideTypes(): Generator
38+
{
39+
yield 'string' => ['string', 'string'];
40+
yield 'bool' => ['bool', 'bool'];
41+
yield 'boolean' => ['bool', 'bool'];
42+
yield 'int' => ['int', 'int'];
43+
yield 'integer' => ['int', 'int'];
44+
yield 'float' => ['float', 'float'];
45+
yield '\\Awesome\\AcmeClass' => ['\\Awesome\\AcmeClass', '\\Awesome\\AcmeClass'];
46+
yield '\\Foo' => ['\\Foo', '\\Foo'];
47+
}
48+
49+
/**
50+
* @test
51+
* @dataProvider provideTypes
52+
* @param string $type
53+
* @param string $expectedOutput
54+
*/
55+
public function it_generates_type(string $type, string $expectedOutput): void
56+
{
57+
$type = TypeGenerator::fromTypeString($type);
58+
59+
$expectedOutput = <<<PHP
60+
<?php
61+
62+
$expectedOutput
63+
PHP;
64+
65+
66+
$this->assertSame($expectedOutput, $this->printer->prettyPrintFile([$type->generate()]));
67+
}
68+
69+
/**
70+
* @test
71+
* @dataProvider provideTypes
72+
* @param string $type
73+
* @param string $expectedOutput
74+
*/
75+
public function it_generates_nullable_type(string $type, string $expectedOutput): void
76+
{
77+
$type = TypeGenerator::fromTypeString('?'. $type);
78+
79+
$expectedOutput = <<<PHP
80+
<?php
81+
82+
?$expectedOutput
83+
PHP;
84+
85+
$this->assertSame($expectedOutput, $this->printer->prettyPrintFile([$type->generate()]));
86+
}
87+
}

tests/NodeVisitor/ClassConstantTest.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
use OpenCodeModeling\CodeAst\NodeVisitor\ClassUseTrait;
1313
use OpenCodeModeling\CodeAst\NodeVisitor\NamespaceUse;
1414
use OpenCodeModeling\CodeAst\NodeVisitor\StrictType;
15-
use OpenCodeModeling\JsonSchemaToPhpAst\ValueObject\BooleanFactory;
1615
use PhpParser\NodeTraverser;
1716
use PhpParser\Parser;
1817
use PhpParser\ParserFactory;
@@ -147,7 +146,7 @@ class TestClass
147146
/**
148147
* @test
149148
*/
150-
public function it_preserves_order_of_registered_visitors()
149+
public function it_preserves_order_of_registered_visitors(): void
151150
{
152151
$ast = $this->parser->parse('');
153152

0 commit comments

Comments
 (0)