Skip to content

Commit 9157cee

Browse files
committed
added PhpFile::add()
1 parent 49f1dcd commit 9157cee

2 files changed

Lines changed: 171 additions & 4 deletions

File tree

src/PhpGenerator/PhpFile.php

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
namespace Nette\PhpGenerator;
99

10+
use Nette;
1011
use function count;
1112

1213

@@ -33,6 +34,30 @@ public static function fromCode(string $code): self
3334
}
3435

3536

37+
/**
38+
* Adds a namespace, class-like type, or function to the file. If the item has a namespace,
39+
* it will be added to that namespace (creating it if needed).
40+
*/
41+
public function add(ClassType|InterfaceType|TraitType|EnumType|GlobalFunction|PhpNamespace $item): static
42+
{
43+
if ($item instanceof PhpNamespace) {
44+
if (isset($this->namespaces[$name = $item->getName()])) {
45+
throw new Nette\InvalidStateException("Namespace '$name' already exists in the file.");
46+
}
47+
$this->namespaces[$name] = $item;
48+
$this->refreshBracketedSyntax();
49+
50+
} elseif ($item instanceof GlobalFunction) {
51+
$this->addNamespace('')->add($item);
52+
53+
} else {
54+
$this->addNamespace($item->getNamespace()?->getName() ?? '')->add($item);
55+
}
56+
57+
return $this;
58+
}
59+
60+
3661
/**
3762
* Adds a class to the file. If it already exists, throws an exception.
3863
* As a parameter, pass the full name with namespace.
@@ -102,10 +127,7 @@ public function addNamespace(string|PhpNamespace $namespace): PhpNamespace
102127
? ($this->namespaces[$namespace->getName()] = $namespace)
103128
: ($this->namespaces[$namespace] ??= new PhpNamespace($namespace));
104129

105-
foreach ($this->namespaces as $namespace) {
106-
$namespace->setBracketedSyntax(count($this->namespaces) > 1 && isset($this->namespaces['']));
107-
}
108-
130+
$this->refreshBracketedSyntax();
109131
return $res;
110132
}
111133

@@ -188,4 +210,12 @@ public function __toString(): string
188210
{
189211
return (new Printer)->printFile($this);
190212
}
213+
214+
215+
private function refreshBracketedSyntax(): void
216+
{
217+
foreach ($this->namespaces as $namespace) {
218+
$namespace->setBracketedSyntax(count($this->namespaces) > 1 && isset($this->namespaces['']));
219+
}
220+
}
191221
}
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
<?php declare(strict_types=1);
2+
3+
/**
4+
* Test: PhpFile::add() method.
5+
*/
6+
7+
use Nette\PhpGenerator\ClassType;
8+
use Nette\PhpGenerator\GlobalFunction;
9+
use Nette\PhpGenerator\PhpFile;
10+
use Nette\PhpGenerator\PhpNamespace;
11+
use Tester\Assert;
12+
13+
require __DIR__ . '/../bootstrap.php';
14+
15+
16+
test('add class without namespace', function () {
17+
$file = new PhpFile;
18+
$class = new ClassType('Demo');
19+
$file->add($class);
20+
21+
Assert::same([''], array_keys($file->getNamespaces()));
22+
Assert::same(['Demo'], array_keys($file->getClasses()));
23+
});
24+
25+
26+
test('add class with namespace', function () {
27+
$file = new PhpFile;
28+
$namespace = new PhpNamespace('App\Model');
29+
$class = new ClassType('User', $namespace);
30+
$file->add($class);
31+
32+
Assert::same(['App\Model'], array_keys($file->getNamespaces()));
33+
Assert::same(['App\Model\User'], array_keys($file->getClasses()));
34+
});
35+
36+
37+
test('add class to existing namespace', function () {
38+
$file = new PhpFile;
39+
$existingNamespace = $file->addNamespace('Foo\Bar');
40+
$existingNamespace->addClass('First');
41+
42+
$namespace = new PhpNamespace('Foo\Bar');
43+
$class = new ClassType('Second', $namespace);
44+
$file->add($class);
45+
46+
Assert::same(['Foo\Bar'], array_keys($file->getNamespaces()));
47+
Assert::same(['Foo\Bar\First', 'Foo\Bar\Second'], array_keys($file->getClasses()));
48+
Assert::same($existingNamespace, $file->addNamespace('Foo\Bar'));
49+
});
50+
51+
52+
test('add function without namespace', function () {
53+
$file = new PhpFile;
54+
$function = new GlobalFunction('myFunc');
55+
$function->setBody('return 42;');
56+
$file->add($function);
57+
58+
Assert::same([''], array_keys($file->getNamespaces()));
59+
Assert::same(['myFunc'], array_keys($file->getFunctions()));
60+
});
61+
62+
63+
test('add class from reflection', function () {
64+
$file = new PhpFile;
65+
$stdClass = ClassType::from('stdClass');
66+
$file->add($stdClass);
67+
68+
Assert::same($stdClass, $file->getClasses()['stdClass']);
69+
});
70+
71+
72+
test('multiple items to different namespaces', function () {
73+
$file = new PhpFile;
74+
75+
$ns1 = new PhpNamespace('Foo');
76+
$class1 = new ClassType('A', $ns1);
77+
$file->add($class1);
78+
79+
$ns2 = new PhpNamespace('Bar');
80+
$class2 = new ClassType('B', $ns2);
81+
$file->add($class2);
82+
83+
Assert::same(['Foo', 'Bar'], array_keys($file->getNamespaces()));
84+
Assert::same(['Foo\A', 'Bar\B'], array_keys($file->getClasses()));
85+
});
86+
87+
88+
test('items are correctly added with strict types', function () {
89+
$file = new PhpFile;
90+
$file->setStrictTypes();
91+
92+
$ns = new PhpNamespace('Test');
93+
$class = new ClassType('Sample', $ns);
94+
$class->addProperty('name')->setType('string');
95+
$file->add($class);
96+
97+
Assert::same(['Test'], array_keys($file->getNamespaces()));
98+
Assert::same(['Test\Sample'], array_keys($file->getClasses()));
99+
Assert::true($file->hasStrictTypes());
100+
});
101+
102+
103+
test('add namespace directly', function () {
104+
$file = new PhpFile;
105+
$namespace = new PhpNamespace('App\Services');
106+
$namespace->addClass('MyService');
107+
$file->add($namespace);
108+
109+
Assert::same(['App\Services'], array_keys($file->getNamespaces()));
110+
Assert::same(['App\Services\MyService'], array_keys($file->getClasses()));
111+
});
112+
113+
114+
test('add namespace with multiple items', function () {
115+
$file = new PhpFile;
116+
$namespace = new PhpNamespace('Foo\Bar');
117+
$namespace->addClass('First');
118+
$namespace->addClass('Second');
119+
$namespace->addFunction('helper');
120+
$file->add($namespace);
121+
122+
Assert::same(['Foo\Bar'], array_keys($file->getNamespaces()));
123+
Assert::same(['Foo\Bar\First', 'Foo\Bar\Second'], array_keys($file->getClasses()));
124+
Assert::same(['Foo\Bar\helper'], array_keys($file->getFunctions()));
125+
});
126+
127+
128+
testException('adding namespace object to existing namespace throws exception', function () {
129+
$file = new PhpFile;
130+
$existingNs = $file->addNamespace('App');
131+
$existingNs->addClass('Existing');
132+
133+
$duplicateNs = new PhpNamespace('App');
134+
$duplicateNs->addClass('Duplicate');
135+
136+
$file->add($duplicateNs);
137+
}, Nette\InvalidStateException::class, "Namespace 'App' already exists in the file.");

0 commit comments

Comments
 (0)