3 * Zend Framework (http://framework.zend.com/)
5 * @link http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license http://framework.zend.com/license/new-bsd New BSD License
10 namespace Zend\Code\Generator
;
12 use Zend\Code\Reflection\ClassReflection
;
14 class ClassGenerator
extends AbstractGenerator
16 const FLAG_ABSTRACT
= 0x01;
17 const FLAG_FINAL
= 0x02;
22 protected $containingFileGenerator = null;
27 protected $namespaceName = null;
30 * @var DocBlockGenerator
32 protected $docBlock = null;
37 protected $name = null;
42 protected $flags = 0x00;
47 protected $extendedClass = null;
50 * @var array Array of string names
52 protected $implementedInterfaces = array();
55 * @var PropertyGenerator[] Array of properties
57 protected $properties = array();
60 * @var MethodGenerator[] Array of methods
62 protected $methods = array();
65 * @var array Array of string names
67 protected $uses = array();
70 * Build a Code Generation Php Object from a Class Reflection
72 * @param ClassReflection $classReflection
73 * @return ClassGenerator
75 public static function fromReflection(ClassReflection
$classReflection)
78 $cg = new static($classReflection->getName());
80 $cg->setSourceContent($cg->getSourceContent());
81 $cg->setSourceDirty(false);
83 if ($classReflection->getDocComment() != '') {
84 $cg->setDocBlock(DocBlockGenerator
::fromReflection($classReflection->getDocBlock()));
87 $cg->setAbstract($classReflection->isAbstract());
90 if ($classReflection->inNamespace()) {
91 $cg->setNamespaceName($classReflection->getNamespaceName());
94 /* @var \Zend\Code\Reflection\ClassReflection $parentClass */
95 $parentClass = $classReflection->getParentClass();
97 $cg->setExtendedClass($parentClass->getName());
98 $interfaces = array_diff($classReflection->getInterfaces(), $parentClass->getInterfaces());
100 $interfaces = $classReflection->getInterfaces();
103 $interfaceNames = array();
104 foreach ($interfaces AS $interface) {
105 /* @var \Zend\Code\Reflection\ClassReflection $interface */
106 $interfaceNames[] = $interface->getName();
109 $cg->setImplementedInterfaces($interfaceNames);
111 $properties = array();
112 foreach ($classReflection->getProperties() as $reflectionProperty) {
113 if ($reflectionProperty->getDeclaringClass()->getName() == $classReflection->getName()) {
114 $properties[] = PropertyGenerator
::fromReflection($reflectionProperty);
117 $cg->addProperties($properties);
120 foreach ($classReflection->getMethods() as $reflectionMethod) {
121 $className = ($cg->getNamespaceName())?
$cg->getNamespaceName() . "\\" . $cg->getName() : $cg->getName();
122 if ($reflectionMethod->getDeclaringClass()->getName() == $className) {
123 $methods[] = MethodGenerator
::fromReflection($reflectionMethod);
126 $cg->addMethods($methods);
132 * Generate from array
134 * @configkey name string [required] Class Name
135 * @configkey filegenerator FileGenerator File generator that holds this class
136 * @configkey namespacename string The namespace for this class
137 * @configkey docblock string The docblock information
138 * @configkey flags int Flags, one of ClassGenerator::FLAG_ABSTRACT ClassGenerator::FLAG_FINAL
139 * @configkey extendedclass string Class which this class is extending
140 * @configkey implementedinterfaces
141 * @configkey properties
144 * @throws Exception\InvalidArgumentException
145 * @param array $array
146 * @return ClassGenerator
148 public static function fromArray(array $array)
150 if (!isset($array['name'])) {
151 throw new Exception\
InvalidArgumentException(
152 'Class generator requires that a name is provided for this object'
156 $cg = new static($array['name']);
157 foreach ($array as $name => $value) {
159 switch (strtolower(str_replace(array('.', '-', '_'), '', $name))) {
160 case 'containingfile':
161 $cg->setContainingFileGenerator($value);
163 case 'namespacename':
164 $cg->setNamespaceName($value);
167 $docBlock = ($value instanceof DocBlockGenerator
) ?
$value : DocBlockGenerator
::fromArray($value);
168 $cg->setDocBlock($docBlock);
171 $cg->setFlags($value);
173 case 'extendedclass':
174 $cg->setExtendedClass($value);
176 case 'implementedinterfaces':
177 $cg->setImplementedInterfaces($value);
180 $cg->addProperties($value);
183 $cg->addMethods($value);
192 * @param string $name
193 * @param string $namespaceName
194 * @param array|string $flags
195 * @param string $extends
196 * @param array $interfaces
197 * @param array $properties
198 * @param array $methods
199 * @param DocBlockGenerator $docBlock
201 public function __construct($name = null, $namespaceName = null, $flags = null, $extends = null,
202 $interfaces = array(), $properties = array(), $methods = array(), $docBlock = null)
204 if ($name !== null) {
205 $this->setName($name);
207 if ($namespaceName !== null) {
208 $this->setNamespaceName($namespaceName);
210 if ($flags !== null) {
211 $this->setFlags($flags);
213 if ($properties !== array()) {
214 $this->addProperties($properties);
216 if ($extends !== null) {
217 $this->setExtendedClass($extends);
219 if (is_array($interfaces)) {
220 $this->setImplementedInterfaces($interfaces);
222 if ($methods !== array()) {
223 $this->addMethods($methods);
225 if ($docBlock !== null) {
226 $this->setDocBlock($docBlock);
231 * @param string $name
232 * @return ClassGenerator
234 public function setName($name)
236 if (strstr($name, '\\')) {
237 $namespace = substr($name, 0, strrpos($name, '\\'));
238 $name = substr($name, strrpos($name, '\\') +
1);
239 $this->setNamespaceName($namespace);
249 public function getName()
255 * @param string $namespaceName
256 * @return ClassGenerator
258 public function setNamespaceName($namespaceName)
260 $this->namespaceName
= $namespaceName;
267 public function getNamespaceName()
269 return $this->namespaceName
;
273 * @param FileGenerator $fileGenerator
274 * @return ClassGenerator
276 public function setContainingFileGenerator(FileGenerator
$fileGenerator)
278 $this->containingFileGenerator
= $fileGenerator;
283 * @return FileGenerator
285 public function getContainingFileGenerator()
287 return $this->containingFileGenerator
;
291 * @param DocBlockGenerator $docBlock
292 * @return ClassGenerator
294 public function setDocBlock(DocBlockGenerator
$docBlock)
296 $this->docBlock
= $docBlock;
301 * @return DocBlockGenerator
303 public function getDocBlock()
305 return $this->docBlock
;
309 * @param array|string $flags
310 * @return ClassGenerator
312 public function setFlags($flags)
314 if (is_array($flags)) {
315 $flagsArray = $flags;
317 foreach ($flagsArray as $flag) {
321 // check that visibility is one of three
322 $this->flags
= $flags;
328 * @param string $flag
329 * @return ClassGenerator
331 public function addFlag($flag)
333 $this->setFlags($this->flags |
$flag);
338 * @param string $flag
339 * @return ClassGenerator
341 public function removeFlag($flag)
343 $this->setFlags($this->flags
& ~
$flag);
348 * @param bool $isAbstract
349 * @return ClassGenerator
351 public function setAbstract($isAbstract)
353 return (($isAbstract) ?
$this->addFlag(self
::FLAG_ABSTRACT
) : $this->removeFlag(self
::FLAG_ABSTRACT
));
359 public function isAbstract()
361 return (bool) ($this->flags
& self
::FLAG_ABSTRACT
);
365 * @param bool $isFinal
366 * @return ClassGenerator
368 public function setFinal($isFinal)
370 return (($isFinal) ?
$this->addFlag(self
::FLAG_FINAL
) : $this->removeFlag(self
::FLAG_FINAL
));
376 public function isFinal()
378 return ($this->flags
& self
::FLAG_FINAL
);
382 * @param string $extendedClass
383 * @return ClassGenerator
385 public function setExtendedClass($extendedClass)
387 $this->extendedClass
= $extendedClass;
394 public function getExtendedClass()
396 return $this->extendedClass
;
400 * @param array $implementedInterfaces
401 * @return ClassGenerator
403 public function setImplementedInterfaces(array $implementedInterfaces)
405 $this->implementedInterfaces
= $implementedInterfaces;
412 public function getImplementedInterfaces()
414 return $this->implementedInterfaces
;
418 * @param array $properties
419 * @return ClassGenerator
421 public function addProperties(array $properties)
423 foreach ($properties as $property) {
424 if ($property instanceof PropertyGenerator
) {
425 $this->addPropertyFromGenerator($property);
427 if (is_string($property)) {
428 $this->addProperty($property);
429 } elseif (is_array($property)) {
430 call_user_func_array(array($this, 'addProperty'), $property);
439 * Add Property from scalars
441 * @param string $name
442 * @param string|array $defaultValue
444 * @throws Exception\InvalidArgumentException
445 * @return ClassGenerator
447 public function addProperty($name, $defaultValue = null, $flags = PropertyGenerator
::FLAG_PUBLIC
)
449 if (!is_string($name)) {
450 throw new Exception\
InvalidArgumentException(sprintf(
451 '%s expects string for name',
456 return $this->addPropertyFromGenerator(new PropertyGenerator($name, $defaultValue, $flags));
460 * Add property from PropertyGenerator
462 * @param string|PropertyGenerator $property
463 * @throws Exception\InvalidArgumentException
464 * @return ClassGenerator
466 public function addPropertyFromGenerator(PropertyGenerator
$property)
468 $propertyName = $property->getName();
470 if (isset($this->properties
[$propertyName])) {
471 throw new Exception\
InvalidArgumentException(sprintf(
472 'A property by name %s already exists in this class.',
477 $this->properties
[$propertyName] = $property;
482 * Add a class to "use" classes
485 * @param string|null $useAlias
486 * @return ClassGenerator
488 public function addUse($use, $useAlias = null)
490 if (!empty($useAlias)) {
491 $use .= ' as ' . $useAlias;
494 $this->uses
[$use] = $use;
499 * @return PropertyGenerator[]
501 public function getProperties()
503 return $this->properties
;
507 * @param string $propertyName
508 * @return PropertyGenerator|false
510 public function getProperty($propertyName)
512 foreach ($this->getProperties() as $property) {
513 if ($property->getName() == $propertyName) {
522 * Returns the "use" classes
526 public function getUses()
528 return array_values($this->uses
);
532 * @param string $propertyName
535 public function hasProperty($propertyName)
537 return isset($this->properties
[$propertyName]);
541 * @param array $methods
542 * @return ClassGenerator
544 public function addMethods(array $methods)
546 foreach ($methods as $method) {
547 if ($method instanceof MethodGenerator
) {
548 $this->addMethodFromGenerator($method);
550 if (is_string($method)) {
551 $this->addMethod($method);
552 } elseif (is_array($method)) {
553 call_user_func_array(array($this, 'addMethod'), $method);
562 * Add Method from scalars
564 * @param string $name
565 * @param array $parameters
567 * @param string $body
568 * @param string $docBlock
569 * @throws Exception\InvalidArgumentException
570 * @return ClassGenerator
572 public function addMethod($name = null, array $parameters = array(), $flags = MethodGenerator
::FLAG_PUBLIC
,
573 $body = null, $docBlock = null)
575 if (!is_string($name)) {
576 throw new Exception\
InvalidArgumentException(sprintf(
577 '%s expects string for name',
582 return $this->addMethodFromGenerator(new MethodGenerator($name, $parameters, $flags, $body, $docBlock));
586 * Add Method from MethodGenerator
588 * @param MethodGenerator $method
589 * @throws Exception\InvalidArgumentException
590 * @return ClassGenerator
592 public function addMethodFromGenerator(MethodGenerator
$method)
594 $methodName = $method->getName();
596 if (isset($this->methods
[$methodName])) {
597 throw new Exception\
InvalidArgumentException(sprintf(
598 'A method by name %s already exists in this class.',
603 $this->methods
[$methodName] = $method;
608 * @return MethodGenerator[]
610 public function getMethods()
612 return $this->methods
;
616 * @param string $methodName
617 * @return MethodGenerator|false
619 public function getMethod($methodName)
621 foreach ($this->methods
as $method) {
622 if ($method->getName() == $methodName) {
631 * @param string $methodName
632 * @return ClassGenerator
634 public function removeMethod($methodName)
636 foreach ($this->methods
as $key => $method) {
637 if ($method->getName() == $methodName) {
638 unset($this->methods
[$key]);
647 * @param string $methodName
650 public function hasMethod($methodName)
652 return isset($this->methods
[$methodName]);
658 public function isSourceDirty()
660 if (($docBlock = $this->getDocBlock()) && $docBlock->isSourceDirty()) {
664 foreach ($this->getProperties() as $property) {
665 if ($property->isSourceDirty()) {
670 foreach ($this->getMethods() as $method) {
671 if ($method->isSourceDirty()) {
676 return parent
::isSourceDirty();
682 public function generate()
684 if (!$this->isSourceDirty()) {
685 $output = $this->getSourceContent();
686 if (!empty($output)) {
693 if (null !== ($namespace = $this->getNamespaceName())) {
694 $output .= 'namespace ' . $namespace . ';' . self
::LINE_FEED
. self
::LINE_FEED
;
697 $uses = $this->getUses();
699 foreach ($uses as $use) {
700 $output .= 'use ' . $use . ';' . self
::LINE_FEED
;
702 $output .= self
::LINE_FEED
;
705 if (null !== ($docBlock = $this->getDocBlock())) {
706 $docBlock->setIndentation('');
707 $output .= $docBlock->generate();
710 if ($this->isAbstract()) {
711 $output .= 'abstract ';
714 $output .= 'class ' . $this->getName();
716 if (!empty($this->extendedClass
)) {
717 $output .= ' extends ' . $this->extendedClass
;
720 $implemented = $this->getImplementedInterfaces();
721 if (!empty($implemented)) {
722 $output .= ' implements ' . implode(', ', $implemented);
725 $output .= self
::LINE_FEED
. '{' . self
::LINE_FEED
. self
::LINE_FEED
;
727 $properties = $this->getProperties();
728 if (!empty($properties)) {
729 foreach ($properties as $property) {
730 $output .= $property->generate() . self
::LINE_FEED
. self
::LINE_FEED
;
734 $methods = $this->getMethods();
735 if (!empty($methods)) {
736 foreach ($methods as $method) {
737 $output .= $method->generate() . self
::LINE_FEED
;
741 $output .= self
::LINE_FEED
. '}' . self
::LINE_FEED
;