1: <?php
2:
3: 4: 5: 6:
7:
8: namespace Nette\PhpGenerator;
9:
10: use Nette;
11: use Nette\Utils\Strings;
12:
13:
14: 15: 16:
17: class ClassType extends Nette\Object
18: {
19: const TYPE_CLASS = 'class';
20:
21: const TYPE_INTERFACE = 'interface';
22:
23: const TYPE_TRAIT = 'trait';
24:
25:
26: private $namespace;
27:
28:
29: private $name;
30:
31:
32: private $type = 'class';
33:
34:
35: private $final = FALSE;
36:
37:
38: private $abstract = FALSE;
39:
40:
41: private $extends = array();
42:
43:
44: private $implements = array();
45:
46:
47: private $traits = array();
48:
49:
50: private $documents = array();
51:
52:
53: private $consts = array();
54:
55:
56: private $properties = array();
57:
58:
59: private $methods = array();
60:
61:
62: 63: 64: 65:
66: public static function from($from)
67: {
68: $from = new \ReflectionClass($from instanceof \ReflectionClass ? $from->getName() : $from);
69: if (PHP_VERSION_ID >= 70000 && $from->isAnonymous()) {
70: $class = new static('anonymous');
71: } else {
72: $class = new static($from->getShortName(), new PhpNamespace($from->getNamespaceName()));
73: }
74: $class->type = $from->isInterface() ? 'interface' : (PHP_VERSION_ID >= 50400 && $from->isTrait() ? 'trait' : 'class');
75: $class->final = $from->isFinal() && $class->type === 'class';
76: $class->abstract = $from->isAbstract() && $class->type === 'class';
77: $class->implements = $from->getInterfaceNames();
78: $class->documents = $from->getDocComment() ? array(preg_replace('#^\s*\* ?#m', '', trim($from->getDocComment(), "/* \r\n\t"))) : array();
79: if ($from->getParentClass()) {
80: $class->extends = $from->getParentClass()->getName();
81: $class->implements = array_diff($class->implements, $from->getParentClass()->getInterfaceNames());
82: }
83: foreach ($from->getProperties() as $prop) {
84: if ($prop->getDeclaringClass()->getName() === $from->getName()) {
85: $class->properties[$prop->getName()] = Property::from($prop);
86: }
87: }
88: foreach ($from->getMethods() as $method) {
89: if ($method->getDeclaringClass()->getName() === $from->getName()) {
90: $class->methods[$method->getName()] = Method::from($method)->setNamespace($class->namespace);
91: }
92: }
93: return $class;
94: }
95:
96:
97: public function __construct($name = '', PhpNamespace $namespace = NULL)
98: {
99: $this->setName($name);
100: $this->namespace = $namespace;
101: }
102:
103:
104: 105: 106:
107: public function __toString()
108: {
109: $consts = array();
110: foreach ($this->consts as $name => $value) {
111: $consts[] = "const $name = " . Helpers::dump($value) . ";\n";
112: }
113:
114: $properties = array();
115: foreach ($this->properties as $property) {
116: $doc = str_replace("\n", "\n * ", implode("\n", $property->getDocuments()));
117: $properties[] = ($property->getDocuments() ? (strpos($doc, "\n") === FALSE ? "/** $doc */\n" : "/**\n * $doc\n */\n") : '')
118: . $property->getVisibility() . ($property->isStatic() ? ' static' : '') . ' $' . $property->getName()
119: . ($property->value === NULL ? '' : ' = ' . Helpers::dump($property->value))
120: . ";\n";
121: }
122:
123: $namespace = $this->namespace;
124: $mapper = function (array $arr) use ($namespace) {
125: return $namespace ? array_map(array($namespace, 'unresolveName'), $arr) : $arr;
126: };
127:
128: return Strings::normalize(
129: ($this->documents ? str_replace("\n", "\n * ", "/**\n" . implode("\n", $this->documents)) . "\n */\n" : '')
130: . ($this->abstract ? 'abstract ' : '')
131: . ($this->final ? 'final ' : '')
132: . $this->type . ' '
133: . $this->name . ' '
134: . ($this->extends ? 'extends ' . implode(', ', $mapper((array) $this->extends)) . ' ' : '')
135: . ($this->implements ? 'implements ' . implode(', ', $mapper($this->implements)) . ' ' : '')
136: . "\n{\n"
137: . Strings::indent(
138: ($this->traits ? 'use ' . implode(";\nuse ", $mapper($this->traits)) . ";\n\n" : '')
139: . ($this->consts ? implode('', $consts) . "\n" : '')
140: . ($this->properties ? implode("\n", $properties) . "\n" : '')
141: . ($this->methods ? "\n" . implode("\n\n\n", $this->methods) . "\n\n" : ''), 1)
142: . '}'
143: ) . "\n";
144: }
145:
146:
147: 148: 149:
150: public function getNamespace()
151: {
152: return $this->namespace;
153: }
154:
155:
156: 157: 158: 159:
160: public function setName($name)
161: {
162: $this->name = (string) $name;
163: return $this;
164: }
165:
166:
167: 168: 169:
170: public function getName()
171: {
172: return $this->name;
173: }
174:
175:
176: 177: 178: 179:
180: public function setType($type)
181: {
182: if (!in_array($type, array('class', 'interface', 'trait'), TRUE)) {
183: throw new Nette\InvalidArgumentException('Argument must be class|interface|trait.');
184: }
185: $this->type = $type;
186: return $this;
187: }
188:
189:
190: 191: 192:
193: public function getType()
194: {
195: return $this->type;
196: }
197:
198:
199: 200: 201: 202:
203: public function setFinal($state = TRUE)
204: {
205: $this->final = (bool) $state;
206: return $this;
207: }
208:
209:
210: 211: 212:
213: public function isFinal()
214: {
215: return $this->final;
216: }
217:
218:
219: 220: 221: 222:
223: public function setAbstract($state = TRUE)
224: {
225: $this->abstract = (bool) $state;
226: return $this;
227: }
228:
229:
230: 231: 232:
233: public function isAbstract()
234: {
235: return $this->abstract;
236: }
237:
238:
239: 240: 241: 242:
243: public function setExtends($types)
244: {
245: if (!is_string($types) && !(is_array($types) && array_filter($types, 'is_string') === $types)) {
246: throw new Nette\InvalidArgumentException('Argument must be string or string[].');
247: }
248: $this->extends = $types;
249: return $this;
250: }
251:
252:
253: 254: 255:
256: public function getExtends()
257: {
258: return $this->extends;
259: }
260:
261:
262: 263: 264: 265:
266: public function addExtend($type)
267: {
268: $this->extends = (array) $this->extends;
269: $this->extends[] = (string) $type;
270: return $this;
271: }
272:
273:
274: 275: 276: 277:
278: public function setImplements(array $types)
279: {
280: $this->implements = $types;
281: return $this;
282: }
283:
284:
285: 286: 287:
288: public function getImplements()
289: {
290: return $this->implements;
291: }
292:
293:
294: 295: 296: 297:
298: public function addImplement($type)
299: {
300: $this->implements[] = (string) $type;
301: return $this;
302: }
303:
304:
305: 306: 307: 308:
309: public function setTraits(array $traits)
310: {
311: $this->traits = $traits;
312: return $this;
313: }
314:
315:
316: 317: 318:
319: public function getTraits()
320: {
321: return $this->traits;
322: }
323:
324:
325: 326: 327: 328:
329: public function addTrait($trait)
330: {
331: $this->traits[] = (string) $trait;
332: return $this;
333: }
334:
335:
336: 337: 338: 339:
340: public function setDocuments(array $s)
341: {
342: $this->documents = $s;
343: return $this;
344: }
345:
346:
347: 348: 349:
350: public function getDocuments()
351: {
352: return $this->documents;
353: }
354:
355:
356: 357: 358: 359:
360: public function addDocument($s)
361: {
362: $this->documents[] = (string) $s;
363: return $this;
364: }
365:
366:
367: 368: 369:
370: public function setConsts(array $consts)
371: {
372: $this->consts = $consts;
373: return $this;
374: }
375:
376:
377: 378: 379:
380: public function getConsts()
381: {
382: return $this->consts;
383: }
384:
385:
386: 387: 388: 389: 390:
391: public function addConst($name, $value)
392: {
393: $this->consts[$name] = $value;
394: return $this;
395: }
396:
397:
398: 399: 400: 401:
402: public function setProperties(array $props)
403: {
404: $this->properties = array();
405: foreach ($props as $v) {
406: if (!$v instanceof Property) {
407: throw new Nette\InvalidArgumentException('Argument must be Nette\PhpGenerator\Property[].');
408: }
409: $this->properties[$v->getName()] = $v;
410: }
411: return $this;
412: }
413:
414:
415: 416: 417:
418: public function getProperties()
419: {
420: return $this->properties;
421: }
422:
423:
424: 425: 426:
427: public function getProperty($name)
428: {
429: if (!isset($this->properties[$name])) {
430: throw new Nette\InvalidArgumentException("Property '$name' not found.");
431: }
432: return $this->properties[$name];
433: }
434:
435:
436: 437: 438: 439: 440:
441: public function addProperty($name, $value = NULL)
442: {
443: $property = new Property($name);
444: return $this->properties[$name] = $property->setValue($value);
445: }
446:
447:
448: 449: 450: 451:
452: public function setMethods(array $methods)
453: {
454: $this->methods = array();
455: foreach ($methods as $v) {
456: if (!$v instanceof Method) {
457: throw new Nette\InvalidArgumentException('Argument must be Nette\PhpGenerator\Method[].');
458: }
459: $this->methods[$v->getName()] = $v->setNamespace($this->namespace);
460: }
461: return $this;
462: }
463:
464:
465: 466: 467:
468: public function getMethods()
469: {
470: return $this->methods;
471: }
472:
473:
474: 475: 476:
477: public function getMethod($name)
478: {
479: if (!isset($this->methods[$name])) {
480: throw new Nette\InvalidArgumentException("Method '$name' not found.");
481: }
482: return $this->methods[$name];
483: }
484:
485:
486: 487: 488: 489:
490: public function addMethod($name)
491: {
492: $method = new Method($name);
493: if ($this->type === 'interface') {
494: $method->setVisibility(NULL)->setBody(FALSE);
495: } else {
496: $method->setVisibility('public');
497: }
498: return $this->methods[$name] = $method->setNamespace($this->namespace);
499: }
500:
501: }
502: