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