Skip to content

Commit b2d8a85

Browse files
committed
added PhpFile::add()
1 parent d3e893b commit b2d8a85

File tree

2 files changed

+173
-4
lines changed

2 files changed

+173
-4
lines changed

src/PhpGenerator/PhpFile.php

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

1010
namespace Nette\PhpGenerator;
1111

12+
use Nette;
1213
use function count;
1314

1415

@@ -35,6 +36,30 @@ public static function fromCode(string $code): self
3536
}
3637

3738

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

107-
foreach ($this->namespaces as $namespace) {
108-
$namespace->setBracketedSyntax(count($this->namespaces) > 1 && isset($this->namespaces['']));
109-
}
110-
132+
$this->refreshBracketedSyntax();
111133
return $res;
112134
}
113135

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

0 commit comments

Comments
 (0)