Skip to content

Commit c6f7b9a

Browse files
committed
Support final and abstract in ClassMethodBuilder - Close #24
1 parent 12ff888 commit c6f7b9a

File tree

2 files changed

+143
-2
lines changed

2 files changed

+143
-2
lines changed

src/Builder/ClassMethodBuilder.php

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ final class ClassMethodBuilder
5757
*/
5858
private $docBlock;
5959

60+
/** @var bool */
61+
private $final = false;
62+
63+
/** @var bool */
64+
private $abstract = false;
65+
6066
private function __construct()
6167
{
6268
}
@@ -68,6 +74,8 @@ public static function fromNode(Node\Stmt\ClassMethod $node): self
6874
$self->name = $node->name->toString();
6975
$self->returnType = $node->returnType ? $node->returnType->toString() : null;
7076
$self->visibility = $node->flags;
77+
$self->abstract = ($node->flags & MethodGenerator::FLAG_ABSTRACT) > 0;
78+
$self->final = ($node->flags & MethodGenerator::FLAG_FINAL) > 0;
7179

7280
foreach ($node->params as $param) {
7381
$self->parameters[] = ParameterBuilder::fromNode($param);
@@ -182,6 +190,30 @@ public function overrideDocBlock(?DocBlock $docBlock): void
182190
$this->docBlock = $docBlock;
183191
}
184192

193+
public function setFinal(bool $final): self
194+
{
195+
$this->final = $final;
196+
197+
return $this;
198+
}
199+
200+
public function setAbstract(bool $abstract): self
201+
{
202+
$this->abstract = $abstract;
203+
204+
return $this;
205+
}
206+
207+
public function isFinal(): bool
208+
{
209+
return $this->final;
210+
}
211+
212+
public function isAbstract(): bool
213+
{
214+
return $this->abstract;
215+
}
216+
185217
public function generate(Parser $parser): NodeVisitor
186218
{
187219
return new ClassMethod($this->methodGenerator($parser));
@@ -191,7 +223,18 @@ private function methodGenerator(Parser $parser): MethodGenerator
191223
{
192224
$flags = $this->visibility;
193225

194-
$body = new BodyGenerator($parser, $this->body);
226+
if ($this->final) {
227+
$flags |= MethodGenerator::FLAG_FINAL;
228+
}
229+
if ($this->abstract) {
230+
$flags |= MethodGenerator::FLAG_ABSTRACT;
231+
}
232+
233+
$body = null;
234+
235+
if (false === $this->isAbstract()) {
236+
$body = new BodyGenerator($parser, $this->body);
237+
}
195238

196239
$methodGenerator = new MethodGenerator(
197240
$this->name,

tests/Builder/ClassMethodBuilderTest.php

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,22 @@ public function it_generates_method_for_empty_class(): void
4545
$ast = $this->parser->parse('');
4646

4747
$classFactory = ClassBuilder::fromScratch('TestClass', 'My\\Awesome\\Service');
48-
$classFactory->setMethods(ClassMethodBuilder::fromScratch('setActive')->setReturnType('void'));
48+
$classFactory->setMethods(
49+
ClassMethodBuilder::fromScratch('setActive')->setReturnType('void'),
50+
ClassMethodBuilder::fromScratch('doSomething')->setReturnType('void')->setFinal(true)
51+
);
52+
53+
$methods = $classFactory->getMethods();
54+
55+
$this->assertCount(2, $methods);
56+
57+
$this->assertSame('setActive', $methods[0]->getName());
58+
$this->assertFalse($methods[0]->isAbstract());
59+
$this->assertFalse($methods[0]->isFinal());
60+
61+
$this->assertSame('doSomething', $methods[1]->getName());
62+
$this->assertFalse($methods[1]->isAbstract());
63+
$this->assertTrue($methods[1]->isFinal());
4964

5065
$nodeTraverser = new NodeTraverser();
5166
$classFactory->injectVisitors($nodeTraverser, $this->parser);
@@ -61,6 +76,45 @@ class TestClass
6176
public function setActive() : void
6277
{
6378
}
79+
public final function doSomething() : void
80+
{
81+
}
82+
}
83+
EOF;
84+
85+
$this->assertSame($expected, $this->printer->prettyPrintFile($nodeTraverser->traverse($ast)));
86+
}
87+
88+
/**
89+
* @test
90+
*/
91+
public function it_generates_abstract_method_for_empty_class(): void
92+
{
93+
$ast = $this->parser->parse('');
94+
95+
$classFactory = ClassBuilder::fromScratch('TestClass', 'My\\Awesome\\Service');
96+
$classFactory->setMethods(ClassMethodBuilder::fromScratch('setActive')->setReturnType('void')->setAbstract(true));
97+
98+
$methods = $classFactory->getMethods();
99+
100+
$this->assertCount(1, $methods);
101+
102+
$this->assertSame('setActive', $methods[0]->getName());
103+
$this->assertTrue($methods[0]->isAbstract());
104+
$this->assertFalse($methods[0]->isFinal());
105+
106+
$nodeTraverser = new NodeTraverser();
107+
$classFactory->injectVisitors($nodeTraverser, $this->parser);
108+
109+
$expected = <<<'EOF'
110+
<?php
111+
112+
declare (strict_types=1);
113+
namespace My\Awesome\Service;
114+
115+
class TestClass
116+
{
117+
public abstract function setActive() : void;
64118
}
65119
EOF;
66120

@@ -83,6 +137,48 @@ class TestClass
83137
public function setActive() : void
84138
{
85139
}
140+
public final function doSomething() : void
141+
{
142+
}
143+
}
144+
EOF;
145+
146+
$ast = $this->parser->parse($expected);
147+
148+
$classFactory = ClassBuilder::fromNodes(...$ast);
149+
150+
$methods = $classFactory->getMethods();
151+
152+
$this->assertCount(2, $methods);
153+
154+
$this->assertSame('setActive', $methods[0]->getName());
155+
$this->assertFalse($methods[0]->isAbstract());
156+
$this->assertFalse($methods[0]->isFinal());
157+
158+
$this->assertSame('doSomething', $methods[1]->getName());
159+
$this->assertFalse($methods[1]->isAbstract());
160+
$this->assertTrue($methods[1]->isFinal());
161+
162+
$nodeTraverser = new NodeTraverser();
163+
$classFactory->injectVisitors($nodeTraverser, $this->parser);
164+
165+
$this->assertSame($expected, $this->printer->prettyPrintFile($nodeTraverser->traverse($this->parser->parse(''))));
166+
}
167+
168+
/**
169+
* @test
170+
*/
171+
public function it_generates_abstract_method_for_empty_class_from_template(): void
172+
{
173+
$expected = <<<'EOF'
174+
<?php
175+
176+
declare (strict_types=1);
177+
namespace My\Awesome\Service;
178+
179+
class TestClass
180+
{
181+
public abstract function setActive() : void;
86182
}
87183
EOF;
88184

@@ -95,6 +191,8 @@ public function setActive() : void
95191
$this->assertCount(1, $methods);
96192

97193
$this->assertSame('setActive', $methods[0]->getName());
194+
$this->assertTrue($methods[0]->isAbstract());
195+
$this->assertFalse($methods[0]->isFinal());
98196

99197
$nodeTraverser = new NodeTraverser();
100198
$classFactory->injectVisitors($nodeTraverser, $this->parser);

0 commit comments

Comments
 (0)