Verzeichnisstruktur phpBB-3.3.15
- Veröffentlicht
- 28.08.2024
So funktioniert es
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
ClassGenerator.php
0001 <?php
0002 /**
0003 * Zend Framework (http://framework.zend.com/)
0004 *
0005 * @link http://github.com/zendframework/zf2 for the canonical source repository
0006 * @copyright Copyright (c) 2005-2016 Zend Technologies USA Inc. (http://www.zend.com)
0007 * @license http://framework.zend.com/license/new-bsd New BSD License
0008 */
0009
0010 namespace Zend\Code\Generator;
0011
0012 use Zend\Code\Reflection\ClassReflection;
0013
0014 use function array_diff;
0015 use function array_map;
0016 use function array_pop;
0017 use function array_search;
0018 use function array_values;
0019 use function array_walk;
0020 use function explode;
0021 use function get_class;
0022 use function gettype;
0023 use function implode;
0024 use function in_array;
0025 use function is_array;
0026 use function is_scalar;
0027 use function is_string;
0028 use function ltrim;
0029 use function sprintf;
0030 use function str_replace;
0031 use function strpos;
0032 use function strrpos;
0033 use function strstr;
0034 use function strtolower;
0035 use function substr;
0036
0037 class ClassGenerator extends AbstractGenerator implements TraitUsageInterface
0038 {
0039 const OBJECT_TYPE = 'class';
0040 const IMPLEMENTS_KEYWORD = 'implements';
0041
0042 const FLAG_ABSTRACT = 0x01;
0043 const FLAG_FINAL = 0x02;
0044
0045 /**
0046 * @var FileGenerator
0047 */
0048 protected $containingFileGenerator;
0049
0050 /**
0051 * @var string
0052 */
0053 protected $namespaceName;
0054
0055 /**
0056 * @var DocBlockGenerator
0057 */
0058 protected $docBlock;
0059
0060 /**
0061 * @var string
0062 */
0063 protected $name;
0064
0065 /**
0066 * @var bool
0067 */
0068 protected $flags = 0x00;
0069
0070 /**
0071 * @var string
0072 */
0073 protected $extendedClass;
0074
0075 /**
0076 * @var array Array of string names
0077 */
0078 protected $implementedInterfaces = [];
0079
0080 /**
0081 * @var PropertyGenerator[] Array of properties
0082 */
0083 protected $properties = [];
0084
0085 /**
0086 * @var PropertyGenerator[] Array of constants
0087 */
0088 protected $constants = [];
0089
0090 /**
0091 * @var MethodGenerator[] Array of methods
0092 */
0093 protected $methods = [];
0094
0095 /**
0096 * @var TraitUsageGenerator Object to encapsulate trait usage logic
0097 */
0098 protected $traitUsageGenerator;
0099
0100 /**
0101 * Build a Code Generation Php Object from a Class Reflection
0102 *
0103 * @param ClassReflection $classReflection
0104 * @return self
0105 */
0106 public static function fromReflection(ClassReflection $classReflection)
0107 {
0108 $cg = new static($classReflection->getName());
0109
0110 $cg->setSourceContent($cg->getSourceContent());
0111 $cg->setSourceDirty(false);
0112
0113 if ($classReflection->getDocComment() != '') {
0114 $cg->setDocBlock(DocBlockGenerator::fromReflection($classReflection->getDocBlock()));
0115 }
0116
0117 $cg->setAbstract($classReflection->isAbstract());
0118
0119 // set the namespace
0120 if ($classReflection->inNamespace()) {
0121 $cg->setNamespaceName($classReflection->getNamespaceName());
0122 }
0123
0124 /* @var \Zend\Code\Reflection\ClassReflection $parentClass */
0125 $parentClass = $classReflection->getParentClass();
0126 $interfaces = $classReflection->getInterfaces();
0127
0128 if ($parentClass) {
0129 $cg->setExtendedClass($parentClass->getName());
0130
0131 $interfaces = array_diff($interfaces, $parentClass->getInterfaces());
0132 }
0133
0134 $interfaceNames = [];
0135 foreach ($interfaces as $interface) {
0136 /* @var \Zend\Code\Reflection\ClassReflection $interface */
0137 $interfaceNames[] = $interface->getName();
0138 }
0139
0140 $cg->setImplementedInterfaces($interfaceNames);
0141
0142 $properties = [];
0143
0144 foreach ($classReflection->getProperties() as $reflectionProperty) {
0145 if ($reflectionProperty->getDeclaringClass()->getName() == $classReflection->getName()) {
0146 $properties[] = PropertyGenerator::fromReflection($reflectionProperty);
0147 }
0148 }
0149
0150 $cg->addProperties($properties);
0151
0152 $constants = [];
0153
0154 foreach ($classReflection->getConstants() as $name => $value) {
0155 $constants[] = [
0156 'name' => $name,
0157 'value' => $value,
0158 ];
0159 }
0160
0161 $cg->addConstants($constants);
0162
0163 $methods = [];
0164
0165 foreach ($classReflection->getMethods() as $reflectionMethod) {
0166 $className = $cg->getNamespaceName() ? $cg->getNamespaceName() . '\\' . $cg->getName() : $cg->getName();
0167
0168 if ($reflectionMethod->getDeclaringClass()->getName() == $className) {
0169 $methods[] = MethodGenerator::fromReflection($reflectionMethod);
0170 }
0171 }
0172
0173 $cg->addMethods($methods);
0174
0175 return $cg;
0176 }
0177
0178 /**
0179 * Generate from array
0180 *
0181 * @configkey name string [required] Class Name
0182 * @configkey filegenerator FileGenerator File generator that holds this class
0183 * @configkey namespacename string The namespace for this class
0184 * @configkey docblock string The docblock information
0185 * @configkey flags int Flags, one of ClassGenerator::FLAG_ABSTRACT ClassGenerator::FLAG_FINAL
0186 * @configkey extendedclass string Class which this class is extending
0187 * @configkey implementedinterfaces
0188 * @configkey properties
0189 * @configkey methods
0190 *
0191 * @throws Exception\InvalidArgumentException
0192 * @param array $array
0193 * @return self
0194 */
0195 public static function fromArray(array $array)
0196 {
0197 if (! isset($array['name'])) {
0198 throw new Exception\InvalidArgumentException(
0199 'Class generator requires that a name is provided for this object'
0200 );
0201 }
0202
0203 $cg = new static($array['name']);
0204 foreach ($array as $name => $value) {
0205 // normalize key
0206 switch (strtolower(str_replace(['.', '-', '_'], '', $name))) {
0207 case 'containingfile':
0208 $cg->setContainingFileGenerator($value);
0209 break;
0210 case 'namespacename':
0211 $cg->setNamespaceName($value);
0212 break;
0213 case 'docblock':
0214 $docBlock = $value instanceof DocBlockGenerator ? $value : DocBlockGenerator::fromArray($value);
0215 $cg->setDocBlock($docBlock);
0216 break;
0217 case 'flags':
0218 $cg->setFlags($value);
0219 break;
0220 case 'extendedclass':
0221 $cg->setExtendedClass($value);
0222 break;
0223 case 'implementedinterfaces':
0224 $cg->setImplementedInterfaces($value);
0225 break;
0226 case 'properties':
0227 $cg->addProperties($value);
0228 break;
0229 case 'methods':
0230 $cg->addMethods($value);
0231 break;
0232 }
0233 }
0234
0235 return $cg;
0236 }
0237
0238 /**
0239 * @param string $name
0240 * @param string $namespaceName
0241 * @param array|string $flags
0242 * @param string $extends
0243 * @param array $interfaces
0244 * @param array $properties
0245 * @param array $methods
0246 * @param DocBlockGenerator $docBlock
0247 */
0248 public function __construct(
0249 $name = null,
0250 $namespaceName = null,
0251 $flags = null,
0252 $extends = null,
0253 $interfaces = [],
0254 $properties = [],
0255 $methods = [],
0256 $docBlock = null
0257 ) {
0258 $this->traitUsageGenerator = new TraitUsageGenerator($this);
0259
0260 if ($name !== null) {
0261 $this->setName($name);
0262 }
0263 if ($namespaceName !== null) {
0264 $this->setNamespaceName($namespaceName);
0265 }
0266 if ($flags !== null) {
0267 $this->setFlags($flags);
0268 }
0269 if ($properties !== []) {
0270 $this->addProperties($properties);
0271 }
0272 if ($extends !== null) {
0273 $this->setExtendedClass($extends);
0274 }
0275 if (is_array($interfaces)) {
0276 $this->setImplementedInterfaces($interfaces);
0277 }
0278 if ($methods !== []) {
0279 $this->addMethods($methods);
0280 }
0281 if ($docBlock !== null) {
0282 $this->setDocBlock($docBlock);
0283 }
0284 }
0285
0286 /**
0287 * @param string $name
0288 * @return self
0289 */
0290 public function setName($name)
0291 {
0292 if (false !== strpos($name, '\\')) {
0293 $namespace = substr($name, 0, strrpos($name, '\\'));
0294 $name = substr($name, strrpos($name, '\\') + 1);
0295 $this->setNamespaceName($namespace);
0296 }
0297
0298 $this->name = $name;
0299 return $this;
0300 }
0301
0302 /**
0303 * @return string
0304 */
0305 public function getName()
0306 {
0307 return $this->name;
0308 }
0309
0310 /**
0311 * @param string $namespaceName
0312 * @return self
0313 */
0314 public function setNamespaceName($namespaceName)
0315 {
0316 $this->namespaceName = $namespaceName;
0317 return $this;
0318 }
0319
0320 /**
0321 * @return string
0322 */
0323 public function getNamespaceName()
0324 {
0325 return $this->namespaceName;
0326 }
0327
0328 /**
0329 * @param FileGenerator $fileGenerator
0330 * @return self
0331 */
0332 public function setContainingFileGenerator(FileGenerator $fileGenerator)
0333 {
0334 $this->containingFileGenerator = $fileGenerator;
0335 return $this;
0336 }
0337
0338 /**
0339 * @return FileGenerator
0340 */
0341 public function getContainingFileGenerator()
0342 {
0343 return $this->containingFileGenerator;
0344 }
0345
0346 /**
0347 * @param DocBlockGenerator $docBlock
0348 * @return self
0349 */
0350 public function setDocBlock(DocBlockGenerator $docBlock)
0351 {
0352 $this->docBlock = $docBlock;
0353 return $this;
0354 }
0355
0356 /**
0357 * @return DocBlockGenerator
0358 */
0359 public function getDocBlock()
0360 {
0361 return $this->docBlock;
0362 }
0363
0364 /**
0365 * @param array|string $flags
0366 * @return self
0367 */
0368 public function setFlags($flags)
0369 {
0370 if (is_array($flags)) {
0371 $flagsArray = $flags;
0372 $flags = 0x00;
0373 foreach ($flagsArray as $flag) {
0374 $flags |= $flag;
0375 }
0376 }
0377 // check that visibility is one of three
0378 $this->flags = $flags;
0379
0380 return $this;
0381 }
0382
0383 /**
0384 * @param string $flag
0385 * @return self
0386 */
0387 public function addFlag($flag)
0388 {
0389 $this->setFlags($this->flags | $flag);
0390 return $this;
0391 }
0392
0393 /**
0394 * @param string $flag
0395 * @return self
0396 */
0397 public function removeFlag($flag)
0398 {
0399 $this->setFlags($this->flags & ~$flag);
0400 return $this;
0401 }
0402
0403 /**
0404 * @param bool $isAbstract
0405 * @return self
0406 */
0407 public function setAbstract($isAbstract)
0408 {
0409 return $isAbstract ? $this->addFlag(self::FLAG_ABSTRACT) : $this->removeFlag(self::FLAG_ABSTRACT);
0410 }
0411
0412 /**
0413 * @return bool
0414 */
0415 public function isAbstract()
0416 {
0417 return (bool) ($this->flags & self::FLAG_ABSTRACT);
0418 }
0419
0420 /**
0421 * @param bool $isFinal
0422 * @return self
0423 */
0424 public function setFinal($isFinal)
0425 {
0426 return $isFinal ? $this->addFlag(self::FLAG_FINAL) : $this->removeFlag(self::FLAG_FINAL);
0427 }
0428
0429 /**
0430 * @return bool
0431 */
0432 public function isFinal()
0433 {
0434 return $this->flags & self::FLAG_FINAL;
0435 }
0436
0437 /**
0438 * @param string $extendedClass
0439 * @return self
0440 */
0441 public function setExtendedClass($extendedClass)
0442 {
0443 $this->extendedClass = $extendedClass;
0444 return $this;
0445 }
0446
0447 /**
0448 * @return string
0449 */
0450 public function getExtendedClass()
0451 {
0452 return $this->extendedClass;
0453 }
0454
0455 /**
0456 * @return bool
0457 */
0458 public function hasExtentedClass()
0459 {
0460 return ! empty($this->extendedClass);
0461 }
0462
0463 /**
0464 * @return self
0465 */
0466 public function removeExtentedClass()
0467 {
0468 $this->setExtendedClass(null);
0469 return $this;
0470 }
0471
0472 /**
0473 * @param array $implementedInterfaces
0474 * @return self
0475 */
0476 public function setImplementedInterfaces(array $implementedInterfaces)
0477 {
0478 array_map(function ($implementedInterface) {
0479 return (string) TypeGenerator::fromTypeString($implementedInterface);
0480 }, $implementedInterfaces);
0481
0482 $this->implementedInterfaces = $implementedInterfaces;
0483 return $this;
0484 }
0485
0486 /**
0487 * @return array
0488 */
0489 public function getImplementedInterfaces()
0490 {
0491 return $this->implementedInterfaces;
0492 }
0493
0494 /**
0495 * @param string $implementedInterface
0496 * @return bool
0497 */
0498 public function hasImplementedInterface($implementedInterface)
0499 {
0500 $implementedInterface = (string) TypeGenerator::fromTypeString($implementedInterface);
0501 return in_array($implementedInterface, $this->implementedInterfaces);
0502 }
0503
0504 /**
0505 * @param string $implementedInterface
0506 * @return self
0507 */
0508 public function removeImplementedInterface($implementedInterface)
0509 {
0510 $implementedInterface = (string) TypeGenerator::fromTypeString($implementedInterface);
0511 unset($this->implementedInterfaces[array_search($implementedInterface, $this->implementedInterfaces)]);
0512 return $this;
0513 }
0514
0515 /**
0516 * @param string $constantName
0517 * @return PropertyGenerator|false
0518 */
0519 public function getConstant($constantName)
0520 {
0521 if (isset($this->constants[$constantName])) {
0522 return $this->constants[$constantName];
0523 }
0524
0525 return false;
0526 }
0527
0528 /**
0529 * @return PropertyGenerator[] indexed by constant name
0530 */
0531 public function getConstants()
0532 {
0533 return $this->constants;
0534 }
0535
0536 /**
0537 * @param string $constantName
0538 * @return self
0539 */
0540 public function removeConstant($constantName)
0541 {
0542 unset($this->constants[$constantName]);
0543
0544 return $this;
0545 }
0546
0547 /**
0548 * @param string $constantName
0549 * @return bool
0550 */
0551 public function hasConstant($constantName)
0552 {
0553 return isset($this->constants[$constantName]);
0554 }
0555
0556 /**
0557 * Add constant from PropertyGenerator
0558 *
0559 * @param PropertyGenerator $constant
0560 * @throws Exception\InvalidArgumentException
0561 * @return self
0562 */
0563 public function addConstantFromGenerator(PropertyGenerator $constant)
0564 {
0565 $constantName = $constant->getName();
0566
0567 if (isset($this->constants[$constantName])) {
0568 throw new Exception\InvalidArgumentException(sprintf(
0569 'A constant by name %s already exists in this class.',
0570 $constantName
0571 ));
0572 }
0573
0574 if (! $constant->isConst()) {
0575 throw new Exception\InvalidArgumentException(sprintf(
0576 'The value %s is not defined as a constant.',
0577 $constantName
0578 ));
0579 }
0580
0581 $this->constants[$constantName] = $constant;
0582
0583 return $this;
0584 }
0585
0586 /**
0587 * Add Constant
0588 *
0589 * @param string $name Non-empty string
0590 * @param string|int|null|float|array $value Scalar
0591 *
0592 * @throws Exception\InvalidArgumentException
0593 *
0594 * @return self
0595 */
0596 public function addConstant($name, $value)
0597 {
0598 if (empty($name) || ! is_string($name)) {
0599 throw new Exception\InvalidArgumentException(sprintf(
0600 '%s expects string for name',
0601 __METHOD__
0602 ));
0603 }
0604
0605 $this->validateConstantValue($value);
0606
0607 return $this->addConstantFromGenerator(
0608 new PropertyGenerator($name, new PropertyValueGenerator($value), PropertyGenerator::FLAG_CONSTANT)
0609 );
0610 }
0611
0612 /**
0613 * @param PropertyGenerator[]|array[] $constants
0614 *
0615 * @return self
0616 */
0617 public function addConstants(array $constants)
0618 {
0619 foreach ($constants as $constant) {
0620 if ($constant instanceof PropertyGenerator) {
0621 $this->addPropertyFromGenerator($constant);
0622 } else {
0623 if (is_array($constant)) {
0624 $this->addConstant(...array_values($constant));
0625 }
0626 }
0627 }
0628
0629 return $this;
0630 }
0631
0632 /**
0633 * @param array $properties
0634 * @return self
0635 */
0636 public function addProperties(array $properties)
0637 {
0638 foreach ($properties as $property) {
0639 if ($property instanceof PropertyGenerator) {
0640 $this->addPropertyFromGenerator($property);
0641 } else {
0642 if (is_string($property)) {
0643 $this->addProperty($property);
0644 } elseif (is_array($property)) {
0645 $this->addProperty(...array_values($property));
0646 }
0647 }
0648 }
0649
0650 return $this;
0651 }
0652
0653 /**
0654 * Add Property from scalars
0655 *
0656 * @param string $name
0657 * @param string|array $defaultValue
0658 * @param int $flags
0659 * @throws Exception\InvalidArgumentException
0660 * @return self
0661 */
0662 public function addProperty($name, $defaultValue = null, $flags = PropertyGenerator::FLAG_PUBLIC)
0663 {
0664 if (! is_string($name)) {
0665 throw new Exception\InvalidArgumentException(sprintf(
0666 '%s::%s expects string for name',
0667 get_class($this),
0668 __FUNCTION__
0669 ));
0670 }
0671
0672 // backwards compatibility
0673 // @todo remove this on next major version
0674 if ($flags === PropertyGenerator::FLAG_CONSTANT) {
0675 return $this->addConstant($name, $defaultValue);
0676 }
0677
0678 return $this->addPropertyFromGenerator(new PropertyGenerator($name, $defaultValue, $flags));
0679 }
0680
0681 /**
0682 * Add property from PropertyGenerator
0683 *
0684 * @param PropertyGenerator $property
0685 * @throws Exception\InvalidArgumentException
0686 * @return self
0687 */
0688 public function addPropertyFromGenerator(PropertyGenerator $property)
0689 {
0690 $propertyName = $property->getName();
0691
0692 if (isset($this->properties[$propertyName])) {
0693 throw new Exception\InvalidArgumentException(sprintf(
0694 'A property by name %s already exists in this class.',
0695 $propertyName
0696 ));
0697 }
0698
0699 // backwards compatibility
0700 // @todo remove this on next major version
0701 if ($property->isConst()) {
0702 return $this->addConstantFromGenerator($property);
0703 }
0704
0705 $this->properties[$propertyName] = $property;
0706 return $this;
0707 }
0708
0709 /**
0710 * @return PropertyGenerator[]
0711 */
0712 public function getProperties()
0713 {
0714 return $this->properties;
0715 }
0716
0717 /**
0718 * @param string $propertyName
0719 * @return PropertyGenerator|false
0720 */
0721 public function getProperty($propertyName)
0722 {
0723 foreach ($this->getProperties() as $property) {
0724 if ($property->getName() == $propertyName) {
0725 return $property;
0726 }
0727 }
0728
0729 return false;
0730 }
0731
0732 /**
0733 * Add a class to "use" classes
0734 *
0735 * @param string $use
0736 * @param string|null $useAlias
0737 * @return self
0738 */
0739 public function addUse($use, $useAlias = null)
0740 {
0741 $this->traitUsageGenerator->addUse($use, $useAlias);
0742 return $this;
0743 }
0744
0745 /**
0746 * @param string $use
0747 * @return bool
0748 */
0749 public function hasUse($use)
0750 {
0751 return $this->traitUsageGenerator->hasUse($use);
0752 }
0753
0754 /**
0755 * @param string $use
0756 * @return self
0757 */
0758 public function removeUse($use)
0759 {
0760 $this->traitUsageGenerator->removeUse($use);
0761 return $this;
0762 }
0763
0764 /**
0765 * @param string $use
0766 * @return bool
0767 */
0768 public function hasUseAlias($use)
0769 {
0770 return $this->traitUsageGenerator->hasUseAlias($use);
0771 }
0772
0773 /**
0774 * @param string $use
0775 * @return self
0776 */
0777 public function removeUseAlias($use)
0778 {
0779 $this->traitUsageGenerator->removeUseAlias($use);
0780 return $this;
0781 }
0782
0783 /**
0784 * Returns the "use" classes
0785 *
0786 * @return array
0787 */
0788 public function getUses()
0789 {
0790 return $this->traitUsageGenerator->getUses();
0791 }
0792
0793 /**
0794 * @param string $propertyName
0795 * @return self
0796 */
0797 public function removeProperty($propertyName)
0798 {
0799 unset($this->properties[$propertyName]);
0800
0801 return $this;
0802 }
0803
0804 /**
0805 * @param string $propertyName
0806 * @return bool
0807 */
0808 public function hasProperty($propertyName)
0809 {
0810 return isset($this->properties[$propertyName]);
0811 }
0812
0813 /**
0814 * @param array $methods
0815 * @return self
0816 */
0817 public function addMethods(array $methods)
0818 {
0819 foreach ($methods as $method) {
0820 if ($method instanceof MethodGenerator) {
0821 $this->addMethodFromGenerator($method);
0822 } else {
0823 if (is_string($method)) {
0824 $this->addMethod($method);
0825 } elseif (is_array($method)) {
0826 $this->addMethod(...array_values($method));
0827 }
0828 }
0829 }
0830
0831 return $this;
0832 }
0833
0834 /**
0835 * Add Method from scalars
0836 *
0837 * @param string $name
0838 * @param array $parameters
0839 * @param int $flags
0840 * @param string $body
0841 * @param string $docBlock
0842 * @throws Exception\InvalidArgumentException
0843 * @return self
0844 */
0845 public function addMethod(
0846 $name,
0847 array $parameters = [],
0848 $flags = MethodGenerator::FLAG_PUBLIC,
0849 $body = null,
0850 $docBlock = null
0851 ) {
0852 if (! is_string($name)) {
0853 throw new Exception\InvalidArgumentException(sprintf(
0854 '%s::%s expects string for name',
0855 get_class($this),
0856 __FUNCTION__
0857 ));
0858 }
0859
0860 return $this->addMethodFromGenerator(new MethodGenerator($name, $parameters, $flags, $body, $docBlock));
0861 }
0862
0863 /**
0864 * Add Method from MethodGenerator
0865 *
0866 * @param MethodGenerator $method
0867 * @throws Exception\InvalidArgumentException
0868 * @return self
0869 */
0870 public function addMethodFromGenerator(MethodGenerator $method)
0871 {
0872 $methodName = $method->getName();
0873
0874 if ($this->hasMethod($methodName)) {
0875 throw new Exception\InvalidArgumentException(sprintf(
0876 'A method by name %s already exists in this class.',
0877 $methodName
0878 ));
0879 }
0880
0881 $this->methods[strtolower($methodName)] = $method;
0882 return $this;
0883 }
0884
0885 /**
0886 * @return MethodGenerator[]
0887 */
0888 public function getMethods()
0889 {
0890 return $this->methods;
0891 }
0892
0893 /**
0894 * @param string $methodName
0895 * @return MethodGenerator|false
0896 */
0897 public function getMethod($methodName)
0898 {
0899 return $this->hasMethod($methodName) ? $this->methods[strtolower($methodName)] : false;
0900 }
0901
0902 /**
0903 * @param string $methodName
0904 * @return self
0905 */
0906 public function removeMethod($methodName)
0907 {
0908 unset($this->methods[strtolower($methodName)]);
0909
0910 return $this;
0911 }
0912
0913 /**
0914 * @param string $methodName
0915 * @return bool
0916 */
0917 public function hasMethod($methodName)
0918 {
0919 return isset($this->methods[strtolower($methodName)]);
0920 }
0921
0922 /**
0923 * @inheritDoc
0924 */
0925 public function addTrait($trait)
0926 {
0927 $this->traitUsageGenerator->addTrait($trait);
0928 return $this;
0929 }
0930
0931 /**
0932 * @inheritDoc
0933 */
0934 public function addTraits(array $traits)
0935 {
0936 $this->traitUsageGenerator->addTraits($traits);
0937 return $this;
0938 }
0939
0940 /**
0941 * @inheritDoc
0942 */
0943 public function hasTrait($traitName)
0944 {
0945 return $this->traitUsageGenerator->hasTrait($traitName);
0946 }
0947
0948 /**
0949 * @inheritDoc
0950 */
0951 public function getTraits()
0952 {
0953 return $this->traitUsageGenerator->getTraits();
0954 }
0955
0956 /**
0957 * @inheritDoc
0958 */
0959 public function removeTrait($traitName)
0960 {
0961 return $this->traitUsageGenerator->removeTrait($traitName);
0962 }
0963
0964 /**
0965 * @inheritDoc
0966 */
0967 public function addTraitAlias($method, $alias, $visibility = null)
0968 {
0969 $this->traitUsageGenerator->addTraitAlias($method, $alias, $visibility);
0970 return $this;
0971 }
0972
0973 /**
0974 * @inheritDoc
0975 */
0976 public function getTraitAliases()
0977 {
0978 return $this->traitUsageGenerator->getTraitAliases();
0979 }
0980
0981 /**
0982 * @inheritDoc
0983 */
0984 public function addTraitOverride($method, $traitsToReplace)
0985 {
0986 $this->traitUsageGenerator->addTraitOverride($method, $traitsToReplace);
0987 return $this;
0988 }
0989
0990 /**
0991 * @inheritDoc
0992 */
0993 public function removeTraitOverride($method, $overridesToRemove = null)
0994 {
0995 $this->traitUsageGenerator->removeTraitOverride($method, $overridesToRemove);
0996
0997 return $this;
0998 }
0999
1000 /**
1001 * @inheritDoc
1002 */
1003 public function getTraitOverrides()
1004 {
1005 return $this->traitUsageGenerator->getTraitOverrides();
1006 }
1007
1008 /**
1009 * @return bool
1010 */
1011 public function isSourceDirty()
1012 {
1013 if (($docBlock = $this->getDocBlock()) && $docBlock->isSourceDirty()) {
1014 return true;
1015 }
1016
1017 foreach ($this->getProperties() as $property) {
1018 if ($property->isSourceDirty()) {
1019 return true;
1020 }
1021 }
1022
1023 foreach ($this->getMethods() as $method) {
1024 if ($method->isSourceDirty()) {
1025 return true;
1026 }
1027 }
1028
1029 return parent::isSourceDirty();
1030 }
1031
1032 /**
1033 * @inheritDoc
1034 */
1035 public function generate()
1036 {
1037 if (! $this->isSourceDirty()) {
1038 $output = $this->getSourceContent();
1039 if (! empty($output)) {
1040 return $output;
1041 }
1042 }
1043
1044 $indent = $this->getIndentation();
1045 $output = '';
1046
1047 if (null !== ($namespace = $this->getNamespaceName())) {
1048 $output .= 'namespace ' . $namespace . ';' . self::LINE_FEED . self::LINE_FEED;
1049 }
1050
1051 $uses = $this->getUses();
1052
1053 if (! empty($uses)) {
1054 foreach ($uses as $use) {
1055 $output .= 'use ' . $use . ';' . self::LINE_FEED;
1056 }
1057
1058 $output .= self::LINE_FEED;
1059 }
1060
1061 if (null !== ($docBlock = $this->getDocBlock())) {
1062 $docBlock->setIndentation('');
1063 $output .= $docBlock->generate();
1064 }
1065
1066 if ($this->isAbstract()) {
1067 $output .= 'abstract ';
1068 } elseif ($this->isFinal()) {
1069 $output .= 'final ';
1070 }
1071
1072 $output .= static::OBJECT_TYPE . ' ' . $this->getName();
1073
1074 if (! empty($this->extendedClass)) {
1075 $output .= ' extends ' . $this->generateShortOrCompleteClassname($this->extendedClass);
1076 }
1077
1078 $implemented = $this->getImplementedInterfaces();
1079
1080 if (! empty($implemented)) {
1081 $implemented = array_map([$this, 'generateShortOrCompleteClassname'], $implemented);
1082 $output .= ' ' . static::IMPLEMENTS_KEYWORD . ' ' . implode(', ', $implemented);
1083 }
1084
1085 $output .= self::LINE_FEED . '{' . self::LINE_FEED . self::LINE_FEED;
1086 $output .= $this->traitUsageGenerator->generate();
1087
1088 $constants = $this->getConstants();
1089
1090 foreach ($constants as $constant) {
1091 $output .= $constant->generate() . self::LINE_FEED . self::LINE_FEED;
1092 }
1093
1094 $properties = $this->getProperties();
1095
1096 foreach ($properties as $property) {
1097 $output .= $property->generate() . self::LINE_FEED . self::LINE_FEED;
1098 }
1099
1100 $methods = $this->getMethods();
1101
1102 foreach ($methods as $method) {
1103 $output .= $method->generate() . self::LINE_FEED;
1104 }
1105
1106 $output .= self::LINE_FEED . '}' . self::LINE_FEED;
1107
1108 return $output;
1109 }
1110
1111 /**
1112 * @param mixed $value
1113 *
1114 * @return void
1115 *
1116 * @throws Exception\InvalidArgumentException
1117 */
1118 private function validateConstantValue($value)
1119 {
1120 if (null === $value || is_scalar($value)) {
1121 return;
1122 }
1123
1124 if (is_array($value)) {
1125 array_walk($value, [$this, 'validateConstantValue']);
1126
1127 return;
1128 }
1129
1130 throw new Exception\InvalidArgumentException(sprintf(
1131 'Expected value for constant, value must be a "scalar" or "null", "%s" found',
1132 gettype($value)
1133 ));
1134 }
1135
1136 /**
1137 * @param string $fqnClassName
1138 *
1139 * @return string
1140 */
1141 private function generateShortOrCompleteClassname($fqnClassName)
1142 {
1143 $fqnClassName = ltrim($fqnClassName, '\\');
1144 $parts = explode('\\', $fqnClassName);
1145 $className = array_pop($parts);
1146 $classNamespace = implode('\\', $parts);
1147 $currentNamespace = (string) $this->getNamespaceName();
1148
1149 if ($this->hasUseAlias($fqnClassName)) {
1150 return $this->traitUsageGenerator->getUseAlias($fqnClassName);
1151 }
1152 if ($this->hasUseAlias($classNamespace)) {
1153 $namespaceAlias = $this->traitUsageGenerator->getUseAlias($classNamespace);
1154
1155 return $namespaceAlias . '\\' . $className;
1156 }
1157 if ($this->traitUsageGenerator->isUseAlias($fqnClassName)) {
1158 return $fqnClassName;
1159 }
1160 if ($this->traitUsageGenerator->isUseAlias($classNamespace)) {
1161 return $fqnClassName;
1162 }
1163 if ($classNamespace === $currentNamespace || in_array($fqnClassName, $this->getUses())) {
1164 return $className;
1165 }
1166
1167 return '\\' . $fqnClassName;
1168 }
1169 }
1170