1: <?php
2:
3: 4: 5: 6:
7:
8: namespace Nette\PhpGenerator;
9:
10: use Nette;
11: use Nette\InvalidStateException;
12: use Nette\Utils\Strings;
13:
14:
15: 16: 17: 18: 19: 20: 21: 22:
23: class PhpNamespace
24: {
25: use Nette\SmartObject;
26:
27:
28: private $name;
29:
30:
31: private $bracketedSyntax = FALSE;
32:
33:
34: private $uses = [];
35:
36:
37: private $classes = [];
38:
39:
40: public function __construct($name = NULL)
41: {
42: $this->setName($name);
43: }
44:
45:
46:
47: public function setName($name)
48: {
49: $this->name = (string) $name;
50: return $this;
51: }
52:
53:
54: 55: 56:
57: public function getName()
58: {
59: return $this->name ?: NULL;
60: }
61:
62:
63: 64: 65: 66: 67:
68: public function setBracketedSyntax($state = TRUE)
69: {
70: $this->bracketedSyntax = (bool) $state;
71: return $this;
72: }
73:
74:
75: 76: 77:
78: public function getBracketedSyntax()
79: {
80: return $this->bracketedSyntax;
81: }
82:
83:
84: 85: 86: 87: 88: 89: 90:
91: public function addUse($name, $alias = NULL, &$aliasOut = NULL)
92: {
93: $name = ltrim($name, '\\');
94: if ($alias === NULL && $this->name === Helpers::extractNamespace($name)) {
95: $alias = Helpers::extractShortName($name);
96: }
97: if ($alias === NULL) {
98: $path = explode('\\', $name);
99: $counter = NULL;
100: do {
101: if (empty($path)) {
102: $counter++;
103: } else {
104: $alias = array_pop($path) . $alias;
105: }
106: } while (isset($this->uses[$alias . $counter]) && $this->uses[$alias . $counter] !== $name);
107: $alias .= $counter;
108:
109: } elseif (isset($this->uses[$alias]) && $this->uses[$alias] !== $name) {
110: throw new InvalidStateException(
111: "Alias '$alias' used already for '{$this->uses[$alias]}', cannot use for '{$name}'."
112: );
113: }
114:
115: $aliasOut = $alias;
116: $this->uses[$alias] = $name;
117: return $this;
118: }
119:
120:
121: 122: 123:
124: public function getUses()
125: {
126: return $this->uses;
127: }
128:
129:
130: 131: 132: 133:
134: public function unresolveName($name)
135: {
136: if (in_array(strtolower($name), ['self', 'parent', 'array', 'callable', 'string', 'bool', 'float', 'int', ''], TRUE)) {
137: return $name;
138: }
139: $name = ltrim($name, '\\');
140: $res = NULL;
141: $lower = strtolower($name);
142: foreach ($this->uses as $alias => $for) {
143: if (Strings::startsWith($lower . '\\', strtolower($for) . '\\')) {
144: $short = $alias . substr($name, strlen($for));
145: if (!isset($res) || strlen($res) > strlen($short)) {
146: $res = $short;
147: }
148: }
149: }
150:
151: if (!$res && Strings::startsWith($lower, strtolower($this->name) . '\\')) {
152: return substr($name, strlen($this->name) + 1);
153: } else {
154: return $res ?: ($this->name ? '\\' : '') . $name;
155: }
156: }
157:
158:
159: 160: 161: 162:
163: public function addClass($name)
164: {
165: if (!isset($this->classes[$name])) {
166: $this->addUse($this->name . '\\' . $name);
167: $this->classes[$name] = new ClassType($name, $this);
168: }
169: return $this->classes[$name];
170: }
171:
172:
173: 174: 175: 176:
177: public function addInterface($name)
178: {
179: return $this->addClass($name)->setType(ClassType::TYPE_INTERFACE);
180: }
181:
182:
183: 184: 185: 186:
187: public function addTrait($name)
188: {
189: return $this->addClass($name)->setType(ClassType::TYPE_TRAIT);
190: }
191:
192:
193: 194: 195:
196: public function getClasses()
197: {
198: return $this->classes;
199: }
200:
201:
202: 203: 204:
205: public function __toString()
206: {
207: $uses = [];
208: asort($this->uses);
209: foreach ($this->uses as $alias => $name) {
210: $useNamespace = Helpers::extractNamespace($name);
211:
212: if ($this->name !== $useNamespace) {
213: if ($alias === $name || substr($name, -(strlen($alias) + 1)) === '\\' . $alias) {
214: $uses[] = "use {$name};";
215: } else {
216: $uses[] = "use {$name} as {$alias};";
217: }
218: }
219: }
220:
221: $body = ($uses ? implode("\n", $uses) . "\n\n" : '')
222: . implode("\n", $this->classes);
223:
224: if ($this->bracketedSyntax) {
225: return 'namespace' . ($this->name ? ' ' . $this->name : '') . " {\n\n"
226: . Strings::indent($body)
227: . "\n}\n";
228:
229: } else {
230: return ($this->name ? "namespace {$this->name};\n\n" : '')
231: . $body;
232: }
233: }
234:
235: }
236: