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 ($val)
341: {
342: $this->documents = $val ? array((string) $val) : array();
343: return $this;
344: }
345:
346:
347: 348: 349:
350: public function ()
351: {
352: return implode($this->documents) ?: NULL;
353: }
354:
355:
356: 357: 358: 359:
360: public function ($val)
361: {
362: return $this->addDocument($val);
363: }
364:
365:
366: 367: 368: 369:
370: public function setDocuments(array $s)
371: {
372: $this->documents = $s;
373: return $this;
374: }
375:
376:
377: 378: 379:
380: public function getDocuments()
381: {
382: return $this->documents;
383: }
384:
385:
386: 387: 388: 389:
390: public function addDocument($s)
391: {
392: $this->documents[] = (string) $s;
393: return $this;
394: }
395:
396:
397: 398: 399:
400: public function setConsts(array $consts)
401: {
402: $this->consts = $consts;
403: return $this;
404: }
405:
406:
407: 408: 409:
410: public function getConsts()
411: {
412: return $this->consts;
413: }
414:
415:
416: 417: 418: 419: 420:
421: public function addConst($name, $value)
422: {
423: $this->consts[$name] = $value;
424: return $this;
425: }
426:
427:
428: 429: 430: 431:
432: public function setProperties(array $props)
433: {
434: $this->properties = array();
435: foreach ($props as $v) {
436: if (!$v instanceof Property) {
437: throw new Nette\InvalidArgumentException('Argument must be Nette\PhpGenerator\Property[].');
438: }
439: $this->properties[$v->getName()] = $v;
440: }
441: return $this;
442: }
443:
444:
445: 446: 447:
448: public function getProperties()
449: {
450: return $this->properties;
451: }
452:
453:
454: 455: 456:
457: public function getProperty($name)
458: {
459: if (!isset($this->properties[$name])) {
460: throw new Nette\InvalidArgumentException("Property '$name' not found.");
461: }
462: return $this->properties[$name];
463: }
464:
465:
466: 467: 468: 469: 470:
471: public function addProperty($name, $value = NULL)
472: {
473: $property = new Property($name);
474: return $this->properties[$name] = $property->setValue($value);
475: }
476:
477:
478: 479: 480: 481:
482: public function setMethods(array $methods)
483: {
484: $this->methods = array();
485: foreach ($methods as $v) {
486: if (!$v instanceof Method) {
487: throw new Nette\InvalidArgumentException('Argument must be Nette\PhpGenerator\Method[].');
488: }
489: $this->methods[$v->getName()] = $v->setNamespace($this->namespace);
490: }
491: return $this;
492: }
493:
494:
495: 496: 497:
498: public function getMethods()
499: {
500: return $this->methods;
501: }
502:
503:
504: 505: 506:
507: public function getMethod($name)
508: {
509: if (!isset($this->methods[$name])) {
510: throw new Nette\InvalidArgumentException("Method '$name' not found.");
511: }
512: return $this->methods[$name];
513: }
514:
515:
516: 517: 518: 519:
520: public function addMethod($name)
521: {
522: $method = new Method($name);
523: if ($this->type === 'interface') {
524: $method->setVisibility(NULL)->setBody(FALSE);
525: } else {
526: $method->setVisibility('public');
527: }
528: return $this->methods[$name] = $method->setNamespace($this->namespace);
529: }
530:
531: }
532: